Node - Js Coding Standards
Node - Js Coding Standards
Document Summary
This document describes the Coding Standards and Guidelines that should be used in Airline control
systems.
1. Introduction .............................................................................................................................................................................. 3
1.1 Background ........................................................................................................................................................................ 3
1.2 Intended Audience .............................................................................................................................................................. 3
1.3 Scope of the document ....................................................................................................................................................... 3
1.4 Terminology ....................................................................................................................................................................... 3
1.5 Cautions .............................................................................................................................................................................. 4
2. Node.js projects ........................................................................................................................................................................ 4
2.1 Npm init .......................................................................................................................................................................... 4
2.2 Setup .npmrc............................................................................................................................................................................ 4
2.3 Add scripts to your package.json............................................................................................................................................. 5
2.4 Use environment variables ...................................................................................................................................................... 6
2.5 Use a style guide...................................................................................................................................................................... 6
2.6 Embrace async ......................................................................................................................................................................... 7
2.7 Handle errors ........................................................................................................................................................................... 7
2.8 Ensure your app automatically restarts .................................................................................................................................... 8
2.9 Cluster your app to improve performance and reliability ........................................................................................................ 8
2.10 Require all your dependencies up front ................................................................................................................................. 9
2.11 Use a logging library to increase errors visibility .................................................................................................................. 9
2.12 Use Helmet if you’re writing a web app .............................................................................................................................. 10
2.13 Monitor your applications ................................................................................................................................................... 10
2.14 Test your code ..................................................................................................................................................................... 11
3. Node.js Coding Standards as per NPM recommendation (for projects other than EK.com) .................................................. 12
3.1 Description ..................................................................................................................................................................... 12
3.2 Line Length .................................................................................................................................................................... 12
3.3 Indentation ..................................................................................................................................................................... 12
3.4 Curly braces ................................................................................................................................................................... 12
3.5 Semicolons ..................................................................................................................................................................... 13
3.6 Comma First .................................................................................................................................................................. 13
3.7 Quotes ............................................................................................................................................................................ 14
3.8 Whitespace ..................................................................................................................................................................... 14
3.9 Functions........................................................................................................................................................................ 14
3.10 Callbacks, Sync/async Style .......................................................................................................................................... 14
3.11 Errors ............................................................................................................................................................................. 15
3.12 Logging .......................................................................................................................................................................... 15
3.13 Case, naming, etc. .......................................................................................................................................................... 15
3.14 null, undefined, false, 0 .................................................................................................................................................. 15
4. Node.js Structure .................................................................................................................................................................... 16
4.1 An Example ................................................................................................................................................................... 16
5. The conclusion ........................................................................................................................................................................ 17
Node.js Coding Standards Emirates Group Internal & Vendors Page 2 of 19
1. Introduction
It sure is easy to get started on those Node.js projects, but once you get beyond the basic Hello
World app, knowing how to best structure your code and how to deal with errors can sometimes
become a nightmare (as with most languages and frameworks). And unfortunately, that nightmare
makes all the difference between a rock solid production application and a launch disaster.
With that said, let's take a look at a few best Node.js practices that will keep you safe from the most
common Node.js traps.
1.1 Background
This document provides standards to which Node.js should be written and maintained. Close
adherence to the rules will help the consultants other than the author to understand a piece of
code.
The aim is to ensure that code is
There is also a need to achieve these aims without unduly restricting the software
consultants' creativity or unnecessarily increasing the quantity of work beyond that merited
by the project/product.
1.4 Terminology
Where recommendations are made that represents the position of this document the verb
should is used and where alternate approaches are provided and no firm recommendations
are made, the verb may is used. Where firm recommendations are made the word must is
used
1.5 Cautions
The recommended standards and guidelines do not prohibit special considerations for
other systems, application specific requirements and hardware constraints
Examples are incorporated in this document to enhance clarity and promote understanding.
Examples should not be considered as the recommended implementations
2. Node.js projects
Most people are familiar with NPM as a way to install dependencies, but it is so much more than
this. First, I highly recommend creating a new project using npm init, like so:
$ mkdir my-new-project
$ cd my-new-project
$ npm init
This will create a new package.json for you which allows you to add a bunch of metadata to
help others working on the project have the same setup as you.
For example, I usually open the package.json and add a specific version of Node.js
"engines": {
"node": "8.11.3"
}
Simply add a scripts property and object to your package.json with a start key. Its value
should be the command to launch your app.
For example:
"scripts": {
"start": "node myapp.js"
}
As soon as someone runs npm start, NPM will run node myapp.js with all the
dependencies from node_modules/.bin on your $PATH. This means you can avoid having to
do global installs of NPM modules.
The postinstall script is run after npm install is run. There’s also preinstall if you
need to run something before all the NPM dependencies are installed.
The test script is run when someone runs npm test. This is a nice simple way for someone to
be able to run your tests without figuring out if you’ve chosen to use Jasmine, Mocha, Selenium,
etc.
You can add your own custom scripts here, too. They can then be run using npm run-script
{name} - a simple way for you to give your team a central set of launch scripts.
The recommended way in Node.js is to use environment variables and to look up the values
from process.env in your code.
For example, to figure out which environment you’re running on, check
the NODE_ENV environment variables:
console.log("Running in :" + process.env.NODE_ENV);
This is now a standard variable name used across most cloud-hosting vendors.
The problem here is a mixture of opinionated developers and no team/company standard style
guide.
It’s far easier to understand code on a codebase if it’s all written in a consistent style. It also
reduces the cognitive overhead of whether you should be writing with tabs or spaces. If the style is
dictated (and enforced using JSHint, ESlint or JSCS) then all of sudden, the codebase becomes a lot
more manageable.
You don’t have to come out with your own rules either, sometimes it’s better to pick an existing set
of guidelines and follow them.
We follow Airbnb JS Style Guide and developers should ensure they adhere to the standards using
ESLint
The problem with synchronous functions in JavaScript is that they block any other code from
running until they complete. However, synchronous code makes the flow of your application logic
easy to understand. On the other hand, async structures like promises actually bring back a lot of
that reasoning while keeping your code free from blockages.
So first, I highly recommend running your app (during development only) with the --trace-
sync-io flag. This will print a warning and stack trace whenever your application uses a
synchronous API.
There are plenty of great articles about how to use promises, generators and async / await.
I don't need to duplicate other great work that's already available, so here’s a few links to get you
started:
Promises - http://www.html5rocks.com/en/tutorials/es6/promises/
Async / Await - https://javascript.info/async-await
Generators
- https://developer.mozilla.org/en/docs/Web/JavaScript/Guide/Iterators_and_Gener
ators
Let’s say you have a chain of promises, and any one of which could suddenly fail, you can easily
handle the error like so:
doSomething()
.then(doNextStage)
.then(recordTheWorkSoFar)
.then(updateAnyInterestedParties)
.then(tidyUp)
.catch(errorHandler);
In the example above, it doesn’t matter which of the earlier functions could have failed, any error
will end up in the errorHandler.
Node.js Coding Standards Emirates Group Internal & Vendors Page 7 of 19
2.8 Ensure your app automatically restarts
Okay, so you followed the best practice to handle errors. Unfortunately, some error from a
dependency still, somehow, brought down your app
This is where it’s important to ensure you use a process manager to make sure the app recovers
gracefully from a runtime error. The other scenario where you need it to restart is if the entire
server you’re running on went down. In that situation, you want minimal downtime and for you
application to restart as soon as the server is alive again!
I’d recommend using KeyMetric’s PM2 http://pm2.keymetrics.io/ to manage your process.
Though other options include (Nodemon)[http://nodemon.io/] and (Forever)
[https://github.com/foreverjs/forever].
To start up multiple instances of your app for each core on a machine, you’d simply run:
$ pm2 start myApp.js -i max
One thing to bear in mind is that each process is standalone — they don’t share memory, or
resources. Each process will open its own connections to databases,
For example. Always keep that in mind as you code. A useful tool people use to share session state,
for example, is Redis, this provides an in-memory datastore that can be quickly accessed by all the
processes to store session related data.
datastore.get(req.query.someKey)
// etc, ...
});
The problem with the code above is that when someone makes a request to /my-service, the
code will now load all files required by myDataStoreDep - any of which could throw an
exception.
Additionally, when the configuration is passed on, there could also be an error at that point which
can bring down the entire process. In addition, we don’t know how long that synchronous setup of
a resource will take. At this point in the code, we essentially block all other requests from being
handled!
So you should always load all your dependencies upfront and configure them upfront. That way,
you'll know from the start up if there is a problem, not three to four hours after your app has gone
live in production!
A mature logging library can help with this. First, they allow you to set levels for each log
message - whether it’s a debug, info, warning, or error.
In addition, they typically allow you to log to different files or even remote data store.
For example,
You can use Loggy [https://www.loggly.com/] or
Kibana [https://www.elastic.co/products/kibana].
It allows to quickly search all log messages using patterns. In addition, it can alert if a threshold is
reached - for example, if a web application starts returning 500 SERVER ERROR messages to the
users for a period longer than 30 seconds, it can send a message and now you can figure out what’s
going on.
Instead of remembering to configure all these headers, Helmet will set them all to sensible defaults
for you, and allow you to tweak the ones that you need.
We already discussed in Chapter (2.8), PM2 for process management. In addition it’s
developers KeyMetrics.io run a process monitoring SaaS with integration with PM2 baked in. It’s
very simple to enable and they have a free plan which is a great starting point for a lot of
developers. Once you’ve signed up for KeyMetrics, you can simply run:
$ pm2 interact [public_key] [private_key] [machine_name]
This will start sending memory & CPU usage data, plus exception reporting to key metrics servers
to view from their dashboard. You can also view latency of your http requests, or set up events
when problems occur (for example timeouts to downstream dependencies).
No matter what stage you are on a project, it’s never too late to introduce testing. My advice is start
small, start simple. I’d also highly recommend writing a test for every bug that gets reported. That
way you know:
How to reproduce the bug (make sure your test fails first!)
That the bug is fixed (make sure you test passes after you fix the issue)
That the bug will never occur again (make sure you run your tests on every new
deployment)
We use Jest as the Unit Testing framework. Developers should make sure unit test cases are written
for all the new components that are created or update test cases whenever an existing component is
enhanced/modified. Test cases coverage should be more than 80%.
3.1 Description
Node.js coding style is a bit unconventional. It is not different for difference's sake, but rather a
carefully crafted style that is designed to reduce visual clutter and make bugs more apparent.
Best is to follow npm's style coding. So, in future it will be easy to contribute to npm.
Keep lines shorter than 80 characters. It's better for lines to be too short than to be too long. Break up
long lists, objects, and other statements onto multiple lines.
3.3 Indentation
Two-spaces. Tabs are better, but they look like hell in web browsers (and on GitHub), and node uses
2 spaces, so that's that.
Curly braces belong on the same line as the thing that necessitates them.
Bad:
function ()
{
Good:
function () {
If a block needs to wrap to the next line, use a curly brace. Don't use it if it doesn't.
Bad:
if (foo) { bar() }
while (foo)
bar()
3.5 Semicolons
Don't use them except in four situations:
A. for (;;) loops. They're actually required.
B. null loops like: while (something) ; (But you'd better have a good reason for doing that.)
C. case 'foo': doSomething(); break
D. In front of a leading ( or [ at the start of the line. This prevents the expression from being
interpreted as a function call or property access, respectively.
Note that starting lines with - and + also should be prefixed with a semicolon, but this is much less
common.
If there is a list of things separated by commas, and it wraps across multiple lines, put the comma at
the start of the next line, directly below the token that starts the list. Put the final token in the list on a
line by itself.
3.7 Quotes
Use single quotes for strings except to avoid escaping.
Bad:
var notOk = "Just double quotes"
Good:
var ok = 'String contains "double" quotes'
var alsoOk = "String contains 'single' quotes or apostrophe"
3.8 Whitespace
Put a single space in front of ( for anything other than a function call. Also use a single space
wherever it makes things more readable.
Don't leave trailing whitespace at the end of lines. Don't indent empty lines. Don't use more spaces
than are helpful.
3.9 Functions
Use named functions. They make stack traces a lot easier to read.
Use the asynchronous/non-blocking versions of things as much as possible. It might make more sense
for node.js to use the synchronous fs APIs, but this way, the fs and http and child process stuff all
uses the same callback-passing methodology.
Be very careful never to ever ever throw anything. It's worse than useless. Just send the error message
back as the first argument to the callback.
3.11 Errors
Always create a new Error object with your message. Don't just return a string message to the
callback. Stack traces are handy.
3.12 Logging
Please clean up logs when they are no longer helpful. In particular, logging the same object over and
over again is not helpful. Logs should report what's happening so that it's easier to track down where
a fault occurs.
Use appropriate log levels.
Use lowerCamelCase for multiword identifiers when they refer to objects, functions, methods,
properties, or anything not specified in this section.
Use UpperCamelCase for class names (things that you'd pass to "new").
Use all-lower-hyphen-css-case for multiword filenames and config keys.
Use named functions. They make stack traces easier to follow.
Use CAPS_SNAKE_CASE for constants, things that should never change and are rarely used.
Use a single uppercase letter for function names where the function would normally be anonymous,
but needs to call itself recursively. It makes it clear that it's a "throwaway" function.
Boolean variables and functions should always be either true or false. Don't set it to 0 unless it's
supposed to be a number.
When something is intentionally missing or removed, set it to null.
Don't set things to undefined. Reserve that value to mean "not yet set to anything."
Node.js is not a framework like Rails or .Net. Only the experience working in different projects will let
anyone define the best structure for every situation.
4.1 An Example
For Example Below structure can be used:
.
├── config # App configuration files
│ ├── sequalize.json # Sequalize config
│ ├── serviceOne.json # ServiceOne config
│ └── ... # Other configurations
├── routes
│ ├── controllers # Request managers
│ ├── middlewares # Request middlewares
│ └── routes.js # Define routes and middlewares here
├── services # External services implementation
│ ├── serviceOne
│ └── serviceTwo
│ └── ... # Other services
├── db # Data access stuff (Sequalize mostly)
│ ├── models # Models
│ ├── migrations # Migrations
│ ├── seeds # Seeds
│ └── index.js # Sequalize instantiation
├── core # Business logic implementation
│ ├── accounts.js
│ ├── sales.js
│ ├── comments.js
│ └── ... # Other business logic implementations
├── utils # Util libs (formats, validation, etc)
├── tests # Testing
├── scripts # Standalone scripts for dev uses
├── pm2.js # pm2 init
├── shipitfile.js # deployment automation file
├── package.json
├── README.md
└── app.js # App starting point
This folder structure follows the idea of making things simple. Don’t over engineer things, keep it
simple! Maybe the project is simpler than what we are using as an example here, so go on and make it
lighter.
But what if the project gets bigger? You can modularize the structure grouping your core files into
subfolders that represent different components of your application (like Users, Administration,
Statistics, etc.).
Other way to modularize it is to create different projects and deploy each one as a different process or
service, so you can have multiple independent projects (this is called Microservices).
And remember, when creating project structures, just pick the easiest thing that you could make and do
it! Don’t over engineer it and just do it!
6. Additional references
Additional reference can be found on the below link which has the Node.js documentations
https://nodejs.org/en/docs/
https://nodejs.org/en/docs/guides/
https://www.codementor.io