Tuesday, 10 January, 2017 UTC


Summary

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.
Storify was an interesting job for me, because unlike many other companies, Storify ran (and maybe still does) everything on JavaScript. You see, most companies, especially large ones such as PayPal, Walmart, or Capital One, only use Node for certain parts of their stack. Usually they use it as an API gateway or an orchestration layer. That's great. But for a software engineer, nothing compares with full immersion into a Node environment.
In this post I'll outline ten tips to help you become a better Node developer in 2017. These tips come from me, who saw and learned them in the trenches, as well as people who have written the most popular Node and npm modules. Here's what we'll be covering:
  1. Avoid complexity — Organize your code into the smallest chunks possible until they look too small and then make them even smaller.
  2. Use asynchronous code — Avoid synchronous code like the plague.
  3. Avoid blocking require — Put ALL your require statements at the top of the file because they are synchronous and will block the execution.
  4. Know that require is cached — This could be a feature or a bug in your code.
  5. Always check for errors — Errors are not footballs. Never throw errors and never skip the error check.
  6. 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.
  7. Return callbacks or use if ... else — Just to be sure, return a callback to prevent execution from continuing.
  8. 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.
  9. Know your npm — Install modules with -S or -D instead of --save or --save-dev
  10. 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.
  11. 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 let's bisect and take a look at each one of them individually. Shall we?
Avoid Complexity
Take a look at some of the modules written by Isaac Z. Schlueter, the creator of npm. For example, use-strict enforces JavaScript strict mode for modules, and it's just three lines of code:
var module = require('module')
module.wrapper[0] += '"use strict";'
Object.freeze(module.wrap)
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.
By keeping your code modularized into smaller parts, you and other developers can understand and reason about it better. You can also test it better. Consider this example,
app.use(function(req, res, next) {
  if (req.session.admin === true) return next()
  else return next(new Error('Not authorized'))
}, function(req, res, next) {
  req.db = db
  next()
})
Or this code:
const auth = require('./middleware/auth.js')
const db = require('./middleware/db.js')(db)

app.use(auth, db)
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).
Use Asynchronous Code
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.
For example, this might be okay if we are just building a database script, and not a system to handle parallel/concurrent tasks:
let data = fs.readFileSync('./acconts.json')
db.collection('accounts').insert(data, (results))=>{
  fs.writeFileSync('./accountIDs.json', results, ()=>{process.exit(1)})
})
But this would be better when building a web app:
app.use('/seed/:name', (req, res) => {
  let data = fs.readFile(`./${req.params.name}.json`, ()=>{
    db.collection(req.params.name).insert(data, (results))=>{
      fs.writeFile(`./${req.params.name}IDs.json`, results, ()={res.status(201).send()})
    })
  })
})
The difference is whether you are writing concurrent (typically long running) or non-concurrent (short running) systems. As a rule of thumb, always write async code in Node.
Continue reading %10 Tips to Become a Better Node Developer in 2017%