The Skinny on BackboneJS

Introduction

From the Backbone site:

"Backbone.js gives structure to web applications by providing models with key-value binding and custom events, collections with a rich API of enumerable functions, views with declarative event handling, and connects it all to your existing API over a RESTful JSON interface."

Now a lot of these terms/paradigms might be quite new to you. That's ok, we're learning something new here.

My Interpretation of What Backbone Really Is & Does

I disagree that it gives structure to web applications, it doesn't really do that at all.

We all know that JavaScript has no concept of classes, right? If someone said:

"Here you go, I've written a load of JavaScript code which will give you a full 'Class' implementation to use in your web applications".

This, in my opinion, is what Backbone does for us. It has 4 or 5, seemingly magic (not magic, just written in an extremely competent way by the team behind it), core Objects which you extend in your application for your own use, Backbone doesn't give you any indication of how you should structure your web application.

Meet the Players

Where Backbone does excel is to push you to separate your code into logical areas, to write more modular and easier to maintain code. If you've ever worked with a MVC then this paradigm might come a little easier for you. PHP, Objective-C, Ruby and now JavaScript have a way of structuring code called MVC:

Backbone has a slightly contrived interpretation of MVC, as in it actually uses MV*. It has Models and Views but then uses Routers instead of Controllers. The core objects that make up the MV* structure are outlined below.

Backbone's Core Objects

Models

Backbone is very heavily biased towards data, if you're building a frontend client to a REST API, then Backbone is your friend.

Nothing explains it better than the site:

"Models are the heart of any JavaScript application, containing the interactive data as well as a large part of the logic surrounding it: conversions, validations, computed properties, and access control. You extend Backbone.Model with your domain-specific methods, and Model provides a basic set of functionality for managing changes."

Think of a Backbone Model as a fancy Object, one which you can run filter functions on for example, an Object which you can sync it's own attributes back to a server. A Backbone Model is simply an intelligent "key:value" store. (I wish I'd have understood what a Backbone Model truly represented earlier on, because the whole thing would have "clicked" a lot quicker.)

Think of a Backbone Model as a single entity, a helpful description, right? No. I agree. Ok, this "entity" could be a database row, an Object in an API JSON response, hell, it could even be a User who's logged in.

In a Todo app, a Todo item would be a Model - it's something you'd want to store in localStorage or a database with fields attached to it. Well these fields directly map to "keys" in our Models. So you start to realise that when people say the phrase "moving the state to the client", that you literally have a representation of your database/persistence layer stored in Objects in your JavaScript.

When a change is made to any of the values in your Model, Backbone will call the .sync() method. Sync is basically like jQuery's $.ajax function. You don't really use .sync() directly but you (as you can with most things in Backbone) extend it with custom functionality, ie. if you needed to send an "auth token" along with every call to the server, you could extend .sync() and do this. In a hypothetical situation (imagine a user has filled out a form), the process of saving the data back to the server might go something like this:

var artist = new Backbone.Model({
    firstName: "Jamie",
    lastName: "Woon"
});

artist.set({birthday: "March 29, 1983"});

artist.save();

In those couple of lines of code, we've created a new Backbone Model, added some default attributes to it, set a new attribute on it and then saved the Model back to the server in JSON format.

Collections

From the site:

"Collections are ordered sets of models. You can bind "change" events to be notified when any model in the collection has been modified, listen for "add" and "remove" events, fetch the collection from the server, and use a full suite of Underscore.js methods."

Collections also took me quite a while to get my head around (like everything in Backbone did), but all it really boils down to is that a Collection is basically an array of Models. You'd have a Todo Model and you'd have a Todos Collection.

Sticking with our "artist" example above:

var Artists = Backbone.Collection.extend({
    model: artist
});

I find myself working with Collections a lot more because it's a little more rare that you'd work with a singular Model. You might have a Collection of Tweets or Invoice Items or Blog Posts. A Collection will hold all of these Models. You can run functions on a Collection, ie.

var friends = new Backbone.Collection([
    {name: "Athos",      job: "Musketeer"},
    {name: "Porthos",    job: "Musketeer"},
    {name: "Aramis",     job: "Musketeer"},
    {name: "d'Artagnan", job: "Guard"},
]);

var musketeers = friends.where({job: "Musketeer"});

alert(musketeers.length);

Each Object passed into a Collection at instantiation becomes a Model (when you use the "new" keyword, you are instantiating something in JavaScript). So then you can run functions on your Collection like the above, much like you'd query a database.

Views

From the site:

"Backbone views are almost more convention than they are code - they don't determine anything about your HTML or CSS for you, and can be used with any JavaScript templating library. The general idea is to organize your interface into logical views, backed by models, each of which can be updated independently when the model changes, without having to redraw the page. Instead of digging into a JSON object, looking up an element in the DOM, and updating the HTML by hand, you can bind your view's render function to the model's "change" event - and now everywhere that model data is displayed in the UI, it is always immediately up to date."

Pretty much sums it up. A View always has a "master element", now this may be your sidebar, or your header bar, or it may just be a <li> in a list. Views can be minimal in functionality, but it's just a really good practice to split your UI up into logical areas; Views. Sticking with our "artist" example, imagine if an artist Model was changed, maybe someone added a "gender" attribute, then we could put a line like this in our View:

this.listenTo(this.model, "change", this.render);

What this does, is every time we change a Model's attributes (a Model which we passed into our view), we automatically call the render function. Which might look something like this:

template: _.template($('#artist-template')),
render: function() {
            this.$el.html(this.template(this.model.attributes));
            return this;
}

This will take the Model's attributes and pass them into a Template to display to the user. Which means that with a few of those listenTo()s in your Views, your UI will be bound to your data; making updating the UI almost trivial.

Routers

Again, from the site:

"Web applications often provide linkable, bookmarkable, shareable URLs for important locations in the app. Until recently, hash fragments - #page - were used to provide these permalinks, but with the arrival of the History API, it's now possible to use standard URLs - /page. Backbone.Router provides methods for routing client-side pages, and connecting them to actions and events. For browsers which don't yet support the History API, the Router handles graceful fallback and transparent translation to the fragment version of the URL."

Routers are fairly simple in theory.

For example, if you wanted to load up a list of Posts, you might do this from elsewhere in your application (maybe the user clicks the "Posts" link):

app.navigate("posts", {trigger: true});

Then in your Router file, you'll have a Routes Object:

routes: {
    "posts":"posts"
}

And then the corresponding "posts" function:

posts: function(){
    var Posts = new Backbone.Collection({
        title: 'my post',
        date: '25/12/2013'
    });
    var posts = new Backbone.View({collection: Posts}); 
}

So you can use your Router to instantiate your views and initialise Collections.

Where Do I Go From Here?

My exact route from learning Backbone to building the large scale application I'm now writing at KashFlow:

  1. Try to work out what Backbone actually was
  2. Sit like a sponge and absorb everything I could read about it, from Addy Osmani's book to numerous tutorials around the internet
  3. Attempt to write a little Todo app in Backbone for the first time
  4. Have a crisis of confidence that I still didn't get it
  5. Read some more
  6. Built a basic app prototype, very simple UI interaction and LocalStorage use
  7. Realise it was becoming DOM spaghetti and badly structured
  8. Hit up @danharper7 who helped me with managing my Views and starting with a really solid application base to build from
  9. Looked at things like the Backbone Boilerplate and took what I felt was relevant, but didn't blindly follow it
  10. Truly realise that there is no "right way" in Backbone to structure your application
  11. Perfect my own method of structuring Backbone applications with my prior knowledge of Design Patterns
  12. Fairly confidently started implementing Backbone into KashFlow's web application as the base for the new frontend that will be coming out this year.
  13. Keep learning! Once you've got the core concepts nailed in Backbone then it's time to find your own path. Look around tutorials and articles on Backbone structure but take them with a pinch of salt. It really is only going to come from your own experimenting. That's why I've tried to keep this article fairly close to the core Backbone Objects and concepts and not dictating "this is how you should build Backbone applications".

Essential Reading

General Backbone gurus to follow/pester

You can always contact myself on Twitter @benhowdle with any questions about the article or any areas of Backbone that you just can't get your head around.

Tag: JavaScript