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

Express on Rails

Kyle Hill
October 04, 2013

Express on Rails

Have you built your first node application yet? Yeah, me too! Wasn't writing it fun and easy? Same here! Did your codebase quickly turn into an unrefactorable soupy mess too? Of course it did!

In this talk, we'll discuss the architectural and organizational strategies used by Ruby on Rails that help the scope and size of applications to scale easily. We'll then learn how we can easily employ those principles with express.js to build some serious node applications, without all the dogmatism and pain that usually comes with RoR.

Kyle Hill

October 04, 2013
Tweet

Other Decks in Programming

Transcript

  1. Why Are You Still Using Semicolons? (Or, How To Piss

    Off The First Kyle In 15 Slides Or Less)
  2. Fun

  3. "we have come to value [...] over following a plan"

    responding to change -- The Agile Manifesto
  4. Rails is a framework which is at doing what it

    wants to do exceptionally good
  5. "I started playing with node and was just setting up

    sockets and listeners and content types, and I was like, 'whoa.' It was awesome." -- the masochistic Rails dev I work with
  6. Q: "How should I structure my application?" A: "There is

    no true answer to this question, it is highly dependent on the scale of your application and the team involved. To be as flexible as possible Express makes no assumptions in terms of structure." -- express.js FAQ
  7. app.js // everyone's first node app v a r a

    p p = r e q u i r e ( ' e x p r e s s ' ) . c r e a t e S e r v e r ( ) ; v a r a s y n c = r e q u i r e ( ' a s y n c ' ) ; v a r r e q u e s t = r e q u i r e ( ' r e q u e s t ' ) ; v a r p a r s e r = r e q u i r e ( ' x m l 2 j s o n ' ) ; v a r u n d e r s c o r e = r e q u i r e ( ' u n d e r s c o r e ' ) ; v a r m o n g o d b = r e q u i r e ( " m o n g o d b " ) ; a p p . g e t ( ' / m e t h o d / s t a t i o n / : i d ' , f u n c t i o n ( r e q , r e s ) { r e q u e s t ( { u r i : ' h t t p : / / ' + r e q . h e a d e r s . h o s t + ' / s t a t i o n l i s t ' , j s o n : t r u e } , r e s . j s o n ( u n d e r s c o r e . f i n d ( b o d y . s t a t i o n s . s t a t i o n , f u n c t i o n ( s ) { r e t u r n s . t e r } ) ; } ) ; a p p . g e t ( ' / m e t h o d / s t a t i o n l i s t ' , f u n c t i o n ( r e q , r e s ) { a s y n c . a u t o ( { g e t X m l : f u n c t i o n ( c a l l b a c k ) { r e q u e s t ( ' h t t p : / / c a p i t a l b i k e s h a r e . c o m / d a t a / s t a t i o n s / b i k e S t a t i o n s . x m l ' , f c a l l b a c k ( n u l l , p a r s e r . t o J s o n ( b o d y , { o b j e c t : t r u e } ) ) ; } ) ; } , d o S t u f f : [ ' g e t X m l ' , f u n c t i o n ( c a l l b a c k , r e s u l t s ) { r e s . j s o n ( r e s u l t s . g e t X m l ) ; } ] } ) ; } ) ;
  8. app.js // npm start a p p = ( r

    e q u i r e ( " . / c o n f i g " ) ) ( ) v a r s e r v e r = r e q u i r e ( ' h t t p ' ) . c r e a t e S e r v e r ( a p p ) s e r v e r . l i s t e n ( a p p . g e t ( ' p o r t ' ) , f u n c t i o n ( ) { c o n s o l e . l o g ( " E x p r e s s r u n n i n g o n " + a p p . g e t ( " p o r t " ) ) } )
  9. Routes establish endpoints Controllers are the switchboard Views act as

    rendering pathways Models contain data and business logic Library functions are tribal knowledge
  10. Routes require controllers... Controllers require views... Views require models... Models

    require library functions... Library functions can exist alone
  11. config/index.js e x p o r t s = m

    o d u l e . e x p o r t s = f u n c t i o n ( ) { a p p = ( r e q u i r e ( " . . / b o o t s t r a p " ) ) ( ) a p p = ( r e q u i r e ( " . . / l i b " ) ) ( a p p ) a p p = ( r e q u i r e ( " . . / m o d e l s " ) ) ( a p p ) a p p = ( r e q u i r e ( " . . / v i e w s " ) ) ( a p p ) a p p = ( r e q u i r e ( " . . / c o n t r o l l e r s " ) ) ( a p p ) a p p = ( r e q u i r e ( " . . / r o u t e s " ) ) ( a p p ) r e t u r n a p p }
  12. routes/index.js e x p o r t s = m

    o d u l e . e x p o r t s = f u n c t i o n ( a p p ) { a p p . a l l ( " / " , a p p . c o n t r o l l e r s . l a n d i n g ) a p p . g e t ( " / c l i e n t / : c l i e n t " , a p p . c o n t r o l l e r s . l a n d i n g ) a p p . p o s t ( " / l o g i n " , a p p . c o n t r o l l e r s . a u t h e n t i c a t e a p p . c o n t r o l l e r s . d i s p l a y ) a p p . g e t ( " / d a s h b o a r d " , a p p . c o n t r o l l e r s . a u t h , a p p . c o n t r o l l e r s . d i s p l a y ) a p p . a l l ( " * " , a p p . c o n t r o l l e r s . 4 0 4 ) }
  13. controllers/index.js e x p o r t s = m

    o d u l e . e x p o r t s = f u n c t i o n ( a p p ) { a p p = a p p | | { } a p p . c o n t r o l l e r s = { l a n d i n g : r e q u i r e ( " . / l a n d i n g " ) , d i s p l a y : r e q u i r e ( " . / d i s p l a y " ) , a u t h : r e q u i r e ( " . / a u t h " ) , a u t h e n t i c a t e : r e q u i r e ( " . / a u t h e n t i c a t e " ) } }
  14. controllers/landing.js e x p o r t s = m

    o d u l e . e x p o r t s = f u n c t i o n ( r e q , r e s , d e f e r , a p p ) { / / H e y , l o o k , i t ' s t h e a p p l i c a t i o n c o n t e x t ! a p p = r e q . a p p | | a p p i f ( r e q . p a r a m ( " c l i e n t " ) ) { r e t u r n a p p . v i e w s . c l i e n t _ s p e c i f i c _ l a n d i n g ( r e q , r e s , a p p ) } a p p . v i e w s . l a n d i n g ( r e q , r e s , a p p ) }
  15. controllers/auth.js e x p o r t s = m

    o d u l e . e x p o r t s = f u n c t i o n ( r e q , r e s , d e f e r , a p p ) { a p p = r e q . a p p | | a p p i f ( r e q . s e s s i o n . u s e r n a m e ) { r e t u r n d e f e r ( ) } a p p . v i e w s . l o g o u t ( r e q , r e s , a p p ) }
  16. views/landing.js e x p o r t s = m

    o d u l e . e x p o r t s = f u n c t i o n ( r e q , r e s , a p p ) { a p p = a p p | | { } a p p . m o d e l s . u s e r . f i n d O n e ( { u s e r n a m e : r e q . p a r a m ( " u s e r n a m e " ) } ) . e x e c ( f u n c t i o n ( e r r , u s e r ) { i f ( e r r ) { r e s . r e n d e r ( " e r r o r _ t e m p l a t e " ) } i f ( ! u s e r ) { r e s . r e n d e r ( " u s e r _ n o t _ f o u n d " ) } r e s . r e n d e r ( " d a s h b o a r d " , { u s e r n a m e : u s e r . u s e r n a m e } ) } ) }
  17. models/index.js e x p o r t s = m

    o d u l e . e x p o r t s = f u n c t i o n ( a p p ) { / / C a n ' t s e t p r o p e r t y o f u n d e f i n e d , s o a p p = a p p | | { } a p p . m o d e l s = { u s e r : r e q u i r e ( " . / u s e r " ) , c l i e n t : r e q u i r e ( " . / c l i e n t " ) } r e t u r n a p p }
  18. test/models/index.js v a r c o d e = r

    e q u i r e ( " . . / . . / m o d e l s " ) . m o d e l s i t ( " s h o u l d h a v e a l l t h e m o d e l s w e w a n t " , f u n c t i o n ( ) { a s s e r t . h a s P r o p e r t y ( c o d e . u s e r ) a s s e r t . h a s P r o p e r t y ( c o d e . c l i e n t ) } )
  19. lib/index.js v a r l d = r e q

    u i r e ( " l o d a s h " ) e x p o r t s = m o d u l e . e x p o r t s = f u n c t i o n ( a p p ) { a p p = a p p | | { } a p p . l i b = l d . e x t e n d ( { } , r e q u i r e ( " . / f i b o n a c c i " ) , r e q u i r e ( " . / f u n c t i o n C o m p o s e " ) , r e q u i r e ( " . / b e e r a m i d " ) ) r e t u r n a p p }
  20. lib/beeramid.js v a r b e e r a m

    i d = f u n c t i o n ( ) { . . . } v a r l e v e l C o u n t e r = f u n c t i o n ( ) { . . . } v a r c a n A m o u n t D e t e r m i n i z e r = f u n c t i o n ( ) { . . . } / / A n y t h i n g n o t e x p o r t e d i s p r i v a t e , u n t e s t a b l e e x p o r t s = m o d u l e . e x p o r t s = { b e e r a m i d : b e e r a m i d , l e v e l C o u n t e r : l e v e l C o u n t e r , c a n A m o u n t D e t e r m i n i z e r : c a n A m o u n t D e t e r m i n i z e r }
  21. test/lib/beeramid.js v a r c o d e = r

    e q u i r e ( " . . / . . / l i b / b e e r a m i d " ) i t ( " s h o u l d c a l c u l a t e b e e r a m i d c o r r e c t l y " , f u n c t i o n ( ) { a s s e r t . e q u a l ( c o d e . b e e r a m i d ( 2 , 3 0 ) , 3 ) a s s e r t . e q u a l ( c o d e . b e e r a m i d ( 2 , 2 6 ) , 2 ) } ) i t ( " s h o u l d c a l c u l a t e l e v e l s i z e c o r r e c t l y " , f u n c t i o n ( ) { a s s e r t . e q u a l ( c o d e . l e v e l C o u n t e r ( 2 , 2 ) , 8 ) } )
  22. bootstrap.js e x p o r t s = m

    o d u l e . e x p o r t s = f u n c t i o n ( a p p ) { v a r e x p r e s s = r e q u i r e ( " e x p r e s s " ) v a r a p p = e x p r e s s ( ) a p p . c o n f i g u r e ( f u n c t i o n ( ) { / * a p p . s e t a n d a p p . u s e s t u f f * / } ) / / i n i t i a l i z e c o n n e c t i o n s h e r e t o o r e t u r n a p p } )