Understanding extend() and object inheritance in Backbone

Asking how best to do object inheritance in javascript is a bit like asking how to raise your kids—everyone has a different system, but as long as they live to adulthood, mission accomplished. But sometimes when working across several different libraries, plugins and code styles, doing inheritance right can quickly become a little confusing.

Let's start with a simple example using Underscore's (or jQuery's) extend() method. We'll pretend that we're writing an image Gallery module, and that we can set a timeout value to determine how long an image stays visible:

This is usually known as object-literal inheritance, or as I like to call it, the "hash-smash" pattern. But in fact, it's not technically inheritance. Each call to extend() will simply merge the properties of the two objects returning a new object. So in reality, we've got three copies of Gallery floating around in memory.

Contrast this with the more traditional approach of using object prototypes and constructors:

Notice that because we've assigned setTimeout() to the object prototype, the property is shared between all it's children. However, the timeout property itself is unique to the instance objects (because we hung it off of 'this' in our constructor function).

Okay, now let's look at another version of an extend() method. This time from Backbone.js:

So looking at this, it would seem to do exactly the same things as the above plain-prototype example. We're using 'new' to get a new instance object that has its own timeout property. Meanwhile, setTimeout() stays attached to the prototype. At the same time, the syntax pattern is closer to the previous extend() method we used from Underscore, where we pass in an object literal that extends Backbone's base Model. It kind of seems we're getting the benefits of prototypes with the simplicity of of the object literal hash-smash.

But in reality, there's a pretty serious defect in the above code. Those tests are simply providing a false positive. Let's look at a more complex example where it's easier to see what we're doing wrong. Here, we're adding another property, an object to describe our gallery's data source:

Holy failing tests! What's going on? It looks like the timeout property is still be set correctly, but when we try to set the URL it's being overwritten by the other instance. Let's look at Backbone's extend method directly to see how it works:

Indeed, we can see that Backbone's extend() works quite differently than its Underscore and jQuery counterparts. Much like a constructor function, it sets up the prototype chain and returns a child object. But whereas a constructor is just limited to assigning a prototype, Backbone's extend() will actually create a Surrogate object that sits in the prototype chain between the Model object and the instance object. So all the properties we pass into extend() are added to the prototype (extend() also takes a second optional argument for static properties, as well). 

So why did our tests fail? Why are we able to set the timeout value on the instance objects, but not the dataSource? The problem actually lies with how we (aren't) declaring these properties on the instance object itself. Timeout only has a simple scalar value, and when we set it using 'this', we're implicitly declaring a new property called timeout on the instance object, which overrides the prototype property. 

However, when it comes to the dataSource property, we're actually using 'this' to access the dataSource property on the prototype, not set it.

Is this a design flaw in Backbone? Not at all. We simply need to be careful about where we're assigning properties. Here's a final example, where we're using Backbone's initialize() to properly declare and assign instance properties:

Until we can all standardize on ECMAScript 6, it's likely we'll continue to see different methods for extending objects and setting up prototypes.

Using Games to Model Complex Thinking

Ian Bogost coins the term "procedural rhetoric" as using rule-based logic to further rhetorical arguments. Or as he puts it, "the practice of using processes persuasively."
 

My big takeaway from this is how Bogost views games as a vector to expose the complexity of social problems that are difficult to express in words or pictures. This should be obvious to any gamer that's picked up Sim City or Dwarf Fortress. Applying it to more topical issues, I wonder what would happen if we gave this generation of school children the Healthcare Cost Simulator just as our generation got Oregon Trail.

 

The Itch of Disconnect

Dave Pell writes

Technology used to be a way to solve life’s little problems. Now, technology is used to solve the little problems caused by technology. On some level, we know that doesn’t make sense, but we don’t have an app to convince us. Where’s the computer algorithm to prove that the quiet walk without the phone calls is the balance?

I would describe the feeling of being disconnected as a constant itch. It's muscle memory unable to fulfill the gestures in it's programming. Where once the activity of getting off a plane involved a dozen lit cigarettes, it is now the glow of a hundred phone screens lighting up.

Successfully disconnecting takes practice and discipline. Like an acetic monk, you must surpress your natural urges. Learn to recognize the urges in your fingers or your brain for another quick hit of e-dopamine, and tell them to shut up for a few seconds while you unwind.