Salsify Engineering Blog

Using Cocktail to create Mixins for Backbone Models that Respect Inheritance

Cocktail: Backbone Mixins that Respect Inheritance

At Salsify we use Backbone heavily to represent our data, fully embracing its Model/Collection paradigm. Backbone models and collections in fact represent all server-managed state in our single-page Javascript client application. We also use Backbone views, relying heavily on Marionette to structure our presentation and Epoxy to bind our model data to the DOM in our views.

We’re always trying to improve how we develop our product and we recently found a technique that helps us reduce boilerplate when reusing code that we’ll share today: using Cocktail to create mixins for Backbone models that respect inheritance.

Sharing implementation via inheritance

In our app we have dozens of Backbone models and collections and hundreds of views, many of which share the same requirements and feature sets. We use inheritance heavily in many places to share common code, but sometimes inheritance isn’t the right model when what we simply want to do is inject some logic into a model, collection, or view.

For instance, take the example of a collection that is a nested resource–its url would look something like this: /api/products/34/digital_assets. This returns the set of digital assets for a product–it’s really a collection whose parent is the product with id 34.

Here’s what such a model would look like:

This is fine and succinct, but products at Salsify have several nested resources with a collection (or model for single-assign) backing each in the client. We could implement this using inheritance:

But this doesn’t work if we also have nested models — we’d have to copy the implementation of initialize so we could call the correct super constructor.

Additionally, what if we needed other functionality for our collections? What if some of our collections supported paging, and others didn’t? We could add that to the inheritance chain as well:

But this begins to get unruly, especially if we need our collections to be filterable as well. Do we add that to the inheritance hierarchy as well? Do we implement a does-everything collection that has “switches” to enable and disable features? Neither seems entirely appropriate.

Mixins

Enter mixins. A mixin is collection of functionality that can be added to a class via any other method than inheritance. Most languages support only single inheritance which makes mixing functionality from multiple parent classes via inheritance impossible. A mixin with backbone can be as simple as:

This works great if all you’re doing is adding functionality via adding new methods. But what if you need to bind some events in initialize? This method doesn’t work—you almost certainly need to call the super’s initialize as well and you can’t do that without really knowing your inheritance chain.

Mixins, improved

Enter Cocktail. Cocktail provides a method that mixes functionality into a class that preserves calling the target class’s functionality for methods that conflict between the mixin and the target. Here’s an example:

Cocktail will ensure that both initialize methods are called when a DigitalAssetsCollection is instantiated. Cocktail will merge hashes as well — if you mixin a view that defines an event listener the event listener will be bound:

One more thing to make Cocktail even more succinct: patch backbone’s extend with: Cocktail.patch(Backbone); Now you can define your mixins inline in your class definition:

Super simple and succinct. More info about how Cocktail works is available on its Github page.

  • amytych

    Mixins are definitely something my codebase could use. Thanks for this article, I have to look into it.

  • Michael Scheibe

    I’d also recommend checking out https://github.com/rhysbrettbowen/Backbone.Advice

    It’s based on some great ideas by Angus Croll, which are now to be seen in Twitter’s Flight https://github.com/twitter/flight#advice

    Because it’s using a functional mixin vs. an object mixin it allows a bit more flexibility and instead of calling all similarly named functions sequentially, you can have your mixin’s version be called before/after or wrap/replace the original function.

    Angus’s original functional mixin article is a great read: http://javascriptweblog.wordpress.com/2011/05/31/a-fresh-look-at-javascript-mixins/

    • Dan Spangenberger

      I definitely like the ideas in Backbone.Advice; thanks for sharing!

      I find the syntax a little difficult to use–certainly more code than with Cocktail–but you do get more power. I’ll have to consider how we can adopt some (or all) of it here.

  • sainaen

    Thanks for the article! Mixins look really useful for some common cases, but we stopped using them because of two reasons:

    1) Looks like there is a tendency to, whenever you write something, think “oh, maybe I should make this function to be a mixin, so we could reuse it later”, and you do create a new mixin. And then again. And again. So it quickly becomes a huge pile of mixins here an there with one or two functions in them, where “classes” are actually constructed every run time from five or more mixins.

    2) It was hard for us to create a nice structure for more than five-ten mixins. We just couldn’t think a way to do it right.

    Have you encountered such problems?

    PS. You have one minor mistype in the last two code examples: there should be curly braces for `events` fields.

    • Dan Spangenberger

      Thanks for mentioning the typo!

      We’ve really only just started using mixins in our codebase. We’ve introduced them to a moderately sized codebase ( < 20k lines of javascript), and we still have fewer than ten mixins. We don't use more than two in any current class, but I'm sure that will change as functionality is added, and existing functionality is broken out into mixins. I personally don't see much of a problem mixing in most functionality that a class needs–it separates concerns cleanly and allows one to easily include (or exclude) certain functionality for a view, model, or collection.

      Mixins also have the benefit of making testing of a piece of functionality much cleaner–if you want to test a PageableCollectionMixin, you only need to test the pageability functionality–not the rest of the inheritance chain that you might bring along with a PageableCollection.

      We haven't defined any more structure for mixins than I've posted about here–we do use RequireJS and define each mixin in a separate file–I already foresee defining multiple mixins in a single RequireJS module, and exposing them as such instead of including many files for many mixins, but we haven't done that yet. I'm also very interested in a better approach to structuring them.

  • Pingback: Data Binding in Backbone with Epoxy