I started working with Node full-time in 2012 when I joined Storify. Since then, I have never looked back or felt that I missed Python, Ruby, Java or PHP — languages with which I had worked during my previous decade of web development.
Avoid complexity — Organize your code into the smallest chunks possible until they look too small and then make them even smaller.
Use asynchronous code — Avoid synchronous code like the plague.
Avoid blocking require — Put ALL your require statements at the top of the file because they are synchronous and will block the execution.
Know that require is cached — This could be a feature or a bug in your code.
Always check for errors — Errors are not footballs. Never throw errors and never skip the error check.
Use try…catch only in sync code — try...catch is useless for async code, plus V8 can’t optimize code in try...catch as well as plain code.
Return callbacks or use if … else — Just to be sure, return a callback to prevent execution from continuing.
Listen to the error events — Almost all Node classes/objects extend the event emitter (observer pattern) and emit the error event. Be sure to listen to that.
Use exact versions in package.json: npm stupidly adds a caret by default when you use -S, so get rid of them manually to lock the versions. Never trust semver in your apps, but do so in open-source modules.
Bonus — Use different dependencies. Put things your project needs only in development in devDependencies and then use npm i --production. The more un-required dependencies you have, the greater the risk of vulnerability.
So why avoid complexity? A famous phrase which originated in the US Navy according to one of the legends proclaims: KEEP IT SIMPLE STUPID (or is it “Keep it simple, stupid”?). That’s for a reason. The human brain can hold only five to seven items in its working memory at any one time. This is just a fact.
I’m sure most of you will prefer the second example, especially when the names are self-explanatory. Of course, when you write the code you might think that you understand how it works. Maybe you even want to show off how smart you are by chaining several methods together in one line. Please, code for the dumber version of you. Code for the you who hasn’t looked at this code for six months, or a tried or drunk version of you. If you write code at the peak of your mental capacity, then it will be harder for you to understand it later, not to even mention your colleagues who are not even familiar with the intricacies of the algorithm. Keeping things simple is especially true for Node which uses the asynchronous way.
And yes, there was the left-pad incident but that only affected projects dependent on the public registry and the replacement was published in 11 minutes. The benefits of going small far outweigh the downsides. Also, npm has changed its unpublish policy, and any serious project should be using a caching strategy or a private registry (as a temporary solution).
Synchronous code does have a (small) place in Node. It’s mostly for writing CLI commands or other scripts not related to web apps. Node developers mostly build web apps, hence they use async code to avoid blocking threads.
Node has a simple module loading system which uses the CommonJS module format. Its built-in require function is an easy way to include modules that exist in separate files. Unlike AMD/requirejs, the Node/CommonJS way of module loading is synchronous. The way require works is: you import what was exported in a module, or a file.
Knowing that some code might run only once, you can use this feature to your advantage.
Node is not Java. In Java, you throw errors because most of the time if there’s an error you don’t want the application to continue. In Java, you can handle multiple errors at a higher levels with a single try...catch.
If we cannot wrap the request call in a try...catch block, that leaves us with errors coming from request unhandled. Node developers solve this by providing you with error as a callback argument. Thus, you need to always manually handle the error in each and every callback. You do so by checking for an error (make sure it’s not null) and then either displaying the error message to the user or a client and logging it, or passing it back up the call stack by calling the callback with error (if you have the callback and another function up the call stack).
A little trick you can use is the okay library. You can apply it like this to avoid manual error check on myriads of nested callbacks (Hello, callback hell).
Almost all Node classes/objects extend the event emitter (observer pattern) and emit the error event. This is an opportunity for developers to catch those pesky errors and handle them before they wreak havoc.
Many Node and event front-end developers know that there is --save (for npm install) which will not only install a module but create an entry in package.json with the version of the module. Well, there’s also --save-dev, for devDependencies (stuff you don’t need in production). But did you know you can just use -S and -D instead of --saveand --save-dev? Yes, you can.
And while you’re in the module installation mode, go ahead and remove those ^ signs which -S and -D will create for you. They are dangerous because they’ll allow npm install (or its shortcut npm i) to pull the latest minor (second digit in the semantic versioning) version from npm. For example, v6.1.0 to v6.2.0 is a minor release.
npm team believes in semver, but you should not. What I mean is that they put caret ^ because they trust open source developers to not introduce breaking changes in minor releases. No one sane should trust it. Lock your versions. Even better, use shrinkwrap: npm shrinkwrap which will create a new file with exact versions of dependencies of dependencies.
This post was part one of two. We’ve already covered a lot of ground, from working with callbacks and asynchronous code, to checking for errors and locking down dependencies. I hope you’ve found something new or useful here. Stay tuned for part two coming soon.
10 Tips to Become a Better Node Developer in 2017 is by Azat Mardan.