Client-side Messaging Essentials

On February 7, 2013, in JavaScript, by Jim Cowart

Wow – dangerous title, right? Our grasp of what is essential certainly changes alongside our understanding of the problems which we are trying to solve. So I won’t lie to you – what I thought was essential a year ago was woefully incomplete, as I’m sure what I’m about to write will seem to me six months down the road. So – this post is a snapshot in time of a few of the things I’ve found to be critical for successfully applying client-side messaging patterns in JavaScript.

1.) Understanding the Difference Between Mediator and Observer

One Does Not Simply "Pub/Sub"

Most people throw around the term “pub/sub” to describe any kind of eventing/messaging – but I think this term fails to adequately communicate the abstraction. Yes, ultimately, something is subscribing to what something else is publishing. But the level at which publishers and subscribers are encapsulated has the power to make a good pattern turn to the dark side. So, what’s the difference?


The observer pattern involves a subject being observed by one or more observers. The subject typically keeps track of the observers, usually by storing a list of callback methods registered by the observer(s) as they subscribe to be notified. Observe: (oh, puns, how I love them)

var observer = {
    listen : function() {
        console.log("Yay for more cliché examples...");
var elem = document.getElementById("cliche");
elem.addEventListener("click", observer.listen);

A couple of things to note:

  • we had to get a direct reference to the subject
  • the subject has to maintain some kind of internal state, keeping track of the observers’ callbacks.
  • while our listener isn’t utilizing any arguments passed back from the subject, there could, in theory, be 0-n* arguments (more on how that gets to be fun later)

* where n isn’t truly infinite, but for the purposes of discussion, it’s a limit we should never reach


The mediator pattern introduces a “third party” between a subject and an observer – effectively decoupling the two and encapsulating how they communicate. A mediator’s API may be as simple as “publish”, “subscribe” and “unsubscribe” calls, or a domain-specific implementation might be given to hide those kinds of methods behind something more semantically meaningful.  Most server-side implementations I’ve worked with were more domain-specific than simple, but there’s no rule against a generic mediator! It’s not uncommon to think of a generic mediator as a type of message broker. In either case, the outcome is the same – the subject and observer no longer know directly about one another:

// It's fun to be naive!
var mediator = {
    _subs: {},
    // a real subscribe would at least check to make sure the
    // same callback instance wasn't registered 2x.
    // Sheesh, where did they find this guy?!
    subscribe: function(topic, callback) {
        this._subs[topic] = this._subs[topic] || [];
    // lolwut? No ability to pass function context? :-) 
    publish : function(topic, data) {
        var subs = this._subs[topic] || [];
        subs.forEach(function(cb) {
var FatherTime = function(med) { this.mediator = med; };
FatherTime.prototype.wakeyWakey = function() {
    this.mediator.publish("alarm.clock", {
        time: "06:00 AM",
        canSnooze: "heck-no-get-up-lazy-bum"
var Developer = function(mediator) {
    this.mediator = mediator;
    this.mediator.subscribe("alarm.clock", this.pleaseGodNo);
Developer.prototype.pleaseGodNo = function(data) {
    alert("ZOMG, it's " + data.time + ". Please just make it stop.");
var fatherTime = new FatherTime(mediator);
var developer = new Developer(mediator);

Aside from the rather naive mediator implementation, you get the idea. The subject is no longer responsible for maintaining a list of subscribers, and both “fatherTime” and the “developer” instances never actually know about each other. They only share a message – which is an important contract, as we’ll see later. “Great, Jim. It’s still all pub/sub to me, so what’s the big deal? Does it really make a difference as to which approach I take?” Read on, dear straw man, read on.

2.) Know When to Use Mediator or Observer

The tl;dr – my own guiding principle when I’m faced with this: use observer “locally”, inside a component, mediator “remotely” between components. No matter what, be ready to use both in tandem.

But that’s a horrible tl;dr. It’s like trying to sum up months of nuanced experience in the trenches in less than 140 characters. The reality of answering this question isn’t always so neat. So here’s the longer version of the internal conversation:

  • Should the observer have a direct reference to the subject for reasons other than just because it’s interested in data emitted? For example – a Backbone.View has every reason to have a direct reference to its model. The very nature of the relationship means that the view might not only be interested in rendering when a model change event occurs, but it may directly invoke fetch on the model in an event handler. If the answer to this question is yes, then observer makes sense.
  • However – if the nature of the observer-subject relationship is solely about data, and a mediated pub/sub approach would work, I’ll go with that. Communication between two Backbone.View instances, or between two models (to pick on Backbone again) are examples of where this might be applicable. A view controlling a navigation menu might publish information about the current state of the app in which a view controlling a breadcrumb widget is interested (say, the current nav hierarchy). The breadcrumb widget doesn’t need a direct reference to the nav view, it just wants information that the nav view happens to provide. The key here is that the nav view might not be the ONLY one providing that information, and that both views could continue on without the other present. Mediated pub/sub is ideal here – and lends itself very well to extensibility.

That’s nice and all, but there’s an ugly elephant in the room: what happens when I have an object that produces a local event, and I want not only direct observers to get it, but indirect subscribers (via a bus)? This is why I said be ready to use both in tandem: you promote (or “bridge”) local events to the message bus as needed. Does this require more code? Initially, perhaps – but not as much as what you’ll end up writing to get yourself out of tightly-coupled hell if you’re passing your subjects directly to everything that needs to observe it. This is a good segue to the next two points…

3.) Selectively “Promote” Local Events to the Bus

Early on, I used the observer pattern almost exclusively for eventing in JavaScript. It’s the pattern we see over and over, and even popular client helper libs that are acting as mediator-hybrids, ultimately, present their API to us as if it’s the observer pattern. When I originally wrote postal.js, I then went through my “mediator all the things!” phase. It wasn’t uncommon to see publish and subscribe calls sprinkled through the prototypes and constructor functions I wrote. While I benefited from the de-coupled nature of this change, non-infrastructure code started to seem full of infrastructure concerns. Constructor functions taking a channel everywhere, subscriptions added as part of the new instance being created, prototype methods that published a value directly to the bus (where even a local subscriber had to listen through the bus to get the information instead of directly). Baking obvious bus-related concerns into these parts of the app began to feel like a code smell. The ‘narrative’ of the code seemed constantly interrupted by “Oh, and publish this out to all the subscribers now” and “WAIT! WAIT! Listen on this channel for that thing. OK, now keep going”. My tests suddenly required the bus as a dependency for low level unit tests. Something didn’t feel right.

The pendulum swung towards the middle and I began to realize I needed to preserve a ‘local API’ and extend the reach of data to the application through a mediator when necessary. My backbone views and models, for example, still used the normal Backbone.Events behavior for emitting events to local observers (i.e. – the model’s events were watched by its corresponding view). When other pieces of the app needed to know about that change in the model, I began bridging those local events to the bus along this line:

var SomeModel = Backbone.Model.extend({
  initialize: function() {
      this.on("change:superImportantField", function(model, value) {
              channel : "someChannel",
              topic : "omg.super.important.field.changed",
              data : {
                muyImportante: value,
                otherFoo: "otherBar"

It’s important to mention that while it’s possible to transparently promote events to the message bus, the local event and message should be treated as separate contracts – at the very least conceptually. In other words, you should be able to modify the ‘internal/local’ events without breaking the message contract. This is an important fact to keep in mind – otherwise you’ve simply provided a new way to tightly couple using an approach that aims to do the opposite!

So, the model above is testable without the message bus, sure. And my view and model could continue to function without any friction if I removed the logic bridging the local event to the bus. However, this is seven lines of boilerplate (albeit, formatted) . Bridging just four events results in almost thirty lines of code. OUCH. How do you get the best of both worlds – local eventing when it’s appropriate for direct observers, and extending the reach of events so that your subject doesn’t have to be passed around to everything – without the bloat? How can eventing have more taste and be less filling?

4.) Hide Boilerplate in Your Infrastructure 

It’s not that the code in the above example – bridging an event to the bus – is wrong syntactically or conceptually (assuming you buy in to the concept of local vs remote/bridged events). However, it’s a great example of the kind of friction good habits can bring to bear on a code base. “That’s too much code” will be said by someone at some point (as if LOC is the sole arbiter of a codebase’s quality). But, in this instance, I agree. It’s dreaded boilerplate. Here’s a pattern I’ve adopted in bridging local events on a Backbone object to postal.js:

// the logic to wire up publications and subscriptions
// exists in our custom MsgBackboneView constructor
var SomeView = MsgBackboneView.extend({

  className : "i-am-classy",

  // bridging local events triggered by this view
  publications: {
    // This is the more common 'shorthand' syntax
    // The key name is the name of the event. The
    // value is "channel topic" in postal. So this
    // means the bridgeTooFar event will get
    // published to postal on the "comm" channel
    // using a topic of "thats.far.enough". By default
    // the 1st argument passed to the event callback
    // will become the message payload.
    bridgeTooFar : "comm thats.far.enough",

    // However, the longhand approach works like this:
    // The key is still the event name that will be bridged.
    // The value is an object that provides a channel name,
    // a topic (which can be a string or a function returning
    // a string), and an optional data function that returns
    // the object that should be the message payload.
    bridgeBurned: {
      channel : "comm",
      topic : "match.lit",
      data : function() {
          return { id: this.get("id"), foo: 'bar' };

    // This is how we subscribe to the bus and invoke
    // local methods to handle incoming messages
    subscriptions: {
      // The key is the name of the method to invoke.
      // The value is the "channel topic" to subscribe to.
      // So this will subscribe to the "hotChannel" channel
      // with a topic binding of "start.burning.*", and any
      // message arriving gets routed to the "burnItWithFire"
      // method on the view.
      burnItWithFire : "hotChannel start.burning.*"

    burnItWithFire: function(data, envelope) {
      // do stuff with message data and/or envelope

    // other wire-up, etc.

You can obviously do this several different ways – with the bus framework of your choice – but it’s much less noise than the boilerplate, and might feel familiar to Backbone devs. When you control both the event emitter and message bus implementation, bridging can be easier. Here’s an example of bridging from a monologue.js emitter to postal.js:

// using the 'monopost' add-on for monologue/postal:
// assuming we have a worker instance that has monologue
// methods on its prototype chain, etc. The keys are event
// topic bindings to match local events to, and if a match is
// found, it gets published to the channel specified in the
// value (using the same topic value)
    "" : "ThisChannelYo",
    "secret.sauce.*" : "SeeecretChannel",
    "another.*.topic" : "YayMoarChannelsChannel"

Good habits are more enjoyable with boilerplate out of the way. Now I can test my objects locally, my bridging code independently, and even test that both together produce & consume the expected messages, etc.

It’s also important to note that if I needed to drop into the normal postal API in the above scenarios, nothing is stopping me from doing so. No loss of flexibility === WIN.

5.) Messages are Contracts – Choose Your Implementation Wisely

There are two general approaches in passing data to subscribers – and while there might be a more ‘official’ label for both, I’ve taken to describing them like this:

  • “0-n arguments”
  • “Envelope” (or “Single Object Payload”)

Consider these examples:

// 0-n args
this.trigger("someGuyBlogged", "Jim", "Cowart", "JavaScript");
// envelope style
this.emit("someGuyBlogged", {
  firstName: "Jim",
  lastName: "Cowart",
  category: "JavaScript"
    In an emitter like monologue.js, the emit call above
    would actually publish an envelope that looked similar
    to this:
        topic: "someGuyBlogged",
        timeStamp: "2013-02-05T04:54:59.209Z",
        data : {
            firstName: "Jim",
            lastName: "Cowart",
            category: "JavaScript"

I’ve found, over time, that there was less and less friction (and code) involved in handling envelope style subscriptions vs 0-n args. The challenge with the “0-n args” approach arises primarily for two reasons (in my experience): first, the typical “Hey do you remember which args were getting passed when that event gets triggered? No? Ok, I guess I’ll go look at the source triggering it”. Not really a big deal, right? But it can break the narrative of the code. You can use a debugging tool, inspect the values at run time and try to infer the “labels” based on the values, but what’s easier – looking at an argument with a value of “1.21″ and wondering what it represents, or inspecting an object and seeing { gigawatts: 1.21 }. The second reason has to do with passing optional data long with the event, and the pains it exposes as method signatures grow longer.

“Really, Jim, you’re bike-shedding.” Perhaps. But I’ve seen code bases grow and morph over time, and simple innocent events with one or two arguments become monstrosities with optional arguments nestled in the midst:

// early on it was just this
this.trigger("someEvent", "a string!", 99);
// one day, it grew up and devoured us all
this.trigger("someEvent", "string", 99, { sky: "blue" }, [1,2,3,4], true, 0);
// BUT WAIT - the 4th and 5th args are OPTIONAL, so they might pass:
this.trigger("someEvent", "string", 99, [1,2,3,4], true, 0);
// Oh, you were checking that 5th arg for truthy/falsy?
// Whoopsies! It's now the previous arg...
this.trigger("someEvent", "string", 99, true, 0);

If any of the data is optional, there’s no getting around testing for it. But it requires less code, is more extensible and is typically more self-explanatory (thanks to member names) to perform that sort of checking on a single object literal being passed to the subscriber callback. I still deal with “0-n args” where I have to, but if it’s up to me, it’s envelopes all the way – both from my event emitters and in my message bus. (Proving my bias, monologue and postal both share the same envelope structure, minus the channel, which isn’t used in monologue.)

So – bear in mind that the structure used to deliver data to subscribers is part of the “contract”. With envelope style approaches, you have the ability to describe the event with additional metadata (without adding additional arguments) – which keeps the method signature (and thus that part of the contract) consistent for every event and subscriber.  You also have the ability to easily version a message structure (or add other envelope-level information as needed). Just be sure to use a consistent envelope structure if you go that route.

6.) Message “Topology” Matters More Than You Think

There’s no silver bullet here. But you need to be deliberate and thoughtful about how you name topics & channels as well as how you structure your message payloads. I tend to map my models one of two ways: on a single data channel, with the topic prefixed by the model type’s name, followed by it’s unique id then by it’s operation ({}), OR I given the model it’s own channel, and the topics are {id.operation}. A consistent convention assists in auto-wiring reply-to behavior when models make requests for data. But not all operations on a bus are requests. You might have simple events being published to the app. Are you naming the topic to describe the event (ideal), or are you falling into the trap of naming the topics to describe the intended behavior one of the subscribers should perform? For example, a message with a topic of “route.changed” vs “show.customer.ui”. One indicates an event, the other a command. Be deliberate as you make these decisions. Commands are not bad at all, but you’d be surprised at how much can be described by events before you need request/reponse or commands.

End Snapshot….

That was quite the mental download – if you made it this far, THANKS. While I hope that I don’t cringe at this six months from now, I’m encouraged that all of these points lend themselves to the goal of not building one large behemoth application, but instead building many small applications that interact via message passing. I hope – as frameworks develop and mature – that more of the boilerplate pain can be removed and greater discipline around these patterns in JavaScript will emerge and flourish…

Further Reading….

Tagged with:  
  • weekenddeveloper

    Awesome breakdown! Thanks so much. It is always good to be reminded, that just because we have learned how to use a screwdriver, not everything automatically becomes a screw. Sometimes a nail is all you need, and sometimes you need screw. No pun intended :)

  • cmartinbot

    Excellent article! Thanks.

  • Pingback: The Morning Brew - Chris Alcock » The Morning Brew #1291

  • Tim Plourde


  • Tim Plourde

    Very cool! I like the concept of observables used for internals and mediators used for externals. Based on this idea, here’s how a basic mediator might look when using Knockout, which is all based on observables:

    • Jim Cowart

      Thanks for sharing that Tim! I’m hoping to find time to blog a bit more about that sort of thing in both KO and Backbone soon. I have a repo started with some rough-draft ideas on doing it in KO here: Hopefully I’ll be able to carve out time to think through it further and write about it…

    • Ryan Niemeyer

      If you are interested in mediator based communication in KO, then you might want to look at my postbox plugin here: It extends observables, so that they can automatically receive/publish messages on a specified topic. It does not go as far as postal (with channels, wildcards, etc.), but it would be pretty easy to use the same concept with postal and encapsulate it behind an observable extension. It makes doing decoupled communication between separate view models pretty easy.

  • Ed Draper

    In the example provided I really don’t see a lot of value in introducing it other than to decouple subscribers from publishers. If it served a function such as a historian, or retry mechanism, or some such, I could see value – otherwise it’s kinda falls in the YAGNI camp to me. What am I missing?

    • Jim Cowart

      Ed – I don’t personally believe that the principle of decoupling components falls under YAGNI. I’m 100% on board with avoiding gold-plating, but just because something *can* be done in a coupled way, doesn’t mean it should be done that way, or that the decoupled approach is superfluous. The gains include a level of modularization not achievable by passing concrete subjects in place of using messages as the contract, greater testability, the ability to simulate (and replay) conditions to test load, edge case/state scenarios and an overall architectural opinion that helps reinforce boundaries around key contexts.

  • chrixian

    good post <3

  • Justin

    Great article JIm!

  • Igor Hlina

    Awesome posting Jim. I really like the idea of declarative definition of event bridging to the bus. Can you provide some more info how this is implemented? Or better, can you confirm that Backbone Marrionette supports this?

    I’m also interested in case when some object is requesting for data via bus. In my last project this quickly becomes a mess of events flying here and there. Debugging was really hard and I didn’t found anything covering this (how to implement, or how to document).

  • Pingback: Scott Banwart's Blog › Distributed Weekly 195

  • Pingback: Angry Birds of JavaScript: Blue Bird – Events | Web Development, Search Engine Optimization, Social Media Marketing Guru