Evented programming patterns: Round-up

This post is part of a series on event-driven programming. The complete series is:

Over the last few articles, I’ve covered a few of the evented programming patterns I use most often. It’s by no means an exhaustive account but there’s plenty of mileage in these simple techniques. Applying them can lead you to highly modular, flexible and responsive software. A quick recap of what we’ve seen so far:

  • Observable objects: use these when you want changes in one object to have side-effects elsewhere without hard-coding those side-effects into the object, or when you want to provide extension points for an object’s behaviour. Event listeners may fire any number of times.
  • Deferrable values: use these when multiple components need to wait for some work to complete or for some condition to hold before proceeding with their work. This pattern requires careful consideration of state, and each listener should fire exactly once.
  • Asynchronous methods: use these when you want to free up a method’s implementation to be non-blocking. Instead of returning a value immediately, the method takes a continuation that is invoked when the data it needs is ready.

These cover at least 90% of my async programming habbits when writing GUIs, and Faye (a non-blocking Bayeux client/server library) uses all three patterns extensively. Which brings me to my next point: though I’ve been doing all these articles with JavaScript, the patterns are not JavaScript-specific. JavaScript is a great language for this sort of work, which is one reason Node.js is so great, but really any language with first-class functions and lexical closures should be a good tool here. For example, two of the patterns I’ve talked about exist in Ruby as Observable, Eventful and EM::Deferrable. In the Python world there’s Twisted, though I’m afraid that’s all I can tell you about it. And it should go without saying that any halfway decent Lisp should be good at this sort of thing.

If you want to get started with evented Ruby you should really take a look at EventMachine and its various contributed gems. Ruby is a more complex language than JavaScript, especially with regard to function-like objects and its scoping rules, and personally I don’t find it as nice as JavaScript for event-driven work. It’s close, just not quite as good. To make up for criticising his screencast the other day I’m going to point you to Yehuda Katz on Ruby blocks and callables – both are required reading for working with functional Ruby.

To round off the series, I’m going to cover some general concerns when working with event-driven code. These apply to all the patterns I’ve covered; I left them out of the original articles partly so as not to repeat myself and partly so as not to obscure the core ideas being presented.

First, and I can’t stress this enough: you need to be very careful about state. In JavaScript you don’t have thread safety to worry about, but the fact remains that when you bundle up a section of code as a callback function, that code could potentially run at any time in the future. If there’s high latency in your async I/O, or if an event fires when you weren’t expecting it, your callback function needs to make sure that what it’s going to do still makes sense when it eventually gets called. For example, if you’re going to update a DOM element, does that element still exist? Apply a little paranoia and you’ll be fine.

Second, and I mentioned this in a previous post: make sure that you never write two callback functions that depend on each other. Relying on execution order means you’re very tightly coupling your code to the implementation of whatever event scheduler is managing your application, be it the browser runtime, the EventMachine loop, etc. Callbacks should be independent, atomic units of code that will behave sanely no matter when they execute. Remember: async code means you have no idea when a block of code will actually run, so don’t make any silly asumptions. The example I gave before was of two callbacks for the same event, one of which sets a value that the other is expected to use:

$("ul.tabs").bind("change", function(e) {
  // Set a value
  $(this).attr("selected", e.target);
});

$("ul.tabs").bind("change", function() {
  // Use the value
  $(this).attr("selected").show();
});

If you see code like this, consider refactoring into a single cohesive callback or find another way to decouple the event handlers.

Third it’s worth mentioning error handling. When you implement a callback system, your methods are going to be calling functions from other parts of your application, or even third party code. If one of the callbacks in a list throws an exception, you don’t want that to block execution of the other callbacks or of the rest of your method. Dean Edwards wrote about this last year, though his post specifically deals with using the DOM to dispatch events since it handles errors gracefully. Exactly how you deal with errors will depend on your app: you might not want to catch them, you might want to catch and log them, you might want to do some automatic recovery, but the important thing is you need to make a decision one way or another.

In JavaScript, you have several options. If you’re client-side, you can use the DOM as described in Dean’s article, you can use try/catch or you can use setTimeout()to schedule each callback asynchronously so it won’t block the others if it fails. Here’s a couple of examples of how you’d modify your dispatch loop; listeners is an array of [callback, scope] tuples.

// Catch errors and log them with Firebug
for (var i = 0, n = listeners.length; i < n; i++) {
  try {
    listeners[i][0].call(listeners[i][1]);
  } catch (e) {
    if (window.console) console.error(e);
  }
}

// Use setTimeout for async scheduling
for (var i = 0, n = listeners.length; i < n; i++)
  (function(x) {
    setTimeout(function() {
      listeners[x][0].call(listeners[x][1]);
    }, 0);
  })(i);

The setTimeout() illustrates the point about keeping your listeners independent – if events are dispatched asynchronously you’ve got even less of a guarantee about execution order. Most event systems do execute callbacks in sequence but there’s nothing to say they couldn’t execute them out of sequence or in parallel. It also shows how in some situations you’ll need an extra closure; in this example we use a closure to fix x to the value of i for that iteration, because if we didn’t do that the asynchronously dispatched function would use the value of i from the end of the loop every time it was called. Did I mention you should be careful with state?

Finally, think carefully about which pattern makes sense for implementing a feature. For example I recently used a Deferrable when I should have just used an async method; the stored callback hung around in memory after some initial check to decide whether to run it returned false, then the callback fired much later on when I wasn’t expecting it, resulting in multiple copies of UI elements being generated. Getting it right requires a little experience to get a feel for how to structure evented code – hopefully this series has helped point you in the right direction.

If you’ve enjoyed this article, you might enjoy my recently published book JavaScript Testing Recipes. It’s full of simple techniques for writing modular, maintainable JavaScript apps in the browser and on the server.