Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Confronting a Monolithic Rails App with Angular...

Sponsored · Your Podcast. Everywhere. Effortlessly. Share. Educate. Inspire. Entertain. You do you. We'll handle the rest.

Confronting a Monolithic Rails App with Angular and TDD

Thoughts and observations on gradually retrofitting a Rails/jQuery app with Angular and TDD. I gave this talk as a quick presentation at BrooklynJS in June.

Avatar for Scott Luptowski

Scott Luptowski

June 19, 2014

More Decks by Scott Luptowski

Other Decks in Programming

Transcript

  1. Lighthearted talk on confronting a monolithic Rails app by gradually

    replacing "sprinkles of jQuery" with components designed in Angular with TDD
  2. The Ball of Mud Architectural Pattern: "How the feature too

    small to design becomes too big to maintain"
  3. Pieces of our code base we all have $ (

    d o c u m e n t ) . r e a d y ( f u n c t i o n ( ) { $ ( ' . e l e m e n t ' ) . o n ( ' c l i c k ' , f u n c t i o n ( ) { $ ( t h i s ) . s o m e t h i n g S i m p l e ( ) ; } ) ; } ) ;
  4. Pieces of our code base we all have $ (

    d o c u m e n t ) . r e a d y ( f u n c t i o n ( ) { $ ( ' . e l e m e n t ' ) . o n ( ' c l i c k ' , f u n c t i o n ( ) { $ ( t h i s ) . s o m e t h i n g S i m p l e ( ) ; } ) ; $ ( ' . o t h e r - e l e m e n t ' ) . o n ( ' c l i c k ' , f u n c t i o n ( e ) { / / D O N ' T T O U C H s o m e t h i n g E l s e ( ) ; s o m e t h i n g H a r d T o F o l l o w ( e ) ; } ) ; $ ( ' . s o m e t h i n g - e l s e ' ) . o n ( ' c l i c k ' , f u n c t i o n ( ) { / / T O D O f i n d a d i f f e r e n t w a y t o d o t h i s s o m e t h i n g E l s e ( ) ; $ ( t h i s ) . p a r e n t ( ) . h i d e ( ) . s h o w ( ) s o m e t h i n g E l s e E n t i r e l y ( ) ; } ) ; } ) ;
  5. We were spending a lot of time fighting issues related

    to this ball of mud We knew client-side MVC was the way to move forward
  6. Angular 'easier' than Backbone or Ember to include as you

    wish and migrate at your own speed < b o d y > < d i v n g - a p p > < / d i v > < / b o d y >
  7. The hardest part was looking at this... $ . p

    o s t ( $ ( ' # c o u p o n _ c h e c k ' ) . d a t a ( ' s e t C o u p o n U r l ' ) ) , p a r a m s , ( d a t a ) - > i f d a t a [ ' e r r o r s ' ] ! = n u l l f o r e r r o r _ a r r a y i n d a t a [ ' e r r o r s ' ] f o r m e s s a g e i n e r r o r _ a r r a y [ 1 ] $ ( ' # c o u p o n _ e r r o r s ' ) . a p p e n d ( m e s s a g e + ' < b r / > ' ) $ ( ' . c o u p o n - i c o n s . s u c c e s s - i c o n ' ) . h i d e ( ) $ ( ' . c o u p o n - i c o n s . e r r o r - i c o n ' ) . s h o w ( ) $ ( ' # c o u p o n ' ) . a d d C l a s s ( ' f o r m - i n p u t - e r r o r ' ) i f d a t a [ ' c o u p o n _ i d ' ] ! = n u l l $ ( ' # c o u p o n l i n k ' ) . h i d e ( ) $ ( ' # c o u p o n r e m o v e ' ) . s h o w ( ) $ ( ' # s a v e _ i d ' ) . s h o w ( ) $ ( ' # c o u p o n ' ) . a d d C l a s s ( ' j s - s u c c e s s - c h e c k f o r m - i n p u t - s u c c e s s ' ) i f d a t a . r e p e a t & & $ ( ' # t r a n s a c t i o n _ f r e q u e n c y _ r a d i o _ 0 ' ) . l e n g t h > 0 $ ( ' # t r a n s a c t i o n _ f r e q u e n c y _ r a d i o _ 0 ' ) . p r o p ( ' d i s a b l e d ' , t r u e ) $ ( ' # t r a n s a c t i o n _ f r e q u e n c y _ r a d i o _ 0 ' ) . p a r e n t ( ) . a d d C l a s s ( ' d i s a b l e d - b u t t o n ' ) $ ( ' . t o t a l _ p r i c e ' ) . h t m l ( ' $ ' + g e t A d j u s t e d C o n s u m e r P r i c e ( ) ) . h i d e ( ) . f a d e I n
  8. ...continued... $ ( ' . t o t a l

    _ p r i c e ' ) . h t m l ( ' $ ' + g e t A d j u s t e d C o n s u m e r P r i c e ( ) ) . h i d e ( ) . f a d e I n " s $ ( ' . o r i g i n a l _ p r i c e ' ) . h t m l ( ' $ ' + g e t C o n s u m e r P r i c e ( ) ) i f $ ( ' . p a g e - c o n t e n t ' ) . l e n g t h = = 0 $ ( ' . o r i g i n a l _ p r i c e ' ) . h i d e ( ) . f a d e I n ( " s l o w " ) . c s s ( ' d i s p l a y ' , ' i n l i n e - b l o c k $ ( ' . p r i c e - b u t t o n ' ) . a d d C l a s s ( ' w i t h - d i s c o u n t ' ) $ ( ' . r e c u r r i n g - o r i g i n a l ' ) . a d d C l a s s ( ' h i d d e n ' ) $ ( ' . r e c u r r i n g - w i t h - d i s c o u n t ' ) . r e m o v e C l a s s ( ' h i d d e n ' ) u p d a t e _ o r i g i n a l _ e x e c _ p r i c i n g ( ) i f $ ( ' . p a g e - c o n t e n t ' ) . l e n g t h > 0 $ ( ' # t r a n s a c t i o n _ c o u p o n _ i d ' ) . v a l ( d a t a [ ' c o u p o n _ i d ' ] ) $ ( ' . c o u p o n - i c o n s . s u c c e s s - i c o n ' ) . s h o w ( ) $ ( ' . c o u p o n - i c o n s . e r r o r - i c o n ' ) . h i d e ( ) $ ( ' # c o u p o n ' ) . r e m o v e C l a s s ( ' f o r m - i n p u t - e r r o r ' )
  9. And wondering how to turn it into this . f

    a c t o r y ( ' C o u p o n S e r v i c e ' , [ ' $ h t t p ' , f u n c t i o n ( $ h t t p ) { v a r C o u p o n S e r v i c e = { } ; C o u p o n S e r v i c e . d a t a = { } ; C o u p o n S e r v i c e . v a l i d a t e = f u n c t i o n ( d a t a ) { r e t u r n $ h t t p ( { m e t h o d : ' P O S T ' , d a t a : d a t a , u r l : $ ( ' # c o u p o n _ c h e c k ' ) . d a t a ( ' s e t C o u p o n U r l ' ) } ) . t h e n ( f u n c t i o n ( r e s ) { C o u p o n S e r v i c e . d a t a = r e s . d a t a ; } ) }
  10. Remove logic from anonymous functions that are hard to test

    Decouple AJAX calls from their implementation
  11. Break things up into modules -- POJOs are fine Relationships

    help -- how do these methods interact with each other?
  12. Tests we don't have to write in Angular i t

    ( ' t o g g l e s t h e v a l i d a t e a n d r e m o v e c o u p o n b u t t o n s ' , f u n c t i o n ( ) { C o u p o n H a n d l e r . v a l i d a t e C o u p o n ( d a t a F o r C o u p o n ) ; e x p e c t ( $ ( ' . j s - r e m o v e - c o u p o n ' ) ) . t o B e V i s i b l e ( ) ; e x p e c t ( $ ( ' . j s - v a l i d a t e - c o u p o n ' ) ) . n o t . t o B e V i s i b l e ( ) ; } ) ;
  13. Interfacing with Angular outside Angular Some ways code-smellier than others

    < d i v i d = " h i d d e n T h i n g " > { { s o m e B o u n d V a l u e } } < / d i v > n g - i n i t a n g u l a r . e l e m e n t . s c o p e ( ) s c o p e . $ a p p l y ( )
  14. Client side MVC doesn't have to be all- encompassing. Just

    pick something small I used to think about the move to client side MVC like flipping a switch
  15. Every day I get to toss out old code to

    make way for better code
  16. Every day I get to toss out old code to

    make way for better code The project's incompleteness is a powerful motivator