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

Confronting a Monolithic Rails App with Angular...

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
Tweet

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