3 More common node.js design patterns that are misused
by December 8, 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.

Part 2 of a 3 part series

Today we continue with our new series on the right way to code common node.js design patterns from node.js contributor and AppNeta engineer Stephen Belanger. You can access Part 1 here.

Common Patterns

Last time I went over Callbacks, Event Emitters, and Streams. While these are all core patterns in node.js, there are a lot more to mention. This week we’ll look at 3 more design patterns that will help you utilize objects in node.js.

  1. Callbacks
  2. Event Emitters
  3. Streams
  4. Singletons
  5. Constructors
  6. Middleware/Pipelining

 

Singletons

A singleton is a single instance of an object. A basic singleton in JavaScript might look something like this:

var linesSingleton = {
  content: '',
  push: function (line) {
    this.content += line + '\n'
  },
  forEach: function (fn) {
    this.content.split('\n').forEach(fn)
  }
}

They are also sometimes constructed as closures, when one wants to prevent access to private data:

var linesSingleton = (function () {
  var content = ''
  return {
    push: function (line) {
      content += line + '\n'
    },
    forEach: function (fn) {
      content.split('\n').forEach(fn)
    }
  }
})()

In some cases, the simplicity of singletons simplifies your code, however it’s not a very common pattern in node.js. Because a node.js process is long-lived and will serve many requests throughout its lifetime, unique objects are generally needed for each request to interact with.

The module system in node.js, called CommonJS, is actually singleton-based. Its content is controlled via the `module` and `exports` objects inside the JavaScript file. Putting the above code into a module would look like this:

var content = ''
module.exports = {
  push: function (line) {
   content += line + '\n'
  },
  forEach: function (fn) {
   content.split('\n').forEach(fn)
  }
}

Constructors

Constructors are very useful for creating an object type that can be instantiated uniquely, many times. This is very important when you need to use an object type many times across many separate requests. A constructor is simply a function which includes a `prototype` and is called with the `new` keyword.

function Person (name) {
  this.name = name
}
Person.prototype.greet = function () {
  return 'Hello, I am ' + this.name + '.'
}

Alternatively, that could have been written something like this:

function makePerson (name) {
  return {
    greet: function () {
      return 'Hello, I am ' + name + '.'
    }
  }
}

Note that not using constructors can have some serious performance penalties. The JavaScript virtual machines are optimized to identify and compile prototype functions at the time the definition runs rather than when the individual call runs, so using prototype functions can substantially reduce load on the virtual machine.

Middleware / Pipelining

The middleware approach, also sometimes called pipelining, is similar to what streams do when using `pipe`, but is generally used to build a flow of transformations on something that is not an event emitter.

The most notable example of middleware usage in the node.js ecosystem is the express framework, or more accurately the connect framework it originated from. It implements a `use` function to attach handlers which do transformations on the request and response objects of an http request. The interface looks something like this:

var app = connect()
app.use(function (req, res, next) {
  req.name = 'World'
  next()
})
app.use(function (req, res) {
  res.send('Hello, ' + req.name)
})
http.createServer(app).listen(3000)

If the `next` function is not called, the flow stops at that handler.

Next week we’ll finish up these series with the last 3 more common patterns and how not to misuse them!