Backbone.js: MVC in JavaScript
Join the DZone community and get the full member experience.
Join For FreeComplex JavaScript applications have more and more logic that is not directly tied to the DOM and HTML elements: presentation logic, persistence mechanism over Ajax and localStorage, or handling of user actions.
This kind of logic can be effectively decoupled from the DOM, in order to simplify testing and make the code reusable in different situations. It's plain old MVC, in its original incarnation (not the web server-side version) which can now be set up in the browser.
The job of Backbone.js is to set up a small MVC framework in a browser's window:
- it provides a structure for models and collections.
- It manages views which are populated and updated via events raised by models.
- It supports REST-like adapters for connecting to a data source on the server side, or localStorage as the persistence mechanism.
Pros
Since JavaScript-based logic is only going to grow in modern applications, there are many pros to this solution.
Backbone.js stimulates a clean separation of concerns: the logic of the presentation models and collections is cut away from the templating and handling of events generated by the user.
Actually, the separation is not extreme: controllers and views are collapsed into the same kind of classes. In these view classes, events on certain DOM elements are tied to methods defined by you on the same object:
window.AppView = Backbone.View.extend({ events: { "keypress #new-todo": "createOnEnter", "keyup #new-todo": "showTooltip", "click .todo-clear a": "clearCompleted" }, ...
while Template Methods call some hooks that you can define to specify the HTML to show:
render: function() { this.$('#todo-stats').html(// ...
Moreover, lots of machinery (event handling, rendering of HTML, storage) is taken away from your responsibility and centralized by the framework.
Cons
Adopting Backbone.js has also some constraints.
First of all, you have to accept a strong framework lock-in: you won't be able to reuse your JavaScript code without it. Each model or view is generated by the framework's routines, starting from plain old objects containing configuration in the form of hooks and methods:
window.Todo = Backbone.Model.extend({ defaults: function() { return { done: false, order: Todos.nextOrder() }; }, toggle: function() { this.save({done: !this.get("done")}); } });
In general, we are at a level of architecture corresponding to the first generation of server-side frameworks: persistence based on Active Record and hard dependency towards the framework's code:
window.TodoList = Backbone.Collection.extend({ model: Todo, localStorage: new Store("todos"), ...
For example, models directly reference the persistence mechanism (at least the collection ones) in order to store the user's manipulation. You cannot test or reuse your code without Backbone.js and its dependencies.
Of course, this coupling is present probably in all JavaScript frameworks more complex than jQuery, and that aim to manage the whole chain of events; the framework jumps in from the user's click to the request to the server side, like in the case of Ext JS. We are still in the "get things done quickly" phase, instead of in the "work smarter" one.
Coupling is a trade-off you make with functionality available out of the box: these kind of frameworks seems all-powerful, but you will never be able to replace them in the future after adoption.
Resources
Usually I code up a self-contained example when I explore a new tool, but this time there are already example, both real-world and didactical ones.
- The annotated source of a very simple application, which stores a list of TODO locally in the browser (in HTML5's localStorage).
- The same application at work.
- The list of all examples, which include mobile versions of Basecamp (37Signals) and LinkedIn, and Pandora. BitTorrent even used Backbone for the user interface of a Win32 application.
- The FAQ.
- Some beginner tutorials on Backbone, just to see code from a different source.
Opinions expressed by DZone contributors are their own.
Comments