3 Final node.js design patterns that are misused
by December 15, 2015

Filed under: Industry Insights

AppNeta no longer blogs on DevOps topics like this one.

Feel free to enjoy it, and check out what we can do for monitoring end user experience of the apps you use to drive your business at www.appneta.com.

Today we finish off our series on the right way to code common node.js design patterns from node.js contributor and AppNeta engineer Stephen Belanger. You can also access the full posts for Part 1 and Part 2 or check out the direct links to the common patterns below. Thanks to Stephen for this series!

Common Patterns

Rounding out our list will be three more common design patterns that you might be misusing. You can click on any of the first 6 to check out posts related to those below.

  1. Callbacks
  2. Event Emitters
  3. Streams
  4. Singletons
  5. Constructors
  6. Middleware/Pipelining
  7. Promises
  8. Dependency Injection
  9. Factory Functions

Promises

With ES6 comes a new construct called a Promise. These are used to encapsulate a resolvable or rejectable behaviour that may be sync or async, but will not continue execution until a future iteration of the event loop, for consistency. The interface includes a `then` function, which takes several callbacks to receive the eventual value or error. You can also use the `catch` function to specifically assigning only an error handler.

The promise API is chainable, and each `then` or `catch` function produces a new promise representing the result of the previous handler. The handlers can also return more promises that will get resolved before the chain continues.

Here’s an example of how all this works:

function delay (n) {
  return new Promise(function (resolve, reject) {
    setTimeout(function () {
      resolve(n)
    }, n)
  })
}

var promise = delay(100)
  .then(function (n) {
    return delay(n)
  })
  .then(function (n) {
    console.log('this was delayed for ' + (n * 2) + 'ms')
  })

Dependency Injection

New users coming from more structure-heavy languages or platforms are often familiar with the concept of Dependency Injection, and tend to reach for it too often in node.js. While node.js *can* do it, it’s not generally needed, due to the flexibility of JavaScript. Sometimes, however, it can become a necessary tool to manage the complexity of a growing codebase. There are many different ways to manage dependency injection in node.js. Most are overly verbose or not very performant, but it can work well if you are careful about it.

The general idea of dependency injection is that segments of code can be modularized, but can depend on a specific set of other modules that the environment should provide somehow. Does this sound familiar? It should, because this is exactly what CommonJS does. Layering more dependency management over top of node.js can feel kind of redundant.

Sometimes you need more than a simple `require` call can provide though, and that is when dependency injection starts to really make sense. Consider, for example, a complicated hierarchy of connected code that needs to interact with each other. If you want to write tests for that code, you may need to mock the objects, but managing the connections between them may be very complicated. With dependency injection, it can be as easy as simply registering a mock object with the same name the real one would have used, leaving the rest of the code blissfully ignorant that it is not interacting with what it thinks it is.

The various implementations of DI in node.js vary wildly in how they work. Some parse a function as a string and use the argument names to identify what to look for, others use an $inject property on the function, and others yet use a sort of pattern matching on object keys for identity. All are valid approaches, but each needs to be carefully considered. Parsing a function as a string is expensive, so it shouldn’t be done in a hot code path. The $inject style requires some extra manual effort, but works well in most cases. Lastly, the pattern matching approach, while very flexible, can also be prone to edge cases.

Factory functions

Factory functions return instances of a constructor without the needing the `new` keyword. Often it is just a convenience, but it can be useful at times.

The most common use of factory functions in node.js core is `http.createServer`, which actually just calls `new http.Server`:

function hello (req, res) {
  res.send('hello')
}

// This...
var server = http.createServer(hello)

// is the same as...
var server = new http.Server(hello)

There’s not a huge benefit there, but it can have advantages in more complex hierarchies. Consider a connection instance and an interface for interacting with a specific database:

function Database (connection, name) {
  // Here, the database interface can store the
  // connection instance and use it later
}
Connection.prototype.database = function (name) {
  return new Database(this, name)
}

// This...
var database = connection.database('test')

// is a little friendlier than this...
var database = new Database(connection, 'test')

Conclusion

I hope you’ve enjoyed this series and find it useful. While node.js can be tricky, but it can also be fast if done correctly. Utilizing design patterns the right way is one key to getting excellent performance from node.js. Please feel free to reach out to me on GitHub at https://github.com/Qard if you have any questions, comments or just want to say hello!