Game On: Backbone and Ember

Game On: Backbone and Ember

Tutorial Details
  • Application: Backbone.js, Ember.js
  • Difficulty: Intermediate

So you’ve accepted the challenge to go thick on the client-side; well done. You’ve considered all the frameworks out there and are unsure which one to choose? You’re not alone. Read on.

My experience, when learning the way of writing client-side apps is proving to be steep and hard. It's not easy to deliberately choose to use MV* on the client for someone who wrote JavaScript, based entirely on jQuery and its plugins. This is an entirely new paradigm; it requires basic programming skills and a considerable understanding of JavaScript (the language) design. If your experience relates to mine, then read on!

I will be explaining the main differences between two of the most popular JavaScript clientside frameworks: Backbone.js and Ember.js. Each of these tools has strong points, as well as weaknesses that might help you make a more thoughtful choice.

Disclaimer: as software professionals, we must deal with diversity of opinion. Backbone and Ember are results of opinionated and experienced professionals, like you and me. One tool isn't better than the other; they just serve different crowds and, ergo, solve different problems. Thanks Trek for the solid advice.


The Philosophy

Backbone is much easier to learn than Ember.

First and foremost, you need to understand that Backbone and Ember particularly serve slightly different crowds. Regarding complexity, Backbone is much easier to learn than Ember. However, it's said that once you learn Ember, it hardly gets any more complex. Take Trek's word on it. If you're just getting started with some real JavaScript, then perhaps Backbone is your tool. If, however, you know that you're going to deal with a lot more than just a simple use case or two, then you might prefer Ember.

Backbone

Jeremy Ashkenas built Backbone so it would be possible totake the truth out of the DOM. What he means by this is: whatever business you did using only jQuery / Mootools / Prototype could and should be better extracted into pure JavaScript structures – objects, if you will. Instead of using DOM elements to define your business elements and behavior, Backbone invites you to do it the other way around. JavaScript objects are the core and the DOM is merely a representation of that data.

With Backbone, you have some given assertions:

  1. Data lies in JavaScript objects, not the DOM
  2. Event handling lies in JavaScript objects, not jQuery event bindings
  3. The way you save data in a backend server is done through the objects that contain the data

You are given complete control over the way you build your app. Backbone was meant to give you a basic way of designing your model objects and how these interact with each other through event bindings.

Rendering HTML to the DOM is of your responsibility. You are free to choose any template engine: Mustache, DoT, Handlebars, Underscore, etc. Backbone contains a View prototype that has the responsibility of articulating the DOM and your JavaScript core.

Ember

When Tilde started building Ember, it did so with a far more challenging goal: to provide standard conventions in client-side development, eliminating as much boilerplate as possible. The result is a much more ambitious framework that aims for a predictable architecture and steady development.

Ember shares some common points with Backbone in the way it tries to pull data and behavior out of the DOM by providing extendable JavaScript prototypes, but it does this in a very different manner than Backbone does.

Ember stands on:

  1. Two-way data binding: objects in Ember are able to register bindings between one another. That way, whenever a bound property changes, the other one is updated automatically.
  2. Computed properties: if you wish to have a property that is a result of a function, you can create them and assign a property as computed by that function.
  3. Template auto-updates: when an object is updated in your app, all the views currently displayed in the screen that are bound to that object automatically reflect the change, with no boilerplate.

The DOM – Views

Both Backbone and Ember have common key concepts, such as views. They both represent DOM communication, respectively. The way they accomplish this concept are somewhat different, though.

I'll use the Todo use case for the examples below, inspired by the TodoMVC showcase.

Backbone

A Backbone View might something like this:

var TaskView = Backbone.View.extend({
  tagName : "li"
, template : "task-template"
, render : function() {
    // your code to render here.
  }
, events : {
    "click .mark-done" : "mark_as_done"
  , "change .body"     : "update_body"
  }
, mark_as_done : function() { /* code here */ }
, update_body  : function() { /* code here */ }
});

This is simply the definition of your view. You will need to instantiate one if you want it to be in the page. Something like this will do the trick:

var task_view = new Task({ model : task_model });
$("body").append(task_view.el);

Notice that we're passing a model in so you can keep a reference to the data object that feeds the template. The template property inside the view can be used to call an outside template, via an identifier. I've used something like this in the past:

var TaskView = Backbone.View.extend({
  template : "#task-template"
, render : function() {
    this.$el.html(
      Mustache.render($(this.template).html())
    , this.model);
  }

  // snip
});

Ember

Ember has a different approach to views. In fact, the convention states that views should talk to controllers and not models directly. This is a good practice, if you intend to follow a stable architecture. I'll explain the sample for the same view:

var TaskView = Ember.View.extend({
  templateName : "task-template"
, mark_as_done : function() { /* code here */ }
, update_body  : function() { /* code here */ }
});

That's it. But where's all the rendering stuff? Well, Ember lifts that boilerplate for you. Simply say what the template is, the controller that holds the data object, and then you just need to append it to the DOM.

var task_view = TaskView.create({
  controller : task_controller // Ember.ObjectController
});

task_view.append();

When creating a new view instance, it will bind the controller's content (which can be an Ember.Object or a list of them) to the view. When you decide to append the view to the DOM, it will look up the template and place the generated markup for you.

Thoughts

Backbone is more explicit and less magical.

Backbone is more explicit and less magical. You create a View, tell it what template to use and how, register the events and do what you have to do. They own the page. That's a great start for those coming from a jQuery background. However, when something needs to be updated in the DOM, you will face some boilerplate.

With Ember, updates are automatic. You say what template it is and event callbacks are functions inside the view object. Any time an object is updated, the view automatically updates the page.

Some common event bindings are built into Ember and others must be put into the template. It's good for those who come from a backend perspective, as it reduces boilerplate in a considerable way.


The Data – Models

Models in Backbone and Ember are quite similar. They hold information for a business entity.

Backbone

An example of a Backbone model looks like this:

var TaskModel = Backbone.Model.extend();

With this simple line of code, you have a working model with RESTful communication built-in. You get methods like save to persist the data and fetch to load it for free; no plugin is required. Validation is also built into the way data is saved by providing a validate callback, which returns a boolean that tells the record to be saved or not. The implementation of the validation is still for the developer to do.

To create a new task, you instantiate a new TaskModel.

var task = new TaskModel({
  body : "Mow the lawn"
, done : false
});

You may inject as many attributes as you like, because the task's attribute list isn't strict (think of it as schemaless). You can still set a defaults property when extending Backbone.Model.

Ember

With Ember, there are no models, just objects. It might look something like this:

var TaskObject = Ember.Object.extend();

Similar to Backbone, you need to extend from Ember.Object to create an object class. It inherits all the basic functionality for a class with callbacks for when it gets changed, created and destroyed, amongst other features. It does not, however, have backend communication out of the box. Ember.Data is being developed as an extension of Ember.Object by the Ember core team to fulfill that need. It's already usable but not stable as far as the documentation tells.

Ember objects are also considered to be schemaless. To inject defaults into Ember objects, you extend Ember.Object by passing an object with as many attributes as you require.

var TaskObject = Ember.Object.extend({
  body : "Mow the lawn"
, done : false    
});

Thoughts

Backbone has a consolidated way of syncing up with a persistence layer over REST and that's a good convention there. It's one less thing you have to configure in order to work with a backend server.

Ember is working its way toward making Ember.Data ready for production use, and it looks promising. Even so, the particularity of Ember objects having two way bindings makes it dead easy to perform connections between objects.

At this point in your reading, you have an inflection point between Backbone's stability in communicating with the backend server and Ember's bindings. Whatever's most important to you should determine your decision.


The Glue – Controllers

This is where the frameworks part ways. They have a huge conceptual gap on how to glue things together in your app. While Backbone strives to remain as simple and flexible as possible, Ember sacrifices codebase size for a better architecture. It's a tradeoff, really.

Warning: the following examples don't contain HTML template samples.

Backbone

As I noted, Backbone aims for simplicity that converts to flexibility and it achieves such attributes precisely through the lack of a controller class. Most of the workhorse is distributed around views, collections, models and the router (should you choose to use Backbone's Router).

Considering a list of tasks that needs to be managed, it would require:

  • A Collection to store the tasks.
  • A Model to store a task's information.
  • A View to represent the collection.
  • Another View to represent each task.
  • A Router to manage URLs.

Most of the application logic will live in the views, as they connect models to the DOM. There is no clear distinction of responsibilities, as the view does everything. It can be good for small applications that don't require a solid architecture.

To display a list of tasks, you would end up with something like this:

Collection

var TaskList = Backbone.Collection.extend({
  model : Task
});

Model

var TaskModel = Backbone.Model.extend();

Views

var TaskListView = Backbone.View.extend({
  render: function() {
    this.$el.empty();
    for (_i = 0, _i < this.collection.length; _i++) {
      var task = this.collection.models[_i];
      this.$el.append(this.renderItem(task));
    }
    var tasks = this.$el.html();
    this.$el.html(Mustache.to_html(template, {
      tasks: tasks,
      no_tasks: !this.collection.length
    }));
  },
  renderItem: function(task) {
    var view = new Row({ model: task });
    var el   = view.render();
    return el.el;
  },

});

var TaskView = Backbone.View.extend({
  tagName: "tr",
  render: function() {
    this.$el.html(M.to_html(template, this.model.attributes));
    return this;
  }
});

Router

var Router = Backbone.Router.extend({
  initialize: function() {
    this.tasks = new TaskList;
    this.view = new TaskListView({
      collection: this.tasks
    });
  },
  routes: {
    "": "tasks_list",
  },
  tasks_list: function() {
    this.view.render();
    $(".bucket:first").html(this.view.el);
  },
  start: function() {
    Backbone.history.start({
      pushState: true,
      root: "/tickets/"
    });
  }
});

Notice that the collection doesn't have a template of its own; rather, it delegates to a single task view being rendered and appended to the final result being put on the page.

Ember

The number of classes required to have the same setup is slightly bigger.

  • Instead of a Collection, you would have an ArrayController, which works very much alike.
  • You would have an extra ObjectController for managing a single task.
  • Instead of a Model, you would have an Object / DS.Model, which work alike.
  • You would have the same kind of Views.
  • A Router is also responsible for managing URLs.

You might be thinking that the two frameworks are not too different from one another. It's rather tempting, but it's not exactly true. Some particular differences are:

  1. The controller is responsible for interacting with the data objects, not the View.
  2. The views are responsible for handling the DOM, not the controller.
  3. The views communicate with the controller, not directly to the data objects.
  4. The data that feeds the view template is actually a binding to the controller's data.
  5. The router is more of a state manager, which includes much more than handling URLs.

The separation of concerns is good in the long term. Controller handles data, views handle the DOM, period. This kind of decoupled and cohesive, boilerplateless design allows for more focused testability.

The implementation to display the same list of tasks would be something like the following, considering a full Ember application:

Application root architecture

window.App = Ember.Application.create();

App.ApplicationController = Ember.ObjectController.extend();
App.ApplicationView       = Ember.View.extend({
  templateName: "application"
});

Object

App.Task = Ember.Object.extend();   

Controllers

App.TasksController = Ember.ArrayController.extend({
  content: []
});

View

App.TasksView = Ember.View.extend({
  templateName: "my-list"
});

Router

App.Router = Ember.Router.extend({
  root : Ember.Route.extend({
    index: Em.Route.extend({
    route: '/',
    connectOutlets: function(router){
      router.get('applicationController').connectOutlet('tasks');
    }
  })
});

In Ember's case, there's not much being said about how things are done inside. All of that boilerplate is taken away so you can focus on what really matters in your app: you define a task object, a task list controller with an array called content, your view and the router simply combines them all together and puts it in the page.

Thoughts

After realizing how Ember really works, it starts to become liberating.

Predictably, this segment was the hardest to grasp on both frameworks. Backbone was definitely easier to learn and its flexible nature gives control over the way objects and DOM interact. This might be good for you, if you really need that kind of flexibility but still want to maintain a structure for your app's logic in the JavaScript side.

As for Ember, its breathtaking implementation might be scary at first. However, after realizing how Ember really works, it starts to become liberating. All the conventions the framework sets for you releases you from boilerplate and configuration, letting you focus on your app. This is similar to what Rails did for serverside development that caught so much attention.


What Sets Them Apart?

Ember was meant to lift the common burdens of JavaScript development in the browser.

So far, the whole point of showing the two tools off has been to acknowledge their single and noble purpose: to delegate power to the client-side, through both structure and method.

Backbone core strength is definitely its KISS approach. It provides you with the minimum to let go of the DOM as the core supporter of your app, and start using real JavaScript objects that can be tested and designed properly.

Backbone comes packed with collections, models, views and the router, amongst other small utilities. You are free to do what you please with them.

Ember, on the other hand, was built with a different mindset, as it aims for a much more conventional and opinionated way of building web apps. It tackles a set of common problems, such as boilerplate, data binding and DOM templating so you don't have to worry about them from the start. Ember was meant to lift the common burdens of JavaScript development in the browser.

Ember comes packed with objects, controllers, auto-updating views, state machines, bindings, observers and a router (which is also a state machine), all of them conjured with a good dose of conventions. You have an architecture already designed and ready to begin working without losing focus.


Conclusion

Mind the learning gap. Your experience and cultural heritage will strongly dictate how fast you join the client-side. If you're scared of what to do or which one to pick, then I struck a nerve of yours and that's good! Want a good answer on which to choose? Both.

It's all about the JavaScript

If you're unsure how even jQuery does all its magic, then start learning Backbone. It's easier to begin with, and the documentation is dead simple to read and understand. After you're done, start building something. Go dirty. Check these tutorials if you need some help.

If you're still in the dark, read Yehuda Katz's entries on how JavaScript works.

Once you get a better vision of how the JavaScript works as a language, you will begin to gain a better grasp of how the objects interact with each other. When you do, go for Ember. It's more complicated at first, but don't give up. Start reading the docs and the guides. You might want to check Trek Glowacki's blog entry just before getting your hands dirty.

My bottom line

Personally, I'm leaning towards Ember; I enjoy its robustness at a macro scale, and I also prefer its conventions. Backbone is a more malleable and easier tool for smaller apps or small features inside an existing app.

I’m still learning both, and have a few challenges to tackle:

  • Automatic tests: how to do them and which testing suite is better. Qunit or Jasmine? Headless (thinking PhantomJS), Node or browser test runner? Not sure yet.
  • File uploads
  • Internationalization

What are your thoughts on this whole debacle? Do you have any challenges in mind? Any difficulties or impediments? Let me know!

Note: Want to add some source code? Type <pre><code> before it and </code></pre> after it. Find out more
  • http://blog.davemo.com Dave Mosher

    Testem [1] is a pretty kickass testing framework that supports headless (PhantomJS) and in browser testing. It is framework agnostic but has support for popular frameworks like Jasmine and Mocha. I was surprised to see that Testem even supports IE7, 8, and 9 (7/8 through compatibility mode).

    [1]: https://github.com/airportyh/testem

  • Ismael

    Shouldnt it be
    var task_view = new TaskView({ model : task_model });
    intead of
    var task_view = new Task({ model : task_model });”

    • http://josemota.net José Mota
      Author

      Yep, thanks for noticing. Will fix it.

      • Ismael

        Btw, nice post!

  • emrah

    What about Angular?

    • http://www.jeffrey-way.com Jeffrey Way

      That’s one I’m intrigued by too. I’m trying to find a good teacher to write that article for us.

      • nish

        @Jeffery…Love angular, it’s an amazing framework. Does a ton with very little code. I’d love to create screencasts for these.

      • emrah

        this guy making pretty good teach videos about Angular. http://johnlindquist.com/

      • http://www.jeffrey-way.com Jeffrey Way

        Thanks – I’ll check it out.

      • Brian

        I am loving AngularJS. I have worked with it for roughly a month now and just handed off my first full app. While developing “The Angular Way” definitely requires a fairly radical shift in thinking, it’s absolutely worth the investment. Extremely fast, massively powerful. I have worked with Ember, and Angular by comparison feels like it does a much better job solving data-binding, templating, and other common issues.

        Jeffrey definitely pursue some coverage of this awesome framework. I have a few sources in mind that you might want to ping (currently active contributors in the community). Feel free to email me if you’re interested.

      • Tony

        Angular looks like a winner

      • http://www.code-pal.com Sumeet Chawla

        Yeah Jeffrey, we need more Angular tuts.. Right now there is just 5 things about Angular. :( I have one doubt that I have been researching for a very long time. Angular’s templating system uses {{ }}. So does Django’s templating system. So is it a good idea to use Angular as a front end framework for a Django app?

    • Brian

      +1 Nothing touches AngularJS when it comes to testing.

    • Sebastian

      I haven’t used Angular in production, but it looks really good. I really like the declarative approach. I have it in my list of things to try in the near future.

    • http://mauromarano.it mauro

      +1 for angularjs

  • Sebastian

    I have used both and ended up using neither of them. Backbone just doesn’t do enough. Ember does but it is too heavy, it is harder to learn and had other issues I didn’t like. Thankfully I found CanJS to give me the best of both worlds: fast, lightway, easy to learn, live binding, computed properties

    • http://josemota.net José Mota
      Author

      I’ve yet to discover other frameworks. Angular, CanJS, Meteor, Spine, amongst others, are rising as alternatives. Would love to have a better understanding of each one, do you have any written opinion on CanJS?

      • Sebastian

        This is what I found about CanJS:

        - it is quite fast, comparable to Backbone
        - Very lightweight, also comparable to Backbone
        - Dead easy to learn
        - It enforces a very good pattern for avoiding memory leaks
        - Does live binding like Ember
        - Also have computed properties like Ember
        - Only supports EJS for now, which is not great but ok (mustache is coming)
        - It has a observer object that is super useful for all kind of general stuff.
        - Documentation is great

    • atech

      same here…Can JS has mix of both Backbone & EmberJS.

  • Jon

    The comma syntax ruins it.

  • donpedrodelaluz

    You should be aware that Ember.js makes memory leakes when there’s a lot of template updates.

    • http://josemota.net José Mota
      Author

      Did you go through this in the past? How much updating would you consider for a practical example? I’m interested in knowing, please share more.

  • beardtwizzle

    Backbone is intentionally light and frees you up to take the route you want. For small apps you can use it on its own in a vanilla fashion, but for larger apps we couple it with backbone.marionette (https://github.com/derickbailey/backbone.marionette) [seriously check this out when thinking about backbone], which gives your backbone app a more solid structure.

    Personally I always find the choice in these libraries comes down to how rigid or free you want your development process to be (e.g. Rails/Sinatra). For many they prefer to be ushered along in the ‘right’ direction (for these people Rails, Ember, etc. are great) – for others they prefer to have more control over their app code base (for these people Sinatra, Backbone.js, etc.) are perfect.

    • Tony

      Agreed!

  • Anonymous

    Let me guess… You’re a coffeescript guy trying to write about Javascript…
    Sloppy code, lack of standards, global variables…

    This article is set to “Difficulty: Intermediate” but let’s face it… anyone reading the frameworks’ documentation would reach the same conclusions… This is an entire article stating the obvious.

    Good way to go…

  • http://victorortega.com.ar Victor

    The only reason that stop me from using Ember.js is that it not has localstorage, or other storage built-in. Ember-data exists but it’s not that good

  • Jesus Bejarano

    Then what about , Meteor and Batman

  • Millad

    I find CanJS far better and simpler than both.

    • Sebastian

      Agree, CanJS is simpler than both. And very powerful, fast and robust.

  • blacksonic

    JsTestDriver combined with SinonJs and BusterJs are two really good testing frameworks

  • Bruno

    Im also starting to learn Backbone, so I have a question.
    Wasn’t it easier if you’d write something like:

    self = this;
    _.each(this.model.models, function(task){
    this.$el.append(self.renderItem(task));
    });

    instead of:

    for (_i = 0, _i < this.collection.length; _i++) {
    var task = this.collection.models[_i];
    this.$el.append(this.renderItem(task));
    }

  • Tyrone Avnit

    I have not used Ember.js, so I cannot comment on the library itself, but have used Backbone.js in many projects. I believe Backbone.js is a library that helps you to write better javascript. It’s not magic in the sense of Ember.js, but rather encourages you to write your own magic. There is no “one way” to do a taks in a Backbone.js app, and thats what I find most liberating. I must disagree wholeheartedly in your statement that “Backbone is a more malleable and easier tool for smaller apps or small features inside an existing app”. I have been burnt by a number of frameworks that are “Magic”. When you are building a larger application with many different requirements, you end up working against the framework and not with it. Thats why I find Backbone.js’s minimalism and simplicity such a joy. You never working against the library. It encourages you to think for yourself, and in turn you become a better at writing robust javascript applications.

    • http://www.joezimjs.com Joe Zim

      Agreed. It always seems like “Magic” always turns out to be something you have to work around later on. I had this problem with the “Magic” of Backbone’s server synchronization because my back end wasn’t set up how they prefer. I imagine Ember would cause me even more difficulties.

    • http://josemota.net José Mota
      Author

      I understand your point when you say that Ember can restrain you from doing certain things. What I’ve come to realize more thoroughly though is what I disclaimed in the first place: they serve different crowds and different purposes. Ember solves common architectural problems, Backbone gives you a set of classes for you to orchestrate. Even though some things are common, they’re different in nature and philosophy.

      Most people will refrain from using something that apparently binds them. Other people give that kind of control away in favor of standards and conventions. It’s a matter of choice. You definitely made one and that’s a good thing.

  • http://blog.hizup.com Manu

    Wow! Very good post! Thanks!

  • http://www.falafel.com Basem Emara

    Great post! Nice clarity on the MVC aspects. CanJS seems like a rising star and looks really elegant. There is a good blog post that compares it with Backbone and other frameworks: http://bitovi.com/blog/2012/04/introducing-canjs.html

  • Rashidul

    You wrote “Most of the application logic will live in the views, as they connect models to the DOM. There is no clear distinction of responsibilities, as the view does everything. It can be good for small applications that don’t require a solid architecture.”

    – I don’t 100% agree with you. view can handle the tasks but we use model to handle the interaction as best practices and this is why we use MVC structure(MV* in this case). We can Handle stuff from view but we use model..
    For example:
    Model logic in view: https://dl.dropbox.com/u/43106216/guest/view.PNG
    Model Logic in model: https://dl.dropbox.com/u/43106216/guest/model.PNG

  • Rashidul

    One c c the difference of using Backbone framework when work on larger app instead of to-do. for to-do it would be too much overkill but for larger app , it does work fantastic.

    backbone’s other advantages is it uses Model, View, Collection, render… all classes and function is very easy to remember when u work on MVC(MV* here).

  • http://www.joezimjs.com Joe Zim

    For the following points, I’m looking at just the Backbone example of the tasks list.

    You sent `this.model.attributes` to the template. DON’T. Please use `this.model.toJSON()` so that there is no write access to the properties.

    You also used a for loop to iterate through the collection. Why? Collections have a built-in `each` function for iterating over them.

    You wrote this:

    renderItem: function(task) {
    var view = new Row({ model: task });
    var el = view.render();
    return el.el;
    }

    Row isn’t defined. It should be TaskView. Also, naming the variable to `el` is just fail. You don’t even need that variable because you already have a variable (`view`) that points to the exact same thing.

    I have no idea what you’re accomplishing with this:

    var tasks = this.$el.html();
    this.$el.html(Mustache.to_html(template, {
    tasks: tasks,
    no_tasks: !this.collection.length
    }));

    What you should be doing is
    1) Render the template
    2) Append a TaskView to a specific element in that template for each model in the collection

    Also in the TaskView, you reference Mustache with `M` instead of `Mustache`.

    Finally, in the router you have this line of code:
    $(“.bucket:first”).html(this.view.el);

    You shouldn’t be sending elements to the `html` function. Read more about that here: http://www.joezimjs.com/javascript/jquery-html-youre-doing-it-wrong/

    Overall the article makes a decent comparison of the two frameworks, but your coding sucks. If that even IS your code. I noticed that it used a different style for where to put the comma than the previous code.

  • Aesthete

    Well written. Thanks for the insight.

  • Ebaggg

    What are your thoughts on knockout? I’m a newbie but looks like the best of all worlds.

  • rferferferf

    gegherbgjk b ernmgbg geiugngr erkbgiergbbgr gweuigiwneg wg uinwuiduiwef wejkbfyuwebf THANKS

  • jceb

    I’ve wrote a project on the company where i used to work, the name is wonka.js, the page http://wonkajs.com, this project is made for the need to build an javascript modulable application that has 210 modules. So i ensure that you can write big applications with backbone and about conventions we’ve formulated so many on this framework that is easy to use and works like a backend framework, but isn’t a backend framework.

  • Mike Cantelon

    I don’t like the fact that Ember auto-updates the DOM. I want to be in control of everything that might use resources.