Slide 1

Slide 1 text

Node JS Development Best Practices

Slide 2

Slide 2 text

Basics First

Slide 3

Slide 3 text

What is NodeJS? A JavaScript runtime built on Chrome's V8 engine. Used primarily for server­side application development, building cross­platform tools & applications, and much more.

Slide 4

Slide 4 text

Async IO & The Event Loop

Slide 5

Slide 5 text

How does it work? c o n s o l e . l o g ( ' A ' ) ; c o n s o l e . l o g ( ' B ' ) ; s e t T i m e o u t ( ( ) = > { c o n s o l e . l o g ( ' C ' ) ; } , 1 0 0 0 ) ; s e t T i m e o u t ( ( ) = > { c o n s o l e . l o g ( ' D ' ) ; } ) ; c o n s o l e . l o g ( ' E ' ) ;

Slide 6

Slide 6 text

Think asynchronously Avoid using synchronous or blocking code like this. v a r f s = r e q u i r e ( ' f s ' ) ; f o r ( v a r i = 0 ; i < f i l e s . l e n g t h ; i + + ) { / / C a l l i n g s y n c h r o n o u s f u n c t i o n d a t a = f s . r e a d F i l e S y n c ( f i l e s [ i ] ) ; c o n s o l e . l o g ( ' C o n t e n t s = ' , d a t a ) ; } Consider using async alternatives instead. f s . r e a d F i l e ( f i l e n a m e , ' u t f 8 ' , ( e r r , d a t a ) = > { / / D o s o m e t h i n g h e r e } ) ;

Slide 7

Slide 7 text

Put require() at the top r e q u i r e ( ) & i m p o r t calls belong to the top; not in the middle of code. a p p . g e t ( " / a p i / s o m e t h i n g " , f u n c t i o n ( r e q , r e s ) { v a r d a t a s t o r e = r e q u i r e ( " m y D a t a S t o r e D e p " ) ( s o m e C o n f i g ) ; d a t a s t o r e . g e t ( r e q . q u e r y . s o m e K e y ) . . . } ) ; Why? Because they're synchronous and blocking.

Slide 8

Slide 8 text

What about CPU intensive jobs? The Non­Blocking anync IO is awesome for IO bound tasks. But what about CPU intensive works? Delegate them to queues or worker processes dedicated to do those work. PS: Avoid thinking of multi­threading as a workaround.

Slide 9

Slide 9 text

Callback Hell? Asynchronity does imply use of callbacks everywhere and could lead to callback hell. g e t D a t a ( f u n c t i o n ( x ) { g e t M o r e D a t a ( x , f u n c t i o n ( y ) { g e t M o r e D a t a ( y , f u n c t i o n ( z ) { g e t E v e n t M o r e D a t a ( z , f u n c t i o n ( ) { / / A n d e v e n m o r e . . . } ) ; } ) ; } ) ; } ) ;

Slide 10

Slide 10 text

Use Promises Promises does save us from callback hell e x p o r t f u n c t i o n g e t P r o j e c t s B y C o m p a n i e s ( a u t h , c o m p a n y I d s ) l e t p r o m i s e s = c o m p a n y I d s . m a p ( c o m p a n y I d = > g e t P r o j e c t s B y C o m p a n y ( a u t h , c o m p a n y I d ) ) ; r e t u r n P r o m i s e . a l l ( p r o m i s e s ) . t h e n ( f o r m a t R e s u l t s ) ; } f u n c t i o n g e t P r o j e c t s B y C o m p a n y ( t o k e n , c o m p a n y I d ) { l e t u r l = ` / p r o j e c t s ? c o m p a n y _ i d = $ { c o m p a n y I d } ` ; r e t u r n r p ( { m e t h o d : ' G E T ' , u r l : B A S E _ U R I + u r l } ) ; } f u n c t i o n f o r m a t R e s u l t s ( d a t a ) { r e t u r n d a t a . r e d u c e ( ( p r e v , c u r ) = > p r e v . c o n c a t ( c u r ) , [ ] ) ; }

Slide 11

Slide 11 text

And a s y n c / a w a i t And the ES7 adds a better syntatic sugar to the language using a s y n c / a w a i t . i m p o r t r p f r o m ' r e q u e s t ­ p r o m i s e ' ; a s y n c f u n c t i o n r e q u e s t A l l ( u r l s ) { l e t r e s u l t = a w a i t P r o m i s e . a l l ( u r l s . m a p ( u r l = > r p ( u r l ) ) ) ; r e t u r n r e s u l t ; } c o n s t u r l s = [ ' h t t p s : / / w w w . g o o g l e . c o m ' , ' h t t p s : / / w w w . a p p l e . c o m ' , ' h t t p s : / / w w w . y a h o o . c o m ' ] ; l e t s i t e s = r e q u e s t A l l ( u r l s ) ;

Slide 12

Slide 12 text

Setting up a new project

Slide 13

Slide 13 text

Use n p m i n i t Always use n p m i n i t (or y a r n i n i t ) to initialize your new project.

Slide 14

Slide 14 text

Use n p m s c r i p t s for your tasks You might not task runners like g u l p all the time. Mostly n p m s c r i p t s would suffice. " s c r i p t s " : { " s t a r t " : " n o d e m o n ­ ­ e x e c b a b e l ­ n o d e s r c / i n d e x . j s " , " s t a r t : s y s t e m d " : " s y s t e m c t l s t a r t o n t a r g e t ­ m o d e l a p i . s e r v i c " l i n t " : " e s l i n t . " , " c l e a n " : " r m r a f d i s t / " , " b u i l d " : " r u n ­ s c l e a n b a b e l " , " r e s t a r t " : " s y s t e m c t l r e s t a r t o n t a r g e t ­ m o d e l a p i . s e r v i c e " " s t o p " : " s y s t e m c t l s t o p o n t a r g e t ­ m o d e l a p i . s e r v i c e " , " l o g s " : " j o u r n a l c t l ­ f ­ u o n t a r g e t ­ m o d e l a p i . s e r v i c e " , " b a b e l " : " b a b e l s r c / ­ d d i s t / " } , $ n p m s t a r t # o r y a r n s t a r t

Slide 15

Slide 15 text

More sophisticated scripts # ! / u s r / b i n / e n v b a s h # G e t t h e b r a n c h n a m e f r o m t h e e n v i r o n m e n t , d e f a u l t s t o ' d e v ' i f [ ­ z " $ B R A N C H " ] ; t h e n B R A N C H = " d e v " f i # C h e c k o u t t o t h e s p e c i f i e d b r a n c h g i t f e t c h g i t c h e c k o u t " $ B R A N C H " # P u l l t h e l a t e s t c h a n g e s g i t p u l l o r i g i n " $ B R A N C H " # B u i l d t h e a p p l i c a t i o n n p m r u n b u i l d ; s y s t e m c t l r e s t a r t " $ S E R V I C E " . . .

Slide 16

Slide 16 text

Register them as n p m s c r i p t s Create your complex scripts in separate files and register n p m s c r i p t s for them. You may use s h , p y t h o n , j s etc anything to write your scripts. " s c r i p t s " : { " d e p l o y " : " . / s c r i p t s / d e p l o y . s h " " , " b u i l d " : " . / s c r i p t s / b u i l d . p y " , " a b c " : " . / s c r i p t s / a b c . j s " } Now run your script $ n p m r u n d e p l o y You might want to use packages like shelljs for these.

Slide 17

Slide 17 text

Do lint your code Make sure you l i n t your javascript code with something like e s l i n t . And ensure the linter doesn't throw any errors before you commit. p a r s e r : ' b a b e l ­ e s l i n t ' e n v : e s 6 : t r u e n o d e : t r u e p a r s e r O p t i o n s : e c m a V e r s i o n : 6 , s o u r c e T y p e : ' m o d u l e ' e c m a F e a t u r e s : m o d u l e s : t r u e

Slide 18

Slide 18 text

Why linting? Improves code quality. Enforces rules for the coding standards. Code consistency. Helps in avoiding bad practices Prevents some potential bugs.

Slide 19

Slide 19 text

Project Directory Structure Keep your root directories simple like these: s r c / ­ your source files s e r v e r / ­ server side code a p p / ­ client­side app code (if in the same repository) d i s t / or b u i l d / ­ compiled files from the source (in case you use ES6+, typescript, coffeescriptetc). And, should be added to g i t i g n o r e . p u b l i c / ­ in case you have files to be served publicly. r e s o u r c e s / ­ other miscellaneous projects resources or files

Slide 20

Slide 20 text

Example project structure So your project might look similar to this: ­ s r c / ­ s e r v e r / ­ c o n f i g / ­ c o n t r o l l e r s / ­ s e r v i c e s ­ m i d d l e w a r e s ­ m o d e l s / ­ v i e w s / ­ i n d e x . j s ­ a p p / ­ i n d e x . j s ­ d i s t / ­ p u b l i c / ­ b u i l d / ­ i n d e x . h t m l ­ r e s o u r c e s / ­ s c r i p t s / ­ d a t a /

Slide 21

Slide 21 text

Application Configuration Create an application central config file to put all your config params. / / c o n f i g . j s m o d u l e . e x p o r t s = { b u c k e t P o l i c y : p r o c e s s . e n v . B U C K E T _ P O L I C Y | | ' t r a n s i e n t ' n i o s : { b a s e U r i : p r o c e s s . e n v . N I O S _ B A S E _ U R I , . . . } , p r o c o r e : { c l i e n t S e c r e t : p r o c e s s . e n v . P R O C O R E _ C L I E N T _ S E C R E T , r e d i r e c t U r i : p r o c e s s . e n v . P R O C O R E _ R E D I R E C T _ U R I , . . . } , . . . } ;

Slide 22

Slide 22 text

Deployment Specific Credentials Put them in g i t i g n o r e d files or use environment variables. NEVER store your deploy specific credentials eg: database login, Google OAuth credentials, S3 client secret etc. in your codebase. Firstly, it's not secure. Secondly, they might be different for each deployment. And, it makes deploying really difficult.

Slide 23

Slide 23 text

Use environment variables Use environment variables to store the your deploy specific configurations & credentials. N O D E _ E N V = d e v e l o p m e n t D B _ U S E R N A M E = k a b i r D B _ P A S S W O R D = k a b i r . . . Now in your application you can do m o d u l e . e x p o r t s = { e n v : p r o c e s s . e n v . N O D E _ E N V , d a t a b a s e : { n a m e : p r o c e s s . e n v . D B _ N A M E , u s e r n a m e : p r o c e s s . e n v . D B _ U S E R N A M E , . . . } . . . } ;

Slide 24

Slide 24 text

Use n o d e ­ f o r e m a n $ y a r n a d d f o r e m a n ­ ­ d e v Now you may put your environment variables in a g i t i g n o r e d . e n v file. And f o r e m a n would load them into p r o c e s s . e n v if you run your application using n f s t a r t . (development only) $ n f s t a r t [ O K A Y ] L o a d e d E N V . e n v F i l e a s K E Y = V A L U E F o r m a t 1 0 : 4 4 : 1 3 P M w e b . 1 | > n o d e j s ­ s a m p l e ­ a p p @ 0 . 0 . 1 s t a r t / h o m e / k a b 1 0 : 4 4 : 1 3 P M w e b . 1 | > n o d e m o n ­ ­ e x e c b a b e l ­ n o d e s r c / i n d e x . j s 1 0 : 4 4 : 1 3 P M w e b . 1 | [ n o d e m o n ] 1 . 1 1 . 0 1 0 : 4 4 : 1 3 P M w e b . 1 | [ n o d e m o n ] t o r e s t a r t a t a n y t i m e , e n t e r ` 1 0 : 4 4 : 1 3 P M w e b . 1 | [ n o d e m o n ] w a t c h i n g : * . * 1 0 : 4 4 : 1 3 P M w e b . 1 | [ n o d e m o n ] s t a r t i n g ` b a b e l ­ n o d e s r c / i n d e x . 1 0 : 4 4 : 1 4 P M w e b . 1 | i n f o : L i s t e n i n g o n p o r t 3 0 0 0

Slide 25

Slide 25 text

ES6 and Beyond

Slide 26

Slide 26 text

Start using ES6+ features i m p o r t c o r s f r o m ' c o r s ' ; i m p o r t e x p r e s s f r o m ' e x p r e s s ' ; i m p o r t m o r g a n f r o m ' m o r g a n ' ; i m p o r t P r o m i s e f r o m ' b l u e b i r d ' ; i m p o r t c o n f i g f r o m ' . / c o n f i g / c o n f i g ' ; i m p o r t r o u t e s f r o m ' . / r o u t e s ' ; i m p o r t { s t a r t } f r o m ' . / s e r v i c e / s e r v e r ' ; i m p o r t { e n s u r e E v e r y t h i n g G o o d } f r o m ' . / s e r v i c e / e n s u r e ' ; l e t a p p = e x p r e s s ( ) ; c o n s t P O R T = p r o c e s s . e n v . P O R T | | 8 0 0 0 ; a p p . u s e ( m o r g a n ( c o n f i g . m o r g o n F o r m a t ( a p p . g e t ( ' e n v ' ) ) ) ) ; a p p . u s e ( c o r s ( ) ; a p p . u s e ( ' / a p i ' , r o u t e s ) ; . . .

Slide 27

Slide 27 text

Transpile your code Current version of NodeJS supports most of the ES2015 features but not all of them. But we can still use ES6+ features in our code using transpilers like b a b e l $ y a r n a d d ­ ­ d e v b a b e l ­ c l i b a b e l ­ p r e s e t ­ e s 2 0 1 5

Slide 28

Slide 28 text

Some useful packages Some of the most common npm packages for NodeJS projects e x p r e s s c o r s m o r g a n b l u e b i r d r e q u e s t r e q u e s t ­ p r o m i s e l o d a s h m o m e n t b o d y ­ p a r s e r w i n s t o n m u l t e r

Slide 29

Slide 29 text

Packages for better development Some of the packages that could improve your development experience b a b e l ­ c l i e s l i n t n o d e m o n f o r e m a n n p m ­ r u n ­ a l l s h e l l j s p m 2 d e v t o o l n o d e ­ i n s p e c t o r

Slide 30

Slide 30 text

Thank You

Slide 31

Slide 31 text

No content