Posted by & filed under Content - Highlights and Reviews, Programming & Development.

A guest post by Tim Ruffles, a Ruby & JavaScript developer based in London who teaches and mentors developers, and works on SidekickJS, a code-quality tracker for teams. Previously he was a front-end tech-lead for Skimlinks and Picklive; he talks about Javascript at conferences and events and can be reached at @timruffles.

Backbone.js applications can become tightly coupled, however, the publish/subscribe (pub/sub) pattern is a great way to decouple these applications, and it is easy to implement the pub/sub pattern in Backbone.js.

In this post, we will look at how pub/sub makes it easier to change, test and reuse your Backbone.js code by reducing coupling. We’ll also see how it affects the structure of your application – especially making sure your Router doesn’t become an all knowing “God object.” You can also take a look at a post on persistence in Backbone.js that details how to split your model from persistence in Backbone.js.

The problem

First, let’s talk more about the problem this pub/sub pattern solves: coupling. Coupling refers to the knowledge two parts of your code, or components, have of each other. You know two components are coupled when a change to one requires a change in the other. Coupling normally takes the form of one object accessing methods or properties on another. The problem with coupling is that if an object’s methods change, or a new object replaces it, you’ll need to update every part of your application that uses it.

Pub/sub reduces coupling, because rather than talking to other objects directly, you can publish messages on a shared pub/sub object. In Backbone.js, an example might be to play a sound on a user being logged out:

Notice we don’t know how the user was logged out, or which object was responsible, only that it happened. As you can see, the pub/sub is coupled to the name and data payload of a message. The only dependency is on the pub/sub object that has a very small API – you can send or receive messages. Which component triggers the message ceases to matter – you just ensure your system reacts to the vocabulary of events correctly.

Let’s see some code

Let’s look at a concrete example. We’re building a little tool to search your favorite tweets. You have a search box, a history view, and a results box. You can search by text, jump back to previous searches, or filter by a specific author.

backbone.app

Our pub/sub implementation is very simple: we just mix Backbone.Events into an empty object:

We’ll just use the standard trigger and on methods to publish and subscribe to messages.

Using our pub/sub implementation we can easily make the views completely unaware of how the search process occurs. They just publish a event with a new query criteria, and a different object is responsible for creating a new search from it. If it triggers a new search, that is broadcast, and any views that are responsible for displaying the search are updated.

For instance, the search view simply triggers a criteria change on submit:

Our TweetList listens for a new search, and sets up listeners and re-renders once it hears it:

Allowing users to switch back and forth between searches in this design is simple. The history view simply fires search changes, and we have a plain old JavaScript object to manage the process of transitioning between searches when new criteria is supplied:

So, we can see that none of these objects know about any one of the others. Their behavior can all be considered in isolation. If they do the right thing given the events firing, the system will work as a whole.

Decoupling

If we contrast this approach with a more traditional one, we can see where the decoupling occurs:

We now have two possible problems when refactoring occurs. First, the search manager’s API is exposed. Changes to this API will affect all components that were updating the criteria. Secondly, we have to pass around our search manager through layers of hierarchy that don’t need it themselves.

In testing, we now also need to pass in a custom mock or an instance of our search manager. If we change the API, that’s one more place our coupling has forced us to change our code. With the pubSub implementation, we can completely change how the system responds to messages without a single line of application or test code changed in the components that broadcast them.

Compared to events

Pub/sub can see similar to events. The core difference is that you don’t know who’s firing the events, and you don’t need a reference to them to listen. Objects in a pub/sub system share a central pub/sub object that they fire messages on. The listener doesn’t have to know about the publisher to listen!

So, from our comparison, we can see one immediate advantage is the non-locality of handler. With events fired via the Backbone.Events methods that are present on Backbone.View, only objects with a reference to that view can listen. For instance: let’s say we refactor a child view that fires a “search:set” event to have a child view of its own that now is responsible for firing the event.

It’s clear we’ve had to listen to the new child view to ensure that the “search:set” event is still visible to our ParentView. Pub/sub doesn’t have these problems, since the pub/sub object is shared throughout:

Getting access to the pubSub object

One potential question that arises is how to get the pub/sub object into our views. One answer is to pass it via constructors, so each view passes it down into its child views. This creates a lot of boiler-plate.

A better approach is to embrace Javascript’s dynamism. We can set the pubSub object on our View’s prototype, so it’s shared among all instances. To maintain testability we create a View subclass that accepts a pubSub in its options, and falls back to first the prototype, and then a global pubSub object.

This has all of the ease of a global pubSub object with none of the pain: we keep testability, and we still have the option to make multiple pubSub objects if we need to isolate a module.

Where to use pub/sub

I use pub/sub in my views. I don’t think it makes sense to use pub/sub in model code, as the views (which do double duty as controllers in Backbone.js) are responsible for making sure models are updated in response to user commands. Models sit and handle domain logic, and controllers can listen to and publish these changes as events that need to change our views.

So: publish model events from controllers that are listening to models if required, but don’t let models use pub/sub internally – it mixes up view concerns with your domain.

Testing pub/sub code

Testing code that uses this pattern is much easier – you simply make sure components respond correctly to messages, and fire any broadcasts it should. We never have to setup complex collaborator objects because we always have just one: our pub/sub.

Pub/sub and Backbone.Router

Pub/sub also helps to reduce a system’s coupling to the router. A typical anti-pattern I see in Backbone.js code is the ‘God router,’ where the router knows about every model and view. This is a nightmare to test, maintain and debug, since the router grows with every new feature. For me, the router should simply be thought of as another View, firing events on the user’s interaction with the URL. This aligns with the “small components, each doing one thing well” approach you may have heard referred to as the Unix philosophy. A router should respond to URLs, not instantiate views.

When using pub/sub, I prefer to have no methods at all on the router and merely publish its events as view:change events. That way, if a view change needs to be triggered for another reason – for instance undoing a command, or a user being logged out – the rest of the application can just as easily fire the view:change event. Supporting PhoneGap and mobile websites becomes much easier this way. And finally, testing the router is made very simple as well.

Pub/sub – object orientation done right

So: if you’ve ever felt that Object Oriented code feels hard to change, and that refactoring always involves changes spreading throughout the system, I think pub/sub will help. Alan Kay’s original conception stressed messaging over the internal properties of a system’s objects. Pub/sub gets a lot closer to this ideal, and keeps your code malleable, easy to test, and simple. Enjoy!

Be sure to look at the Backbone.js resources that you can find in Safari Books Online.

Not a subscriber? Sign up for a free trial.

Safari Books Online has the content you need

Developing a Backbone.js Edge incorporates the best practices and the techniques from the combined authors’ experience of developing many Backbone.js applications. In this book you get a complete guide to Backbone.js and equip you to start using the library straight away. While writing this book the authors developed an example app, called Hubbub, to illustrate the various features of the library.
Developing Backbone.js Applications shows you how to get the job done with Backbone.js. You’ll learn how to create structured JavaScript applications, using Backbone’s own flavor of model-view-controller (MVC) architecture.
Backbone.js Cookbook contains a series of recipes that provide practical, step-by-step solutions to the problems that may occur during frontend application development using an MVC pattern. You will learn how to build Backbone.js applications using the power of popular Backbone extensions and integrating your app with different third party libraries.

About the author

timruffles Tim Ruffles is a Ruby & JavaScript developer based in London. He teaches and mentors developers, and works on SidekickJS, a code-quality tracker for teams. Previously he was a front-end tech-lead for Skimlinks and Picklive. He talks about Javascript at conferences and events and can be reached at @timruffles.

Tags: Backbone, Backbone.js, Decoupling, Javascript, pub/sub, publish/subscribe,

7 Responses to “Decoupling Backbone.js Applications with pub/sub”

  1. Tadas

    Maybe using Backbone (.on(), .off(), .trigger(), etc..) object would be a better idea? :)

    http://backbonejs.org/#changelog

    0.9.9
    The Backbone object now extends Events so that you can use it as a global event bus, if you like.

  2. Morgan Roderick

    Where is the constructor for “PubSub”?

    It’s used by

    var subSystemPubSub = new PubSub;

    but is not defined anywhere I can find.

    • Tim Ruffles

      Oh sorry! Good point – it’d actually intended to be the same as the original pub sub object created from extending Backbone.Events. So a simple definition would be:


      function PubSub() {
      }
      PubSub.prototype = _.extend({},Backbone.Events);

  3. Ben

    Hi I’m trying to use the following from your example…

    function PubSub() {}
    PubSub.prototype = _.extend({},Backbone.Events);

    var View = Backbone.View.extend({
    constructor: function() {
    Backbone.View.apply(this,arguments);
    this.pubSub = this.options.pubSub || this.pubSub || window.pubSub;
    }
    });

    var subSystemPubSub = new PubSub;
    var usesLocalPubSub = new View({pubSub: subSystemPubSub});
    var alsoUsesLocalPubSub = new View({pubSub: subSystemPubSub});

    But I get the following javascript error at the second line of the View’s construtor.

    Uncaught TypeError: Cannot read property ‘pubSub’ of undefined

    • Ben

      Looking at the Backbone View constructor the pubSub option is not set on the object because the viewOptions don’t include it.

      var View = Backbone.View = function(options) {
      this.cid = _.uniqueId(‘view’);
      options || (options = {});
      _.extend(this, _.pick(options, viewOptions));
      this._ensureElement();
      this.initialize.apply(this, arguments);
      this.delegateEvents();
      };

      // List of view options to be merged as properties.
      var viewOptions = ['model', 'collection', 'el', 'id', 'attributes', 'className', 'tagName', 'events'];