Node.js best practices for beginners and experts

Node JS

Node.js best practices for beginners and experts

Node.js is one of the most popular frameworks for web development. Being used by several companies, ranging from small projects to large solutions.
With it, you can create lightweight, scalable, fast, and robust server-side web applications by writing javascript code for the browser.

Today, we’re going to talk about some best practices for developing with Node.js that will help all types of developers build an efficient and more maintainable application, from beginners to the most experienced.

Restart the app on every change

At development time, the application stops and restarts with each change made to the code, this can be a nuisance and can cause loss of focus and productivity. To resolve this you can use tools that avoid restarting the application repeatedly to reflect changes. Below are some of the most popular code monitoring packages for Node.js: Nodemon: It offers an auto-restart feature whenever new code changes are made. To use nodemon, just replace node with nodemon. Forever: It also offers an auto-start feature along with additional configurations like writing logs and setting the working directory to a specific file. PM2: Another process management tool with excellent control and features compared to the previous two. Both Forever and PM2 can be used in the production environment. With them, it is possible to guarantee that the code is recovered after a runtime error and also guarantee a fast startup if the server goes down.

Replace callbacks with async

In the beginning, callbacks were used to create asynchronous methods in Node, but when nested continuously, they tended to get out of control. It is at this point where the code becomes unreadable. With the introduction of async/await, developers have noticed a lessening of this problem. However, to avoid callbacks, it is necessary to ensure the use of async/await. You can easily avoid this bad callback scenario by replacing it with async and await calls.

App Cluster

The Node runtime is limited to a single CPU core and deploying non-clustered Node apps on a huge server can be a waste of resources. Instead, choose to add cluster support to your app so you can take full advantage of multiple cores. With the support of a cluster, you get flexibility even if you are running a single process on small hardware.

Avoid Garbage

Node has a slow garbage collector with a default limit of 1.5GB. This garbage collector will wait until it actually has unused memory to reclaim. If you’re running out of memory, it’s not because of the leak, but because of the lazy behavior of the garbage collector. However, you can take full control over the garbage collector by providing flags for V8.

web: node — optimize_for_size — max_old_space_size=920 — gc_interval=100 server.js

Doing this is crucial, especially when you are running a node in an environment with less than 1.5Gb of memory.

web: node — optimize_for_size — max_old_space_size=460 — gc_interval=100 server.js

The code above can be used to customize the node for a 512MB container.

Clean Code

We already talked in a previous post about the benefits of clean code and how its adoption helps to improve code quality. To help this adoption, I will highlight how the use of IDEs together with plugins for semantic and style correction, helps the programmer at the time of coding. Along with Node, we can use a “Lint” plugin to look up and warn about semantic and syntactic error codes, while we can use a formatter that works with stylistic factors to ensure a set of formatting and styling is consistent across the project. We have some plugins that are quite famous like ESLint, JSLint, and JSHint that are accepted by most IDEs/code editors like Atom and VSCode that value code quality and offer formatting plugins. These IDEs offer additional features like refactoring, autocompletion, documentation support, automatic imports, debugging tools, code navigation, and more.

Dependency Injection

This software design advocate injecting or passing dependencies or services as parameters to modules, rather than creating them. This fancy term keeps your modules independent, flexible, scalable, and application-wide testable. With dependency injection, you can make your functions more generic and flexible. There are other practices besides dependency injection that have made your software better, for that, I recommend reading this article in which I talk about the principles of S.O.L.I.D. Below are some best practices that are recommended:

  • Do not repeat
  • Single Responsibility Principle
  • Keep it simple (Keep it simple)
  • Division of Concerns
  • Avoid early optimization
  • Dependency injection

Use secure, hierarchical, environment-aware configuration

Signs that a good failsafe setup includes: information that is secret is not committed to the code, a hierarchical pattern is followed by a setup that is easy to search, and keys are readable from environment variables. Keep an eye on the project settings to meet the DevOps team’s configuration requirements.

Design your Web Application with Helmet

Building web apps is a lot of fun. To make your coding even simpler, first, secure your app. Use:

  • XSS Protection
  • Set a Context-Security-Policy header
  • Make sure all connections are HTTPS
  • Avoid Clickingjacking using X-Frame-Options
  • Disable the X-Powered-By header so attackers cannot penetrate your attacks on specific software

If you find doing the above practices a little daunting, simply use the Helmet which will be set to the default, and you will be able to adjust the necessary ones.

Conclusion

No development is too hard or no language too easy until you find the best-recommended practices. I advise best practices on your backend project built in Node.js which are covered in this article.

I hope it helped you find the way to build robust, scalable, and flexible software.

Explore mais