May 14, 2022
Quick Summary: Whether you are a beginner or an experienced developer using Node JS, it is necessary to go along with the best practices of Node.js programming while developing applications. In this post, we are going to discuss 11 best practices every Node.js developer should follow in 2022.
Nodejs is a single-threaded, open-source JavaScript runtime environment for building scalable server-side and networking applications. It is popular among developers as a backend server for web applications.
Node js User Survey Report stated that almost 43% of Node.js developers have acknowledged using it for enterprise development. Nodejs is a perfect choice for making up-to-date solutions supported by micro-services, web sockets, and even queues.
To make it simple, Node JS can do sensations in a real-time web application. It is unquestionably easy to employ Node technology, but things could become unmanageable for you once you get beyond the basics.
So, each developer should be well prepared for knowing how to write the structured code and handle the challenges and errors throughout the app development process.
This blog will highlight the 11 Node JS best practices to keep in mind when starting with a new Node.js development project.
Each developer should desire to improve code quality and readability. Most code setup workflows always have a code linter and formatter. A linter warns you about incorrect code syntactically and semantically. In contrast, a code formatter styles the code in a more readable way by ensuring and implementing consistent formatting and styling guidelines across your whole project. Some of the most famous examples of linters for JavaScript are ESLint, JSLint and JSHint.
ESLint is the industry standard for checking and fixing possible code errors and styling issues. It can automatically set code styles, but other tools like prettier and beautify are also more potent in formatting the code and also work in conjunction with ESlint. Most IDEs/Code editors like VS code (Visual Studio Code), Atom, etc., have plugins for these linters and formatters.
A Node developer should pick an existing set of guidelines for coding and use it to maintain code readability throughout the project chain. One can also follow the Javascript coding style and standards used by tech giants like Google, Airbnb, etc.
These guides have standards for everything from naming conventions (for files, variables, classes, etc.) to formatting. These practices and standards used by some expert developers and companies in the world can help you write quality and clean code for your project.
The choice of coding standards and style is subjective for the developers. So, I advise you to analyze your competitors’ coding standards and style guides to get a better idea. Here is the list of style guides used by the global tech titans:
Airbnb # https://github.com/airbnb/javascript
Google # https://google.github.io/styleguide/javascriptguide.xml
jQuery # https://contribute.jquery.org/style-guide/js/
One of the Node js best practices is using naming conventions for all variables, classes, constants and functions you use in your code.
This practice will help you quickly identify plain variables/functions and classes requiring instantiation. Always use related descriptive names, but try to keep them short and meaningful.
// for class name we use UpperCamelCase class SomeClassExample {} // for constants names we use the const keyword and lowerCamelCase const config = { key: 'value' }; // for variables and functions names use lowerCamelCase let someVariableExample = 'value'; function doSomething() {}
Configuration management is a must in any programming language. One must realize the requirement of certain standard config options and settings to be manageable across all modules as application scales.
It is always best to save these options composed in a separate file inside a config folder in your project. This folder contains all your different configuration options grouped in files depending on their use.
/config ├── index.js ├── module1.js └── module2.js
Config folder example
These configuration options mainly have standard basic settings or secure API keys, URLs of database connections, etc.; the latter is supposed to be saved in .env files as environment variables. It is an example of a .env file that stores data in the form of key-value pairs.
DB_HOST=localhost DB_USER=root DB_PASS=my_password_abc
Example .env file
All these environment variables can be retrieved in your code using the dotenv package of npm.
// app.js require('dotenv').config() console.log(process.env.DB_HOST) console.log(process.env.DB_USER)
Accessing environment variables in your code
Prevalent development practice in Node.js is to use all these environment variables in config files and exposing them as an object to the rest of your app. This way, one would need to only make changes to common settings in a single folder to be reflected across the whole application. The snippet given below shows how this can be implemented.
// config/database.js require('dotenv').config() export default { host: process.env.DB_HOST, user: process.env.DB_USER, pass: process.env.DB_PASS, }
Exporting config object with env variables
So, one of the Node best practices is to create separate Node.js config files to manage config variables for different environments like development, staging, testing and production.
There are many ways to handle processes in Node JS or JavaScript. JavaScript programming language is known for callback functions. Callback functions allow you to define the asynchronous behavior in JavaScript. But if code has more and more callbacks, it gets bulkier, and it turns into a situation known as callback hell.
For asynchronous execution, many processes run simultaneously and are handled once the output of each method is available. There are different ways to manage asynchronous behavior in Node JS or JavaScript programming languages.
It is advisable to scrap the use of callback functions and use promises or async/await. They improve the code readability and also easier to look at the code flow and debug.
Below examples explain how the same code would look with callback functions vs async/await.
Function parentFunction( ) { innerFunction(“argument”, ( ) => { deepFunction(“newArgument” , ( ) => { deeperFunction(“Argus” , ( ) => { console.log(“executed”); } ) ; } ) ; } ) ; }
async function parentFunction( ) { await innerFunction(“argument”); await deepFunction(“newArgument”); await deeperFunction(“args”); Console.log (“executed”); }
Code with async/await syntax performs the same process as the callback function, but it is much easier for developers to read and debug.
According to the principle ‘Separation of concerns’, the server-side aspects are mainly divided into three parts. These features can be handled by programming three different layers:
Project can be logically modularized into three different layers. This three layered abstract architecture can be implemented through a proper folder structure that separates different modules into different folders.
Following folder structure allows developers to organize classes and methods into separate containers that are very easy to manage. The common folder structure given below can be used as a template when setting up a new Node.js development project.
src |── app.js app entry point |── /api controller layer: api routes |── /config config settings, env variables |── /services service layer: business logic |── /models data access layer: database models |── /scripts miscellaneous NPM scripts |── /subscribers async event handlers |── /test test suites
Here, the folders – /APIs (controller layer), /models (data access layers), and /services denote the three layers as discussed earlier. /Script directory used to store workflow automation scripts for deployment pipelines. /Config has all configuration files and /test will contain the test cases you write for the application.
Most developers follow the best practices to handle errors, but sometimes, unfortunately, some error from a dependency somehow brings down an app. And, periodically, developers need to stop and restart your app to apply even a simple change in the codebase.
Various different tools and technologies are available for professional developers to monitor an application’s codebase and automatically restart the app each time a change is made.
Some of the many code monitoring packages available for Node are
I would recommend using Keymetrics PM2 to manage your process. Here are the steps to use PM2.
1. Install it as a global module
$ npm install pm2 -g
2. Then, to launch your process, you should run:
$ pm2 start myApp.js
3. To handle restarting after the server crashes, you can follow the PM2 guide for your platform ( http://pm2.keymetrics.io/docs/usage/startup/ )
You need to get acquainted with JavaScript best practices for creating asynchronous programs, callbacks, function & objects, data types and function arguments.
Apart from that, you can get the assistance of Azure Functions or Azure app service to avail the benefit of serverless code infrastructure. This code infrastructure allows you to develop responsive and scalable HTTP endpoints.
Node Developers are primarily familiar with NPM as a way to install dependencies. npm init is much more than this. So, it is advisable to create a new project using npm init.
$ mkdir my-new-project $ cd my-new-project $ npm init
This option will create a new package.json file for you, allowing you to write a metadata cluster to help others working on the same project have the same setup as you.
For example, you can open the package.json and add a specific version of Nodejs that you plan to run on by adding:
"engines": { "node": "6.2.0" }
Testing is fundamental to any software application. Developers can do testing of their code to remove any bugs in the app. Writing unit tests will help keep your code simple and error free.
For any developer, having easy-to-read, simple, bug-free code in the first round of programming is an achievement. Thus it is of utmost importance to write tests that cover all edge cases, resulting in an application with minimum bugs.
Unit tests make the foundation of most testing setups for your app. Here, separate units or components are tested independently from the rest of the code to verify their correctness. It allows the tests to logically validate lower-levels in order to ensure that all internal components are working accurately. Here is an example of a straightforward basic unit test.
// example.test.js const assert = require('assert'); describe('Basic multiply test with test passed', () => { it("LENGTH OUTPUT SHOULD BE 0", function() { let todos = []; assert.strictEqual(todos.length, 0); }); it("OUTPUT SHOULD BE 4", function() { const multiplyByTwo = (value) => { return value * 2; }; assert.strictEqual(multiplyByTwo(2), 4); }); })
These Test cases will check whether unit components of your code are giving expected results or not. There are many testing frameworks available for Node.js developers to choose from. Some of the most popular testing frameworks are Mocha, Jest and Jasmine.
NodeJS has a large worldwide developer community. NPM or Node package manager is a feature-rich, well maintained and documented package with support for third party frameworks, libraries, and tools for different use cases you can imagine. It is very convenient for developers to utilize all these existing solutions in their projects and make the maximum use of their APIs.
Third-party libraries and tools reduce burdens and make things easy for developers. It is imperative to be competent and responsible for each package we import.
Every developer should be aware of a package’s import purpose, strengths, and weaknesses. But you also make sure that you, as a developer, are not over-reliant on them.
Below are some popular Node JS libraries that developers can use to improve the coding workflows:
One of the NodeJS best practices that developers should follow is keeping applications stateless.
Never store any information in your application itself. Store any information like user sessions, cache, user data in external data stores.
The primary goal is to keep the application stateless. One should be able to restart the server without affecting its services to the users. Another way of this practice is using a serverless platform like AWS Lambda that imposes stateless behavior by default.
Keeping servers stateless ensures that applications can survive any eventual system failure without disturbing and damaging their services and performance.
There are various aspects to intelligent web development. I have tried to present the best practices that cover everything from how to logically structure your project to the overview of formatting, linting, style guides to the nitty-gritty of writing asynchronous code.
So, these are the NodeJS practices that may come in handy to you while developing apps. With these best practices followed, we ensure that your app will turn out to be easily maintainable, scalable and extremely resilient to errors.
Not only a novice but even experienced developers can adopt best practices and hone their development skills. You can also achieve improved app performance by implementing these best practices or hiring our dedicated NodeJS developers to do it for you.