small medium large xlarge

Decouple Your Apps with Event-Driven CoffeeScript

How Event-Driven CoffeeScript Can Save You from Dependency Hell

by Trevor Burnham

Generic image illustrating the article
  Trevor shows how to make Node applications as cleanly organized as those in any other runtime environment.  

Unit testing is a pain.

Well-tested code is great. That’s what I tell everyone. Who doesn’t? But more often than not, I just don’t wanna do it on my own projects. That’s partly because most functionality is hard to test in isolation. Unless you’re writing a calculator, your application contains a lot of units that each depend on several other units: Your game’s monster unit invokes sound and video components when struck by a bullet; your bug tracker’s issue unit summons email and RSS when a reply is added; and just about every file in a typical Node.js web app could well start with:

 db = require 'db'
 logger = require 'logger'
 markup = require 'markup'

And so on. Node’s modularity is both a blessing and a curse. While frameworks like Rails make just about every piece of code accessible from everywhere else, Node forces you to make your dependencies explicit. That’s great when you have only a handful of moving parts, but when you have hundreds, it’s a nightmare. And how can anything be tested in isolation when so many dependencies are required?

Fortunately, there’s a way to simplify your application’s structure without simply making everything global: instead of having units communicate through function calls, have them emit events.

Emissions As Transmissions

Node.js is said to be event-driven because it has no threads. Instead, every time a script has finished running, Node checks if any events have been queued (via a method like setTimeout or readFile), and then runs one of the queued functions. The result is often more efficient and less bug-prone code than in other languages where several pieces of code are run “simultaneously” via threading.

But the word “event” has another meaning in Node.js in the form of the EventEmitter API (Full documentation available here.) An EventEmitter can “emit” any kind of event (identified by a string), and when it does, all matching “listeners” (callbacks) are immediately triggered. (If you’re familiar with jQuery or Backbone.js, think of emit as trigger and addListener/on as bind.) EventEmitter is a “class” in the JavaScript sense of being a function with a prototype object attached. That means that you can create EventEmitter instances:

 {EventEmitter} = require 'events'
 emitter = new EventEmitter
 emitter.on 'foo', -> console.log 'bar'
 emitter.emit 'foo' # bar

Or you can make your own EventEmitter subclasses:

 {EventEmitter} = require 'events'
 class Rooster extends EventEmitter
  constructor: ->
  @on 'wake', -> console.log 'COCKADOODLEDOO!'
 (foghorn = new Rooster).emit 'wake' # COCKADOODLEDOO!

Or you can “mix in” EventEmitter’s prototype to add its functionality to an existing object:

 sprinkler = waterSupply: 2
 sprinkler[k] = func for k, func of EventEmitter.prototype
 sprinkler.on 'fire', ->
  if @waterSupply > 0
  @waterSupply--; console.log 'fire extinguished'
  console.log 'good luck...'
 sprinkler.emit 'fire' # fire extinguished
 sprinkler.emit 'fire' # fire extinguished
 sprinkler.emit 'fire' # good luck...

Notice that while emit sounds like something that an object does on its own, the method is public and can be called from anywhere. This is key—anything you can do with a function call, you can do by emitting an event instead. (OK, so events can’t return a value, but this is JavaScript; use a callback!) You can pass arguments after the event name:

 cave = new EventEmitter
 cave.on 'echo', -> console.log x for x in arguments
 cave.emit 'echo', 'Hello?' # Hello?

But what makes the events even more powerful than ordinary function calls is that you can “stack” multiple listeners on the same event. The listeners are triggered in the same order they were attached in:

 codeMonkey = new EventEmitter
 codeMonkey.on 'wake', -> console.log 'get up, get coffee'
 codeMonkey.on 'wake', -> console.log 'go to job'
 codeMonkey.on 'wake', -> console.log 'have meeting'
 codeMonkey.emit 'wake' # get up, get coffee; go to job; have meeting

Inverting Dependencies

So, how can event-driven code save us from dependency hell? Let’s go back to that monster example from the start of the article. We want it to do a bunch of things when it gets hit. A straightforward approach would be to write code like this:

 class Monster
  constructor: -> @hp = 1000
  hit: (damage) ->
  @hp -= damage
  if @hp > 0 'monster_hit' 'monster_hit'
  player.score += 5
  else 'monster_die' 'monster_die'
  player.score += 100
  world.remove this

But look at all the dependencies we have here: audio, video, player, world... That leads to two problems: one is that we have to get references to those objects from every single Monster-like module, leading to lots of code duplication. The other is, how do we test Monster::hit? Surely we don’t want a bunch of monster noises to erupt every time we run our game’s suite of unit tests!

One common approach would be dependency injection, providing some way for Monster to get mock instances of audio and video that have the same properties as the real instances but none of the side effects. Another would be to take advantage of JavaScript’s dynamic nature by directly manipulating the prototypes of objects like audio and video, rendering them inert in test mode. A third would be to special-case those calls with a conditional, something like unless testMode. Of course, none of these workarounds help with the code duplication that comes from explicitly spelling out all dependencies.

What if, instead, we use an event to separate our internal logic code from everything else?

 class Monster extends EventEmitter
  constructor: -> @hp = 1000
  hit: (damage) ->
  @hp -= damage
  if @hp > 0
  @emit 'hit'
  @emit 'die'

Now all we have to do is listen for that event somewhere. Let’s say that the world object is responsible for spawning monsters, and when it does, it emits a new_monster event with the new Monster as an argument. Then in the audio object, we can add:

 world.on 'new_monster', (monster) =>
  monster.on 'hit', => @play 'monster_hit'
  monster.on 'die', => @play 'monster_die'

The video code would look much the same. And the player code would look like:

 world.on 'new_monster', (monster) =>
  monster.on 'hit', => @score += 5
  monster.on 'die', => @score += 100

In many ways, this way of organizing code is more logical. It allows the Monster class to stay more “pure.” To unit test it, all we have to do is create it without emitting the usual new_monster event. And check out how much nicer our dependency graph has become!


Imagine No Dependencies

A lot of Node developers will tell you that attaching things to global rather than exports is a no-no. And if you’re packaging your code as a library, or trying to make your code reusable, then they’re right. But if you’re developing a standalone application, then go ahead and let yourself declare a few globals. In particular, if you’re using the pattern described in the last section, try adding this to your main application file: = world

Not only is this one line worth a thousand world = require 'world's, but it also makes the world dependency soft and easy to replace. At the top of your application’s tests, you could put this: = {
  eventListeners: {}
  emitCounts: {}
  on: (event, func) -> (@eventListeners[event] ?= []).push func
  emit: (event) -> @emitCounts[event] ?= 0; @emitCounts[event]++

Now none of the listeners attached to world will ever actually be fired, and you can easily run assertions on how many listeners are attached for a given event and how many times that event has occurred.

Alternatively, you can take the lighter tack of simply adding additional listeners for testing and selectively using EventEmitter::removeListener to halt those persistent monster screeches during unit testing. You might take advantage of the once method for your assertions, which acts just like on except one-time-only:

 nasa = new EventEmitter
 nasa.once 'land_on_moon', -> console.log 'Wow!'
 nasa.emit 'land_on_moon' # Wow!
 nasa.emit 'land_on_moon' # (silence)

Conclusion: Making the Most of Modules

Despite Node’s reputation for complexity, I’d argue that it’s possible to make Node applications as cleanly organized as those in any other runtime environment. The event paradigm provides an elegant way of connecting objects, providing maximum flexibility and minimum boilerplate. It’s test-friendly, and encourages application code to be split up more by categories of functionality and less by imperative order. There’s nothing else quite like it.

JavaScript has become the world’s most important language. And I, for one, welcome our new event-driven overlords.

Trevor Burnham is the author of CoffeeScript: Accelerated JavaScript Development, new in print from The Pragmatic Bookshelf. As a proponent of beautiful code, he runs @CoffeeScript on Twitter and spoke at RailsConf 2011. As a freelancer, he's available to work on exceptionally interesting projects. He lives in Cambridge, MA.

Send the author your feedback or discuss the article in the magazine forum.