mirror of
https://github.com/goldbergyoni/nodebestpractices.git
synced 2025-10-30 00:57:04 +08:00
Merge pull request #182 from sagirk/fix/sk/spaces-and-periods
Fix spaces, periods and line breaks
This commit is contained in:
147
README.md
147
README.md
@ -3,7 +3,7 @@
|
||||
# Node.js Best Practices
|
||||
|
||||
<h1 align="center">
|
||||
<img src="assets/images/banner-2.jpg" alt="Node.js Best Practices" />
|
||||
<img src="assets/images/banner-2.jpg" alt="Node.js Best Practices">
|
||||
</h1>
|
||||
|
||||
<br/>
|
||||
@ -15,13 +15,15 @@
|
||||
<br/>
|
||||
|
||||
[](https://twitter.com/nodepractices/) **Follow us on Twitter!** [**@nodepractices**](https://twitter.com/nodepractices/)
|
||||
|
||||
<br/>
|
||||
|
||||
Read in different language: [**CN**](/README.chinese.md) [(**ES**, **FR**, **HE**, **KR**, **RU** and **TR** in progress!)](#translations)
|
||||
Read in a different language: [**CN**](/README.chinese.md) [(**ES**, **FR**, **HE**, **KR**, **RU** and **TR** in progress!)](#translations)
|
||||
|
||||
<br/>
|
||||
|
||||
# Welcome! 3 Things You Ought To Know First:
|
||||
|
||||
**1. When you read here, you in fact read dozens of the best Node.js articles -** this is a summary and curation of the top-ranked content on Node.js best practices
|
||||
|
||||
**2. It is the largest compilation, and it is growing every week -** currently, more than 50 best practices, style guides, and architectural tips are presented. New issues and PR are created every day to keep this live book updated. We'd love to see you contributing here, whether fixing some code mistake or suggesting brilliant new ideas. See our [milestones here](https://github.com/i0natan/nodebestpractices/milestones?direction=asc&sort=due_date&state=open)
|
||||
@ -31,6 +33,7 @@
|
||||
<br/><br/><br/>
|
||||
|
||||
## Table of Contents
|
||||
|
||||
1. [Project structure Practices (5)](#1-project-structure-practices)
|
||||
2. [Error Handling Practices (11) ](#2-error-handling-practices)
|
||||
3. [Code Style Practices (12) ](#3-code-style-practices)
|
||||
@ -40,6 +43,7 @@
|
||||
7. Performance Practices ([coming soon](https://github.com/i0natan/nodebestpractices/milestones?direction=asc&sort=due_date&state=open))
|
||||
|
||||
<br/><br/><br/>
|
||||
|
||||
# `1. Project Structure Practices`
|
||||
|
||||
## ![✔] 1.1 Structure your solution by components
|
||||
@ -84,14 +88,12 @@
|
||||
|
||||
## ![✔] 1.5 Use environment aware, secure and hierarchical config
|
||||
|
||||
|
||||
**TL;DR:** A perfect and flawless configuration setup should ensure (a) keys can be read from file AND from environment variable (b) secrets are kept outside committed code (c) config is hierarchical for easier findability. There are a few packages that can help tick most of those boxes like [rc](https://www.npmjs.com/package/rc), [nconf](https://www.npmjs.com/package/nconf) and [config](https://www.npmjs.com/package/config).
|
||||
**TL;DR:** A perfect and flawless configuration setup should ensure (a) keys can be read from file AND from environment variable (b) secrets are kept outside committed code (c) config is hierarchical for easier findability. There are a few packages that can help tick most of those boxes like [rc](https://www.npmjs.com/package/rc), [nconf](https://www.npmjs.com/package/nconf) and [config](https://www.npmjs.com/package/config)
|
||||
|
||||
**Otherwise:** Failing to satisfy any of the config requirements will simply bog down the development or devops team. Probably both
|
||||
|
||||
🔗 [**Read More: configuration best practices**](/sections/projectstructre/configguide.md)
|
||||
|
||||
|
||||
<br/><br/><br/>
|
||||
|
||||
<p align="right"><a href="#table-of-contents">⬆ Return to top</a></p>
|
||||
@ -112,7 +114,6 @@
|
||||
|
||||
**TL;DR:** Many throws errors as a string or as some custom type – this complicates the error handling logic and the interoperability between modules. Whether you reject a promise, throw an exception or an emit error – using only the built-in Error object will increase uniformity and prevent loss of information
|
||||
|
||||
|
||||
**Otherwise:** When invoking some component, being uncertain which type of errors come in return – it makes proper error handling much harder. Even worse, using custom types to describe errors might lead to loss of critical error information like the stack trace!
|
||||
|
||||
🔗 [**Read More: using the built-in error object**](/sections/errorhandling/useonlythebuiltinerror.md)
|
||||
@ -131,7 +132,7 @@
|
||||
|
||||
## ![✔] 2.4 Handle errors centrally, not within an Express middleware
|
||||
|
||||
**TL;DR:** Error handling logic such as mail to admin and logging should be encapsulated in a dedicated and centralized object that all endpoints (e.g. Express middleware, cron jobs, unit-testing) call when an error comes in.
|
||||
**TL;DR:** Error handling logic such as mail to admin and logging should be encapsulated in a dedicated and centralized object that all endpoints (e.g. Express middleware, cron jobs, unit-testing) call when an error comes in
|
||||
|
||||
**Otherwise:** Not handling errors within a single place will lead to code duplication and probably to improperly handled errors
|
||||
|
||||
@ -145,7 +146,6 @@
|
||||
|
||||
**Otherwise:** An API client might decide to crash and restart only because he received back an error he couldn’t understand. Note: the caller of your API might be you (very typical in a microservice environment)
|
||||
|
||||
|
||||
🔗 [**Read More: documenting errors in Swagger**](/sections/errorhandling/documentingusingswagger.md)
|
||||
|
||||
<br/><br/>
|
||||
@ -160,27 +160,22 @@
|
||||
|
||||
<br/><br/>
|
||||
|
||||
|
||||
|
||||
## ![✔] 2.7 Use a mature logger to increase error visibility
|
||||
|
||||
**TL;DR:** A set of mature logging tools like Winston, Bunyan or Log4J, will speed-up error discovery and understanding. So forget about console.log.
|
||||
**TL;DR:** A set of mature logging tools like Winston, Bunyan or Log4J, will speed-up error discovery and understanding. So forget about console.log
|
||||
|
||||
**Otherwise:** Skimming through console.logs or manually through messy text file without querying tools or a decent log viewer might keep you busy at work until late
|
||||
|
||||
🔗 [**Read More: using a mature logger**](/sections/errorhandling/usematurelogger.md)
|
||||
|
||||
|
||||
<br/><br/>
|
||||
|
||||
|
||||
## ![✔] 2.8 Test error flows using your favorite test framework
|
||||
|
||||
**TL;DR:** Whether professional automated QA or plain manual developer testing – Ensure that your code not only satisfies positive scenario but also handle and return the right errors. Testing frameworks like Mocha & Chai can handle this easily (see code examples within the "Gist popup")
|
||||
|
||||
**Otherwise:** Without testing, whether automatically or manually, you can’t rely on our code to return the right errors. Without meaningful errors – there’s no error handling
|
||||
|
||||
|
||||
🔗 [**Read More: testing error flows**](/sections/errorhandling/testingerrorflows.md)
|
||||
|
||||
<br/><br/>
|
||||
@ -191,26 +186,23 @@
|
||||
|
||||
**Otherwise:** You might spend great effort on measuring API performance and downtimes, probably you’ll never be aware which are your slowest code parts under real-world scenario and how these affect the UX
|
||||
|
||||
|
||||
🔗 [**Read More: using APM products**](/sections/errorhandling/apmproducts.md)
|
||||
|
||||
<br/><br/>
|
||||
|
||||
|
||||
## ![✔] 2.10 Catch unhandled promise rejections
|
||||
|
||||
**TL;DR:** Any exception thrown within a promise will get swallowed and discarded unless a developer didn’t forget to explicitly handle. Even if your code is subscribed to process.uncaughtException! Overcome this by registering to the event process.unhandledRejection
|
||||
|
||||
**Otherwise:** Your errors will get swallowed and leave no trace. Nothing to worry about
|
||||
|
||||
|
||||
🔗 [**Read More: catching unhandled promise rejection**](/sections/errorhandling/catchunhandledpromiserejection.md)
|
||||
|
||||
<br/><br/>
|
||||
|
||||
## ![✔] 2.11 Fail fast, validate arguments using a dedicated library
|
||||
|
||||
**TL;DR:** This should be part of your Express best practices – Assert API input to avoid nasty bugs that are much harder to track later. The validation code is usually tedious unless you are using a very cool helper library like Joi.
|
||||
**TL;DR:** This should be part of your Express best practices – Assert API input to avoid nasty bugs that are much harder to track later. The validation code is usually tedious unless you are using a very cool helper library like Joi
|
||||
|
||||
**Otherwise:** Consider this – your function expects a numeric argument “Discount” which the caller forgets to pass, later on, your code checks if Discount!=0 (amount of allowed discount is greater than zero), then it will allow the user to enjoy a discount. OMG, what a nasty bug. Can you see it?
|
||||
|
||||
@ -226,7 +218,7 @@
|
||||
|
||||
**TL;DR:** [ESLint](https://eslint.org) is the de-facto standard for checking possible code errors and fixing code style, not only to identify nitty-gritty spacing issues but also to detect serious code anti-patterns like developers throwing errors without classification. Though ESLint can automatically fix code styles, other tools like [prettier](https://www.npmjs.com/package/prettier) and [beautify](https://www.npmjs.com/package/js-beautify) are more powerful in formatting the fix and work in conjunction with ESLint
|
||||
|
||||
**Otherwise:** Developers will focus on tedious spacing and line-width concerns and time might be wasted overthinking about the project's code style.
|
||||
**Otherwise:** Developers will focus on tedious spacing and line-width concerns and time might be wasted overthinking about the project's code style
|
||||
|
||||
<br/><br/>
|
||||
|
||||
@ -240,9 +232,10 @@
|
||||
|
||||
## ![✔] 3.3 Start a Codeblock's Curly Braces on the Same Line
|
||||
|
||||
**TL;DR:** The opening curly braces of a code block should be in the same line of the opening statement.
|
||||
**TL;DR:** The opening curly braces of a code block should be in the same line of the opening statement
|
||||
|
||||
### Code Example
|
||||
|
||||
```javascript
|
||||
// Do
|
||||
function someFunction() {
|
||||
@ -264,27 +257,28 @@
|
||||
|
||||
## ![✔] 3.4 Don't Forget the Semicolon
|
||||
|
||||
**TL;DR:** While not unanimously agreed upon, it is still recommended to put a semicolon at the end of each statement. This will make your code more readable and explicit to other developers who read it.
|
||||
**TL;DR:** While not unanimously agreed upon, it is still recommended to put a semicolon at the end of each statement. This will make your code more readable and explicit to other developers who read it
|
||||
|
||||
**Otherwise:** As seen in the previous section, JavaScript's interpreter automatically adds a semicolon at the end of a statement if there isn't one which might lead to some undesired results.
|
||||
**Otherwise:** As seen in the previous section, JavaScript's interpreter automatically adds a semicolon at the end of a statement if there isn't one which might lead to some undesired results
|
||||
|
||||
<br/><br/>
|
||||
|
||||
## ![✔] 3.5 Name Your Functions
|
||||
|
||||
**TL;DR:** Name all functions, including closures and callbacks. Avoid anonymous functions. This is especially useful when profiling a node app. Naming all functions will allow you to easily understand what you're looking at when checking a memory snapshot.
|
||||
**TL;DR:** Name all functions, including closures and callbacks. Avoid anonymous functions. This is especially useful when profiling a node app. Naming all functions will allow you to easily understand what you're looking at when checking a memory snapshot
|
||||
|
||||
**Otherwise:** Debugging production issues using a core dump (memory snapshot) might become challenging as you notice significant memory consumption from anonymous functions.
|
||||
**Otherwise:** Debugging production issues using a core dump (memory snapshot) might become challenging as you notice significant memory consumption from anonymous functions
|
||||
|
||||
<br/><br/>
|
||||
|
||||
## ![✔] 3.6 Naming conventions for variables, constants, functions and classes
|
||||
|
||||
**TL;DR:** Use ***lowerCamelCase*** when naming constants, variables and functions and ***UpperCamelCase*** (capital first letter as well) when naming classes. This will help you to easily distinguish between plain variables/functions, and classes that require instantiation. Use descriptive names, but try to keep them short.
|
||||
**TL;DR:** Use **_lowerCamelCase_** when naming constants, variables and functions and **_UpperCamelCase_** (capital first letter as well) when naming classes. This will help you to easily distinguish between plain variables/functions, and classes that require instantiation. Use descriptive names, but try to keep them short
|
||||
|
||||
**Otherwise:** Javascript is the only language in the world which allows invoking a constructor ("Class") directly without instantiating it first. Consequently, Classes and function-constructors are differentiated by starting with UpperCamelCase.
|
||||
**Otherwise:** Javascript is the only language in the world which allows invoking a constructor ("Class") directly without instantiating it first. Consequently, Classes and function-constructors are differentiated by starting with UpperCamelCase
|
||||
|
||||
### Code Example
|
||||
|
||||
### Code Example ###
|
||||
```javascript
|
||||
// for class name we use UpperCamelCase
|
||||
class SomeClassExample {}
|
||||
@ -303,9 +297,9 @@
|
||||
|
||||
## ![✔] 3.7 Prefer const over let. Ditch the var
|
||||
|
||||
**TL;DR:** Using `const` means that once a variable is assigned, it cannot be reassigned. Preferring const will help you to not be tempted to use the same variable for different uses, and make your code clearer. If a variable needs to be reassigned, in a for loop, for example, use `let` to declare it. Another important aspect of `let` is that a variable declared using it is only available in the block scope in which it was defined. `var` is function scoped, not block scoped, and [shouldn't be used in ES6](https://hackernoon.com/why-you-shouldnt-use-var-anymore-f109a58b9b70) now that you have const and let at your disposal.
|
||||
**TL;DR:** Using `const` means that once a variable is assigned, it cannot be reassigned. Preferring const will help you to not be tempted to use the same variable for different uses, and make your code clearer. If a variable needs to be reassigned, in a for loop, for example, use `let` to declare it. Another important aspect of `let` is that a variable declared using it is only available in the block scope in which it was defined. `var` is function scoped, not block scoped, and [shouldn't be used in ES6](https://hackernoon.com/why-you-shouldnt-use-var-anymore-f109a58b9b70) now that you have const and let at your disposal
|
||||
|
||||
**Otherwise:** Debugging becomes way more cumbersome when following a variable that frequently changes.
|
||||
**Otherwise:** Debugging becomes way more cumbersome when following a variable that frequently changes
|
||||
|
||||
🔗 [**Read more: JavaScript ES6+: var, let, or const?** ](https://medium.com/javascript-scene/javascript-es6-var-let-or-const-ba58b8dcde75)
|
||||
|
||||
@ -313,9 +307,9 @@
|
||||
|
||||
## ![✔] 3.8 Requires come first, and not inside functions
|
||||
|
||||
**TL;DR:** Require modules at the beginning of each file, before and outside of any functions. This simple best practice will not only help you easily and quickly tell the dependencies of a file right at the top but also avoids a couple of potential problems.
|
||||
**TL;DR:** Require modules at the beginning of each file, before and outside of any functions. This simple best practice will not only help you easily and quickly tell the dependencies of a file right at the top but also avoids a couple of potential problems
|
||||
|
||||
**Otherwise:** Requires are run synchronously by Node.js. If they are called from within a function, it may block other requests from being handled at a more critical time. Also, if a required module or any of its own dependencies throw an error and crash the server, it is best to find out about it as soon as possible, which might not be the case if that module is required from within a function.
|
||||
**Otherwise:** Requires are run synchronously by Node.js. If they are called from within a function, it may block other requests from being handled at a more critical time. Also, if a required module or any of its own dependencies throw an error and crash the server, it is best to find out about it as soon as possible, which might not be the case if that module is required from within a function
|
||||
|
||||
<br/><br/>
|
||||
|
||||
@ -323,12 +317,13 @@
|
||||
|
||||
**TL;DR:** When developing a module/library in a folder, place an index.js file that exposes the module's
|
||||
internals so every consumer will pass through it. This serves as an 'interface' to your module and eases
|
||||
future changes without breaking the contract.
|
||||
future changes without breaking the contract
|
||||
|
||||
**Otherwise:** Changing the internal structure of files or the signature may break the interface with
|
||||
clients.
|
||||
clients
|
||||
|
||||
### Code example
|
||||
|
||||
```javascript
|
||||
// Do
|
||||
module.exports.SMSProvider = require('./SMSProvider');
|
||||
@ -341,14 +336,14 @@ clients.
|
||||
|
||||
<br/><br/>
|
||||
|
||||
|
||||
## ![✔] 3.10 Use the `===` operator
|
||||
|
||||
**TL;DR:** Prefer the strict equality operator `===` over the weaker abstract equality operator `==`. `==` will compare two variables after converting them to a common type. There is no type conversion in `===`, and both variables must be of the same type to be equal.
|
||||
**TL;DR:** Prefer the strict equality operator `===` over the weaker abstract equality operator `==`. `==` will compare two variables after converting them to a common type. There is no type conversion in `===`, and both variables must be of the same type to be equal
|
||||
|
||||
**Otherwise:** Unequal variables might return true when compared with the `==` operator.
|
||||
**Otherwise:** Unequal variables might return true when compared with the `==` operator
|
||||
|
||||
### Code example
|
||||
|
||||
```javascript
|
||||
'' == '0' // false
|
||||
0 == '' // true
|
||||
@ -363,15 +358,16 @@ null == undefined // true
|
||||
|
||||
' \t\r\n ' == 0 // true
|
||||
```
|
||||
|
||||
All statements above will return false if used with `===`
|
||||
|
||||
<br/><br/>
|
||||
|
||||
## ![✔] 3.11 Use Async Await, avoid callbacks
|
||||
|
||||
**TL;DR:** Node 8 LTS now has full support for Async-await. This is a new way of dealing with asynchronous code which supersedes callbacks and promises. Async-await is non-blocking, and it makes asynchronous code look synchronous. The best gift you can give to your code is using async-await which provides a much more compact and familiar code syntax like try-catch.
|
||||
**TL;DR:** Node 8 LTS now has full support for Async-await. This is a new way of dealing with asynchronous code which supersedes callbacks and promises. Async-await is non-blocking, and it makes asynchronous code look synchronous. The best gift you can give to your code is using async-await which provides a much more compact and familiar code syntax like try-catch
|
||||
|
||||
**Otherwise:** Handling async errors in callback style is probably the fastest way to hell - this style forces to check errors all over, deal with awkward code nesting and make it difficult to reason about the code flow.
|
||||
**Otherwise:** Handling async errors in callback style is probably the fastest way to hell - this style forces to check errors all over, deal with awkward code nesting and make it difficult to reason about the code flow
|
||||
|
||||
🔗[**Read more:** Guide to async await 1.0](https://github.com/yortus/asyncawait)
|
||||
|
||||
@ -379,18 +375,16 @@ All statements above will return false if used with `===`
|
||||
|
||||
## ![✔] 3.12 Use Fat (=>) Arrow Functions
|
||||
|
||||
**TL;DR:** Though it's recommended to use async-await and avoid function parameters when dealing with older API that accept promises or callbacks - arrow functions make the code structure more compact and keep the lexical context of the root function (i.e. 'this').
|
||||
**TL;DR:** Though it's recommended to use async-await and avoid function parameters when dealing with older API that accept promises or callbacks - arrow functions make the code structure more compact and keep the lexical context of the root function (i.e. 'this')
|
||||
|
||||
**Otherwise:** Longer code (in ES5 functions) is more prone to bugs and cumbersome to read.
|
||||
**Otherwise:** Longer code (in ES5 functions) is more prone to bugs and cumbersome to read
|
||||
|
||||
🔗 [**Read mode: It’s Time to Embrace Arrow Functions**](https://medium.com/javascript-scene/familiarity-bias-is-holding-you-back-its-time-to-embrace-arrow-functions-3d37e1a9bb75)
|
||||
|
||||
|
||||
<br/><br/><br/>
|
||||
|
||||
<p align="right"><a href="#table-of-contents">⬆ Return to top</a></p>
|
||||
|
||||
|
||||
# `4. Testing And Overall Quality Practices`
|
||||
|
||||
## ![✔] 4.1 At the very least, write API (component) testing
|
||||
@ -407,12 +401,11 @@ All statements above will return false if used with `===`
|
||||
|
||||
**Otherwise:** You may let pass some anti-pattern and possible vulnerable code to your production environment.
|
||||
|
||||
|
||||
<br/><br/>
|
||||
|
||||
## ![✔] 4.3 Carefully choose your CI platform (Jenkins vs CircleCI vs Travis vs Rest of the world)
|
||||
|
||||
**TL;DR:** Your continuous integration platform (CICD) will host all the quality tools (e.g test, lint) so it should come with a vibrant ecosystem of plugins. [Jenkins](https://jenkins.io/) used to be the default for many projects as it has the biggest community along with a very powerful platform at the price of complex setup that demands a steep learning curve. Nowadays, it became much easier to set up a CI solution using SaaS tools like [CircleCI](https://circleci.com) and others. These tools allow crafting a flexible CI pipeline without the burden of managing the whole infrastructure. Eventually, it's a trade-off between robustness and speed - choose your side carefully.
|
||||
**TL;DR:** Your continuous integration platform (CICD) will host all the quality tools (e.g test, lint) so it should come with a vibrant ecosystem of plugins. [Jenkins](https://jenkins.io/) used to be the default for many projects as it has the biggest community along with a very powerful platform at the price of complex setup that demands a steep learning curve. Nowadays, it became much easier to set up a CI solution using SaaS tools like [CircleCI](https://circleci.com) and others. These tools allow crafting a flexible CI pipeline without the burden of managing the whole infrastructure. Eventually, it's a trade-off between robustness and speed - choose your side carefully
|
||||
|
||||
**Otherwise:** Choosing some niche vendor might get you blocked once you need some advanced customization. On the other hand, going with Jenkins might burn precious time on infrastructure setup
|
||||
|
||||
@ -442,8 +435,6 @@ All statements above will return false if used with `===`
|
||||
|
||||
**Otherwise:** There won't be any automated metric telling you when a large portion of your code is not covered by testing
|
||||
|
||||
|
||||
|
||||
<br/><br/>
|
||||
|
||||
## ![✔] 4.7 Inspect for outdated packages
|
||||
@ -458,21 +449,19 @@ All statements above will return false if used with `===`
|
||||
|
||||
**TL;DR:** End to end (e2e) testing which includes live data used to be the weakest link of the CI process as it depends on multiple heavy services like DB. Docker-compose turns this problem into a breeze by crafting production-like environment using a simple text file and easy commands. It allows crafting all the dependent services, DB and isolated network for e2e testing. Last but not least, it can keep a stateless environment that is invoked before each test suite and dies right after
|
||||
|
||||
|
||||
**Otherwise:** Without docker-compose teams must maintain a testing DB for each testing environment including developers machines, keep all those DBs in sync so test results won't vary across environments
|
||||
|
||||
|
||||
<br/><br/><br/>
|
||||
|
||||
<p align="right"><a href="#table-of-contents">⬆ Return to top</a></p>
|
||||
|
||||
# `5. Going To Production Practices`
|
||||
|
||||
## ![✔] 5.1. Monitoring!
|
||||
|
||||
**TL;DR:** Monitoring is a game of finding out issues before customers do – obviously this should be assigned unprecedented importance. The market is overwhelmed with offers thus consider starting with defining the basic metrics you must follow (my suggestions inside), then go over additional fancy features and choose the solution that ticks all boxes. Click ‘The Gist’ below for an overview of the solutions
|
||||
|
||||
**Otherwise:** Failure === disappointed customers. Simple.
|
||||
|
||||
**Otherwise:** Failure === disappointed customers. Simple
|
||||
|
||||
🔗 [**Read More: Monitoring!**](/sections/production/monitoring.md)
|
||||
|
||||
@ -484,7 +473,6 @@ All statements above will return false if used with `===`
|
||||
|
||||
**Otherwise:** You end-up with a black box that is hard to reason about, then you start re-writing all logging statements to add additional information
|
||||
|
||||
|
||||
🔗 [**Read More: Increase transparency using smart logging**](/sections/production/smartlogging.md)
|
||||
|
||||
<br/><br/>
|
||||
@ -495,18 +483,16 @@ All statements above will return false if used with `===`
|
||||
|
||||
**Otherwise:** Your poor single thread will stay busy doing infrastructural tasks instead of dealing with your application core and performance will degrade accordingly
|
||||
|
||||
|
||||
🔗 [**Read More: Delegate anything possible (e.g. gzip, SSL) to a reverse proxy**](/sections/production/delegatetoproxy.md)
|
||||
|
||||
<br/><br/>
|
||||
|
||||
## ![✔] 5.4. Lock dependencies
|
||||
|
||||
**TL;DR:** Your code must be identical across all environments, but amazingly NPM lets dependencies drift across environments by default – when you install packages at various environments it tries to fetch packages’ latest patch version. Overcome this by using NPM config files, .npmrc, that tell each environment to save the exact (not the latest) version of each package. Alternatively, for finer grain control use NPM” shrinkwrap”. *Update: as of NPM5, dependencies are locked by default. The new package manager in town, Yarn, also got us covered by default
|
||||
**TL;DR:** Your code must be identical across all environments, but amazingly NPM lets dependencies drift across environments by default – when you install packages at various environments it tries to fetch packages’ latest patch version. Overcome this by using NPM config files, .npmrc, that tell each environment to save the exact (not the latest) version of each package. Alternatively, for finer grain control use NPM” shrinkwrap”. \*Update: as of NPM5, dependencies are locked by default. The new package manager in town, Yarn, also got us covered by default
|
||||
|
||||
**Otherwise:** QA will thoroughly test the code and approve a version that will behave differently at production. Even worse, different servers at the same production cluster might run different code
|
||||
|
||||
|
||||
🔗 [**Read More: Lock dependencies**](/sections/production/lockdependencies.md)
|
||||
|
||||
<br/><br/>
|
||||
@ -517,10 +503,8 @@ All statements above will return false if used with `===`
|
||||
|
||||
**Otherwise:** Running dozens of instances without a clear strategy and too many tools together (cluster management, docker, PM2) might lead to a DevOps chaos
|
||||
|
||||
|
||||
🔗 [**Read More: Guard process uptime using the right tool**](/sections/production/guardprocess.md)
|
||||
|
||||
|
||||
<br/><br/>
|
||||
|
||||
## ![✔] 5.6. Utilize all CPU cores
|
||||
@ -529,7 +513,6 @@ All statements above will return false if used with `===`
|
||||
|
||||
**Otherwise:** Your app will likely utilize only 25% of its available resources(!) or even less. Note that a typical server has 4 CPU cores or more, naive deployment of Node.js utilizes only 1 (even using PaaS services like AWS beanstalk!)
|
||||
|
||||
|
||||
🔗 [**Read More: Utilize all CPU cores**](/sections/production/utilizecpu.md)
|
||||
|
||||
<br/><br/>
|
||||
@ -540,7 +523,6 @@ All statements above will return false if used with `===`
|
||||
|
||||
**Otherwise:** You’ll find that you’re performing many “diagnostic deploys” – shipping code to production only to extract some information for diagnostic purposes
|
||||
|
||||
|
||||
🔗 [**Read More: Create a ‘maintenance endpoint’**](/sections/production/createmaintenanceendpoint.md)
|
||||
|
||||
<br/><br/>
|
||||
@ -551,20 +533,16 @@ All statements above will return false if used with `===`
|
||||
|
||||
**Otherwise:** You might spend great effort on measuring API performance and downtimes, probably you’ll never be aware which is your slowest code parts under real-world scenario and how these affects the UX
|
||||
|
||||
|
||||
🔗 [**Read More: Discover errors and downtime using APM products**](/sections/production/apmproducts.md)
|
||||
|
||||
|
||||
<br/><br/>
|
||||
|
||||
|
||||
## ![✔] 5.9. Make your code production-ready
|
||||
|
||||
**TL;DR:** Code with the end in mind, plan for production from day 1. This sounds a bit vague so I’ve compiled a few development tips that are closely related to production maintenance (click Gist below)
|
||||
|
||||
**Otherwise:** A world champion IT/DevOps guy won’t save a system that is badly written
|
||||
|
||||
|
||||
🔗 [**Read More: Make your code production-ready**](/sections/production/productoncode.md)
|
||||
|
||||
<br/><br/>
|
||||
@ -575,74 +553,60 @@ All statements above will return false if used with `===`
|
||||
|
||||
**Otherwise:** Your process memory might leak a hundred megabytes a day like happened in Wallmart
|
||||
|
||||
|
||||
🔗 [**Read More: Measure and guard the memory usage**](/sections/production/measurememory.md)
|
||||
|
||||
<br/><br/>
|
||||
|
||||
|
||||
## ![✔] 5.11. Get your frontend assets out of Node
|
||||
|
||||
**TL;DR:** Serve frontend content using dedicated middleware (nginx, S3, CDN) because Node performance really gets hurt when dealing with many static files due to its single threaded model
|
||||
|
||||
**Otherwise:** Your single Node thread will be busy streaming hundreds of html/images/angular/react files instead of allocating all its resources for the task it was born for – serving dynamic content
|
||||
|
||||
|
||||
🔗 [**Read More: Get your frontend assets out of Node**](/sections/production/frontendout.md)
|
||||
|
||||
<br/><br/>
|
||||
|
||||
|
||||
## ![✔] 5.12. Be stateless, kill your Servers almost every day
|
||||
|
||||
**TL;DR:** Store any type of data (e.g. users session, cache, uploaded files) within external data stores. Consider ‘killing’ your servers periodically or use ‘serverless’ platform (e.g. AWS Lambda) that explicitly enforces a stateless behavior
|
||||
|
||||
**Otherwise:** Failure at a given server will result in application downtime instead of just killing a faulty machine. Moreover, scaling-out elasticity will get more challenging due to the reliance on a specific server
|
||||
|
||||
|
||||
🔗 [**Read More: Be stateless, kill your Servers almost every day**](/sections/production/bestateless.md)
|
||||
|
||||
|
||||
<br/><br/>
|
||||
|
||||
|
||||
## ![✔] 5.13. Use tools that automatically detect vulnerabilities
|
||||
|
||||
**TL;DR:** Even the most reputable dependencies such as Express have known vulnerabilities (from time to time) that can put a system at risk. This can get easily tamed using community and commercial tools that constantly check for vulnerabilities and warn (locally or at GitHub), some can even patch them immediately
|
||||
|
||||
**Otherwise:** Otherwise: Keeping your code clean from vulnerabilities without dedicated tools will require to constantly follow online publications about new threats. Quite tedious
|
||||
|
||||
|
||||
🔗 [**Read More: Use tools that automatically detect vulnerabilities**](/sections/production/detectvulnerabilities.md)
|
||||
|
||||
<br/><br/>
|
||||
|
||||
|
||||
## ![✔] 5.14. Assign ‘TransactionId’ to each log statement
|
||||
|
||||
**TL;DR:** Assign the same identifier, transaction-id: {some value}, to each log entry within a single request. Then when inspecting errors in logs, easily conclude what happened before and after. Unfortunately, this is not easy to achieve in Node due to its async nature, see code examples inside
|
||||
|
||||
**Otherwise:** Looking at a production error log without the context – what happened before – makes it much harder and slower to reason about the issue
|
||||
|
||||
|
||||
🔗 [**Read More: Assign ‘TransactionId’ to each log statement**](/sections/production/assigntransactionid.md)
|
||||
|
||||
<br/><br/>
|
||||
|
||||
|
||||
## ![✔] 5.15. Set NODE_ENV=production
|
||||
|
||||
**TL;DR:** Set the environment variable NODE_ENV to ‘production’ or ‘development’ to flag whether production optimizations should get activated – many NPM packages determining the current environment and optimize their code for production
|
||||
|
||||
**Otherwise:** Omitting this simple property might greatly degrade performance. For example, when using Express for server-side rendering omitting `NODE_ENV` makes the slower by a factor of three!
|
||||
|
||||
|
||||
🔗 [**Read More: Set NODE_ENV=production**](/sections/production/setnodeenv.md)
|
||||
|
||||
|
||||
<br/><br/>
|
||||
|
||||
|
||||
## ![✔] 5.16. Design automated, atomic and zero-downtime deployments
|
||||
|
||||
**TL;DR:** Researches show that teams who perform many deployments – lowers the probability of severe production issues. Fast and automated deployments that don’t require risky manual steps and service downtime significantly improves the deployment process. You should probably achieve that using Docker combined with CI tools as they became the industry standard for streamlined deployment
|
||||
@ -653,9 +617,9 @@ All statements above will return false if used with `===`
|
||||
|
||||
## ![✔] 5.17. Use an LTS release of Node.js
|
||||
|
||||
**TL;DR:** Ensure you are using an LTS version of Node.js to receive critical bug fixes, security updates and performance improvements.
|
||||
**TL;DR:** Ensure you are using an LTS version of Node.js to receive critical bug fixes, security updates and performance improvements
|
||||
|
||||
**Otherwise:** Newly discovered bugs or vulnerabilities could be used to exploit an application running in production, and your application may become unsupported by various modules and harder to maintain.
|
||||
**Otherwise:** Newly discovered bugs or vulnerabilities could be used to exploit an application running in production, and your application may become unsupported by various modules and harder to maintain
|
||||
|
||||
🔗 [**Read More: Use an LTS release of Node.js**](/sections/production/LTSrelease.md)
|
||||
|
||||
@ -668,19 +632,21 @@ All statements above will return false if used with `===`
|
||||
## Our contributors are working on this section. Would you like to join?
|
||||
|
||||
<br/><br/><br/>
|
||||
|
||||
# `Performance Practices`
|
||||
|
||||
## Our contributors are working on this section. Would you like to join?
|
||||
|
||||
|
||||
<br/><br/>
|
||||
<br/><br/><br/>
|
||||
|
||||
# Milestones
|
||||
To maintain this guide and keep it up to date, we are constantly updating and improving the guidelines and best practices with the help of the community. You can follow our [milestones](https://github.com/i0natan/nodebestpractices/milestones) and join the working groups if you want to contribute to this project.
|
||||
|
||||
To maintain this guide and keep it up to date, we are constantly updating and improving the guidelines and best practices with the help of the community. You can follow our [milestones](https://github.com/i0natan/nodebestpractices/milestones) and join the working groups if you want to contribute to this project
|
||||
|
||||
<br/><br/>
|
||||
|
||||
## Translations
|
||||
|
||||
All translations are contributed by the community. We will be happy to get any help with either completed, ongoing or new translations!
|
||||
|
||||
### Completed translations
|
||||
@ -696,28 +662,32 @@ All translations are contributed by the community. We will be happy to get any h
|
||||
*  [Spanish](https://github.com/i0natan/nodebestpractices/blob/spanish-translation/README.spanish.md) ([Discussion](https://github.com/i0natan/nodebestpractices/issues/95))
|
||||
*  Turkish ([Discussion](https://github.com/i0natan/nodebestpractices/issues/139))
|
||||
|
||||
<br/><br/>
|
||||
<br/><br/><br/>
|
||||
|
||||
# Contributors
|
||||
|
||||
## `Yoni Goldberg`
|
||||
|
||||
Independent Node.js consultant who works with customers in USA, Europe, and Israel on building large-scale scalable Node applications. Many of the best practices above were first published in his blog post at [http://www.goldbergyoni.com](http://www.goldbergyoni.com). Reach Yoni at @goldbergyoni or me@goldbergyoni.com
|
||||
|
||||
## `Ido Richter`
|
||||
👨💻 Software engineer, 🌐 web developer, 🤖 emojis enthusiast.
|
||||
|
||||
👨💻 Software engineer, 🌐 web developer, 🤖 emojis enthusiast
|
||||
|
||||
## `Refael Ackermann` [@refack](https://github.com/refack) <refack@gmail.com> (he/him)
|
||||
|
||||
Node.js Core Collaborator, been noding since 0.4, and have noded in multiple production sites. Founded `node4good` home of [`lodash-contrib`](https://github.com/node4good/lodash-contrib), [`formage`](https://github.com/node4good/formage), and [`asynctrace`](https://github.com/node4good/asynctrace).
|
||||
`refack` on freenode, Twitter, GitHub, GMail, and many other platforms. DMs are open, happy to help.
|
||||
`refack` on freenode, Twitter, GitHub, GMail, and many other platforms. DMs are open, happy to help
|
||||
|
||||
## `Bruno Scheufler`
|
||||
💻 full-stack web developer and Node.js enthusiast.
|
||||
|
||||
💻 full-stack web developer and Node.js enthusiast
|
||||
|
||||
<br/><br/>
|
||||
<br/><br/><br/>
|
||||
|
||||
# Thank You Notes
|
||||
|
||||
This repository is being kept up to date thanks to the help from the community. We appreciate any contribution, from a single word fix to a new best practice. Below is a list of everyone who contributed to this project. A 🌻 marks a successful pull request and a ⭐ marks an approved new best practice.
|
||||
This repository is being kept up to date thanks to the help from the community. We appreciate any contribution, from a single word fix to a new best practice. Below is a list of everyone who contributed to this project. A 🌻 marks a successful pull request and a ⭐ marks an approved new best practice
|
||||
|
||||
### Flowers <br/>
|
||||
|
||||
@ -761,6 +731,7 @@ This repository is being kept up to date thanks to the help from the community.
|
||||
🌻 [cwar](https://github.com/cwar)
|
||||
|
||||
### Stars <br/>
|
||||
|
||||
⭐ [Kyle Martin](https://github.com/js-kyle)
|
||||
|
||||
<br/><br/>
|
||||
<br/><br/><br/>
|
||||
|
||||
Reference in New Issue
Block a user