Adding a Centralized Event Dispatcher on Backbone.js

This article contains my solution to adding a simple global event dispatcher to Backbone. It should also help noobies (myself included) understand how Backbone events work (which has one big gotcha).

Sharing Events = Global Dispatcher

Today, I came across a fairly mundane – and probably common – problem: I have two views that need to talk to each other. An example for this would be when you have a status bar in one corner that gets updated when a user completes an action in another area. It turns out that Backbone (as far as I can tell) does not support this use case very well out of the box. Well, it does: it expects you to build that yourself.

Backbone supports a model where you publish and subscribe to things happening in your views/models (commonly known as an “event dispatcher“). For example, you can make your application do stuff when a user clicks on something or if a model attribute changes. The native solution localizes these events (probably a good thing) to the model/view that you’re working with. This works for simple stuff, but when you need it in other parts of your application, things break down. The short answer is that you need to build a global event dispatcher A.K.A. global event “hub.” Everything publishes (“trigger”) and listens (“bind”) to events from this object.

This is a common pattern. In fact, I found two solid articles on this topic. The first explains in detail why you need an event dispatcher. The second shows you how to make the dispatcher natively accessible by all of your Backbone classes.

Event Dispatcher Gotcha: Native Events

However, I felt both solutions weren’t quite there. The first forces you to pass around an Event object everywhere you need it. This is nice from a decoupling standpoint, but highly error prone. The second solution is nice, but makes the caller oblivious to the global event namespace they are triggering/binding to. This is dangerous because Backbone has native generic events that are fired when certain things happen. For example, when you edit a Model, it automatically fires a “change” event into its event dispatcher (which bubbles up to its Collection too). This means if that dispatcher was global, every object would see a “change” firing every time every Model changed. Not good.

Goals

I came up with my own solution that accomplishes three main goals:

  1. Retain native Backbone event triggering/binding
  2. Allow the developer to trigger/bind to global events
  3. Not require the developer to pass things around

Solution Code

(If you can’t read CoffeeScript, just use this converter to convert it back to JavaScript)

The following (very simple) code modifies your Backbone definition to attach the global dispatcher to all objects. The dispatcher is easily accessible from any Model, Route, View, or  Collection through the global_dispatcher parameter. I thought about having it trigger events to the local dispatcher as well, but I decided that keeping them fully separate was in everybody’s best interest (to prevent events from accidentally colliding):

Example Code

The next section is a simple class I wrote that will demonstrate how these events work. I am defining a simple Collection and a Model. Note that I named the global and local events the SAME. This was to help demonstrate that the namespaces are in fact completely separate (as in, just because they are named the same doesn’t mean a local event will ever trigger a global event with the same name).

The following snippet illustrates triggering the events attached to the Collection. Note that we add a Model into this collection (which has no impact on the output). The trigger_stuff method triggers both a local and global event (in that order). The output shows that the events were picked up in the order fired (local, then global). Note that the Collection also listens to the “model_custom_action” event, which coincides with an event the Model triggers. This is very important.

The order of operations looks like this:

  1. Fire a local event
  2. The Collection picks it up
  3. END OF FIRST EVENT
  4. Fire global event
  5. The Collection’s globally attached event handler picks it up
  6. END OF SECOND EVENT

The next snippet shows what happens when you fire an event on a Model inside a Collection. It is also why I decided to keep things separate. This is a little hairy, so pay special attention.

The order of operations looks like this:

  1. Fire a local event
  2. The Model picks it up
  3. The Collection picks it up since all events in children bubble up
  4. END OF FIRST EVENT
  5. Fire global event
  6. The Collection’s globally attached event handler picks it up
  7. The Model’s globally attached event handler picks it up
  8. END OF SECOND EVENT

Notice that in step #6, the Collection’s binding fires BEFORE the Model’s. This is key.

Step #3 fires because there is a LOCAL binding to the “model_custom_action” event in the Collection. The local binding is reacting to an event triggered in the child Model’s local event dispatcher. In other words, any event triggered from the local event dispatcher in a Model will bubble up to the Collection’s local event dispatcher and be otherwise indistinguishable from events triggered directly from that Collection.

Step #6, however, is different. That event did NOT originate from the child model’s local event dispatcher. Instead, it is reacting to the global bindings, which happen to share the same name as the event we saw earlier in step #3. Because it didn’t bubble up, the events are being processed in the order they were bound (via the bind() function). The Collection was defined before the Model, thus, the Collection’s global binding fires first.

In this last snippet, we demonstrate how Models behave when not inside a Collection.

  1. Fire a local event
  2. The Model picks it up
  3. END OF FIRST EVENT
  4. Fire global event
  5. The Model’s globally attached event handler picks it up
  6. END OF SECOND EVENT

This is very straight forward if you managed to follow the last example. To get additional clarity, you may want to try renaming the events in the above class and re-run the examples.

By having the global dispatcher separate, you can consciously decide when an event should be “public,” as well as not clobber any existing Backbone functionality. Backbone is still really young (pre 1.0!), so I wanted to avoid using any solution that might break if they changed the internals. Also, completely preserving the behavior of event bubbling for Model-Collections is important to future proof my hack.

I hope this is useful for all of your Google-visitors!

What Agile is NOT

Agile Will NOT Make People Work Faster

People will work just as slow or fast as before. It is not a miracle drug. Agile DOES ensure people are working on the stuff that matters at that particular moment. Which leads to the next point…

Agile Does NOT Mean You Can Change Your Mind All Day Long and Still Ship on Time

If you change your mind that the product should do X instead of Y, you may have to throw away code. This is a fact of life. Agile DOES encourage making key decisions at the last possible moment so that the cost of change is minimized. Agile (a la retrospectives) exposes why or how the deadline was missed and how costly bad decisions were.

Agile is NOT a Better Way to Manage Down

Yes, there are lots of little tasks now. And yes, they are all prioritized and bite-sized so it’s easier to micromanage, right? But you’ve missed the point. Agile let’s the engineers tell the managers what is going on. Agile IS a way to manage expectations (e.g., “managing up”).

Bonus Non-Issue: “We Need to Focus on How It Will Scale”

I’ve heard this a lot. It doesn’t matter (and if you disagree, then you probably aren’t ready for Agile). Agile is about making stuff that works – right now – so you can see if what you’ve made has any value. If it has value, then you worry about scaling. If it’s garbage, nobody will care how it was architected. Get it to work first; scale second. Getting stuff in the customers’ hands and then making decisions based on the feedback is your top priority. If you aren’t focusing on that, you’re probably on your way to creating your very own crappy product that nobody uses.

Today we learned that “agile” is a loaded word.

Avoid Gloss on Dark Business Cards

So we just got our business cards. The company logo is on a black/dark backdrop. We decided to gloss it up to give the cards that extra sexy shine.

Instead, we ended up with an ugly smudge magnet. Don’t make the mistake we made.

See for yourself (covering our catch phrase on purpose):

Our business card

 

 

Browser Wars… Wait, That’s Still Going on Right?

Rewind 5 years. Ask any self-proclaimed nerd what the browser market shares were. Market share stats were like the stock market ticker of the Internet Nerds. Everybody knew about it, and everybody cared.

But what’s the market shares today? Did you know that IE is below 50% by most measures? Did you know that Chrome ate up Firefox’s market share? And what’s Safari’s market share if all the iPhones and iPads use it?

You probably don’t know.

Because, who cares.

5-10 years ago, it mattered that IE had 70+% of the browser market because it directly influenced what was possible as an application developer. But mobile changed all that.

Mobile browsers ended up being the adoption wedge for HTML5 and alternatives to Flash thanks in large to the fact users — and developers — treated mobile as separate from regular browser apps. What a blessing in disguise: it let everybody start over. And once the mobile stuff got popular and apps broke, people blamed the bad mobile browser (“My ghetto Blackberry won’t load Facebook right!”) instead of the website. It was the perfect storm to force everybody to start adopting HTML5. Add in CSS/JavaScript standardizing tools (Modernizr,  jQuery, GWT, etc.) and developers didn’t even have to do cross-browser testing for simple stuff.

Maybe this is a bad thing to admit, but I haven’t bothered testing in all browsers for a year or two now. Stuff just breaks less often. IE7 is “good enough,” and the other browsers work 99% of the time. Thus, the only time I bother checking browser compatibility is if I’m doing something super complex or a user complains.

Good job, Internet. Ya, the evil Microsoft IE empire is still around, but we won the war and nobody even noticed.

Failure Paralysis – The Thing that Holds You Back

We all have this friend: he talks about all the things he will do soon. He’s going to ask out that cute girl. He’s going to start hitting the gym. He’s going to ask for that big raise. He’s going to be more social. Yet, he never does.

Your friend is a victim of Failure Paralysis.

It’s clear that inaction guarantees a lack of success. No success can be achieved by doing nothing. You can’t even win the lottery unless you buy a ticket. This applies to anything: becoming president, getting a girlfriend, losing weight, seeing a movie, etc. The first step, is to start moving toward the goal.

This is the struggle every entrepreneur eventually has to overcome.

A lot of people talk about the uncertainty around taking that first step. The reality is that as soon as you take that first step, you’ll be hit with 100 new issues you never imagined. You can read all day about poker theory, but it pales in comparison to real playing experience. And yet, so many people get stuck in the theory-crafting stage of an idea. Move past this step.

To succeed, you must do. And not doing assures failure.

What are the odds that the idea in your head will become a million dollar company? Well, if you do nothing, the odds are 0%. If you start now, maybe you increase your odds to 0.1% – a literal infinity-percent better odds. The problem is that some people don’t want 0.1%. They want 99%. Thus, they wait while they do stuff to try to increase their odds. But isn’t actually doing it going to increase your odds too? When does the waiting stop and the doing start? Well, for most people: never.

Everybody has excuses to do something later. But only a few don’t let those excuses stop them. Kevin Rose famously destroyed his relationship to fund Digg. Mark Zuckerberg dropped out of Harvard for Facebook. HARVARD! Actually, so did Bill Gates for Microsoft. Michael Arrington, a now-famous tech journalist, abandoned a career as a lawyer to join the startup world. Even Jack Dorsey bailed (I use this term in jest) on Twitter to go do Square.

Did these guys fear failure? I’m sure. You can’t gamble your future and not be. But that didn’t matter — they ignored all the “sound” advice from their friends and family. I won’t get into each case, but history shows us that if each had waited an extra year or two to make the jump “safer,” they may have missed the boat entirely.

Later is the same as never. Now is the only acceptable time.

Your friends might buy your excuses, but as an Internet-Stranger, I’m going to say the truth: your excuses don’t matter. Results do.

  • Too tired after work? Suck it up or change your sleeping habits.
  • Credit card debt holding you back? Pay it off and quit going out.
  • Not enough time? Manage your time better and quit reading Reddit.
  • Can’t code? It’s OK to suck at it. Learn.

So, take a deep breath, and do something. Anything. Don’t fear failure. Fear not-succeeding.

Ruby: Time Comparisons Seem Backwards Due to Asian Culture

I found a weird quick in Ruby best explained by the fact it’s written by a Japanese dude. Nerd post below. In Ruby, when you compare two time signatures, you use the operator:

It compares two Time objects and then returns -1, 0, +1, or nil. So this is how it looks in practice:

What’s the value of “comparison_result?” The answer is 1. 1? I stared at this for a long time and my inclination was to think it should return whichever side was bigger. There was very little documentation I could find on this topic, but I finally figured out why.

The reason WHY is that time flows down or backwards in Asian culture, and Ruby is written by a Japanese dude. Confirmation in this wiki article.

So the conclusion is that this operator should be read as, “Which side is smaller?” As in: left side = -1, right side = +1, 0 = same, and nil = invalid.

Come on, Facebook

Facebook just had their annual F8 conference, and it was a snooze-fest to me. Examples of things they could have done that would be ACTUAL game changers:

  • An HTML5-based social application platform (currently missing from their mobile strategy and making embedded FB apps less important on mobile)
  • Embedded contextual ads on existing Facebook widges, complete with rev-sharing – yep, it would be hated
  • A truly threatening Adsense competitor for off-Facebook publishers – yep, could be hated too
  • A FB credits fee of 5% (from 30%), and enable physical e-commerce – yep, threatens a working business model
  • A connect-to-pay Paypal clone – yep, would increase Facebook’s financial liabilties

Yes they might harm them. Yes they’re risky. But they’re game changers. They flip the market upside down. They make existing competitors freak out. It pushes you even further as a leader. And, thus, the absence of such a risk shows how conservative Facebook has become.

Instead, they announced a glorified scrap book and some cool automated like buttons.

I’m sorry, but the timeline is hardly revolutionary. How is this remotely on par with the introduction of apps or the Graph API at previous F8 conferences? As a company approaching IPO, this was their moment to really show the world what Facebook’s potential could be. And so they showed off a bunch of visual fluff. The press is fawning over the newly released changes like the second coming of Jesus.

Not to mention all of these new integration points don’t even work on their current web-based or native mobile applications! What am I missing here?

I am disappointed.

“Michi’s Minions” – On Respecting Co-workers

In my relatively short, but unusual, career I’ve heard the phrase “Michi’s minions” a number of times. People use it to jokingly refer to my staff. They say it in private, so I think some people might conclude it’s just a crass joke. Perhaps. For people that know my crude sense of humor, my offense to this joke probably takes you by surprise. Every time I hear that phrase, I immediately conclude the other person is not somebody I want to work for and that they have a naive understanding of professional relationships. History usually proved that conclusion correct.

To me, it indicates a certain condescending/naive attitude that the person has toward employees that is absolutely unacceptable. I once heard the analogy that management is like a rowing team. You’re the coxwain that helps keep the rowboat straight. Yet, when you think about it, you don’t lift a finger to help the results get done. If somebody gets tired or wants to quit, you can’t take out a whip and start cracking. At the same time, without the coxwain, the team will never make it to the finish line. You both need each other. All of my greatest accomplishments as a leader in an organization were because of the hard work the team put in. To forget that your staff were the ones furiously rowing is ignorant if not insulting.

When somebody thinks that “managing” equates to “having minions,” it’s not pretty to watch them get a little power. I’ve seen this a few times now and it had disturbing results every time. The usual trend is:

  1. They give their staff all the boring, dirty work
  2. They scold in public and praise in private (if at all)
  3. They say, “I don’t need to be liked as long as work is getting done”
  4. People start quitting

I want to address #3 really quickly. “Being liked” and “getting things done” are not mutually exclusive. A good leader will get both done together, every time. If you can’t create a work environment where people are happy, you aren’t qualified to be a leader. Think about the last job where you constantly went above and beyond. Did you like your boss? I bet you did. I am very confident in the importance of having a good relationship with those you work with.

This post isn’t about watching your language. It’s about watching your attitude.

You need your staff more than they need you.

Social Payments: the Future is Unified

Physical credit cards will soon be a thing of the past. Is the rest of the US startup industry ready?

The next real-world cash-replacement could be powered by Facebook, Google, Apple, Square, Intuit, Paypal, or some other company hiding in the wings.  There’s a few obvious names in there, and then there’s a few left-field ones to some people. This post isn’t about how those left-field plays could happen. I simply wanted to explain how the landscape is changing.

There’s a convergence happening right now between social, payments, and e-commerce. Imagine this predictable future:

You buy some coffee at Starbucks. You take out your phone and swipe it at the terminal. Your [insert phone app name here] Bucks (from here forth known as: “Phone Bucks”) are deducted from your account. Your purchase is optionally posted on your Facebook/Twitter stream. You get highly-targeted Groupon-clone notice for a Starbucks coupon redeemable online immediately. You decide to buy it using your Phone-Bucks — no signing in, no additional authorizations — by clicking a button.

We’re talking about a future where your online wallet (today, known as Paypal, Facebook Credits, etc.) follows you into the real world and ties directly into your mobile phone. This represents a single unified wallet. And it makes sense. That’s the future. That’s where we are headed now. I’ve been watching this trend happen for the past few years, and it’s exciting to finally see some big players waking up to this reality. Which players are the closest to achieving this? In this order:

1. Facebook – Due to its large install base (virtually all smart phones) and an existing currency platform (Credits), they are best positioned to move into the real world. And they recently made a huge move indicating a desire to do exactly this (creating a subsidiary is the first step in buffering liabilities that come with real-world payments).
2. Square (or Intuit depending on how things play out) – They would solve this from the other direction: they have a stronger real-world presence, and moving into the digital space might be easier than vice-versa.
3. Google – They will approach this from the platform (Android) by opening it (Google Checkout 2.0) up to developers and creating an ecosystem. They also recently stole a key exec from Paypal, so you know they’re serious.

It’s my belief that any startup entering the e-commerce landscape right now needs to make sure they are thinking about this convergence. To get big valuations, I think a startup needs to not only understand these trends, but be the first to market in the new paradigm that will be coming (really soon!). This convergence will create an opportunity for new players to emerge and destroy existing leaders. All mobile startups around commerce, Groupon, Paypal, and even the advertising arm of Google are probably already adjusting to these trends. Is your startup?

Think about it.

Quick Command Line Method to Get Memcached Stats

I had to look for a while to figure this out:

echo stats | nc 127.0.0.1 11211

This assumes the memcached instance is running on a local instance with the standard port. This will output a bunch of statistics about the machine. The one to watch is “evictions,” which represent items getting overwritten before they naturally expired. This would indicate items being cached too long or the server running out of memory.