BT

Contrasting Backbone and Angular

Posted by Victor Savkin on Nov 26, 2013 |

Contrasting ideas and tools is a great way to understand them better.

In this article I will go down the list of the things we have to deal with day to day when building web applications, and show how Backbone and Angular can help with each of them.

What We are Trying to Solve

Most of the things we do as web developers fall into one of the following categories:

  • Implementing business logic

  • Constructing the DOM

  • Implementing view logic (declarative and imperative)

  • Syncing up the model and view

  • Managing complex UI interactions

  • Managing state and routing

  • Creating and wiring up components

Not surprisingly most client-side frameworks address these in one way or another.

Backbone

Let's start by looking at what Backbone gives us to solve these problems.

Business Logic

Backbone Models and Collections

Constructing DOM

Handlebars

Declarative View Logic

Backbone Views

Imperative View Logic

Backbone Views

Sync up Views and Models

StickIt

Managing UI Interactions

JS Objects or Marionette Controllers

Managing State and Routing

Backbone.Router

Creating and Wiring Up Components

Manually

For visual people:

When I Say Backbone...

Comparing vanilla Backbone with Angular would not be fair. So by Backbone I actually mean Backbone + Marionette + add-ons.

Business Logic

A large chunk of the business logic of the application goes into Backbone models and collections. Often these objects correspond to resources on the backend. On top of that, they are used for backing up views.

Having to extend Backbone.Model and Backbone.Collection adds quite a bit of complexity.

First, it separates all domain objects into POJOs and Backbone models. POJOs are used when rendering templates and talking to the server. Backbone models are used when observable properties are needed (e.g., setting up data bindings).

Second, it promotes mutability. Since Backbone does not support observing functions, every computed property has to be reset when any of the source properties changes. This adds a lot of accidental complexity, which results in the code that is hard to understand and test. On top of that, all the dependencies have to be explicitly specified in the form of on("change:sourceProperty, this.recalculateComputedProperty).

Constructing the DOM

Backbone uses template engines to construct the DOM. In theory, you can plug in any engine you want. In practice, though, Mustache and Handlebars are the ones that usually get used for large applications. As a result, templates in Backbone are often logic less and string-based, but they do not have to be.

View Logic

The idea of dividing the view logic into imperative and declarative is an old one (goes back to the original MVC pattern). Event handling configuration and data bindings are declarative. Event handling itself, on the other hand, is imperative. Backbone does not draw a strict line between the two. Both go into Backbone.View.

Syncing Up the Model and View

Due to the minimalist nature of Backbone, there is no built-in support for data bindings. That is not an issue for small projects, where the view can be made responsible for syncing up the model and the DOM. It, however, can get easily out of control when the application grows.

There are several add-ons available (like Backbone.StickIt) that help unload this burden, so you can focus on complex interactions rather than the trivial model-view synchronization. Most of these add-ons are configured using plain JavaScript, which enables building abstractions on top of them matching the needs of your application.

The downside of using data bindings in Backbone is that they depend on observable properties, whereas template engines use POJOs. Having these two ways of working with the DOM often results in code duplication.

Managing Complex UI Interactions

All UI interactions can be split into simple (managed using the Observer Synchronization) and complex (where the Flow Synchronization) is required).

As mentioned above, simple interactions get handled by Backbone.View using data bindings and event handlers. Since Backbone does not have any prescribed solutions for orchestrating complex UI interactions, you are free to choose the one that fits your application the best. Some use Backbone.View, but I recommend against doing that. Backbone.View already does too much. Supervising Presenter is the pattern I tend to use for managing complex interactions.

Managing State and Routing

Backbone comes with a very simple implementation of the router. It provides no support for managing view and the application state. Everything has to be done manually. That is why in practice other libraries (e.g., router.js) are often get used instead of the built-in router.

Creating and Wiring up Components

In Backbone you get the freedom to create and wire up components in the way that fits your application best. The downside is the amount of boilerplate you have to write, in addition to the discipline required to keep the code well organized.

Angular

Now, let's contrast it with how Angular approaches the same problems.

Business Logic

JS objects

Constructing DOM

Directives

Declarative View Logic

Directives

Imperative View Logic

Controllers

Sync up Views and Models

Built-in mechanism

Managing UI Interactions

Controllers

Managing State and Routing

AngularUI Router

Creating and Wiring Up Components

Dependency Injection

For visual people:

Business Logic

Since Angular does not use observable properties, it does not restrict you when it comes to implementing the model. There is no class to extend and no interface to comply to. You are free to use whatever you want (including existing Backbone models). In practice, most developers use plain old JavaScript objects, which yields the following benefits:

  • All domain objects are framework-agnostic, which makes reusing them across applications easier.
  • They are close to the data that is being sent over the wire, which simplifies the client-server communication.
  • They are used to render views, so there is no need to implement toJSON.
  • Computed properties are modeled as functions.

The Template and View

The template in Angular is a piece of the DOM before it gets compiled. During the compilation Angular transforms that DOM subtree and attaches some JavaScript to it. The result of this compilation is another DOM subtree, which is the view. In other words, you do not create the view yourself. Angular does it by compiling the template.

Constructing the DOM

Backbone clearly separates the construction of the DOM from the view logic. The first one is done using a template engine; the second one is done via data bindings and imperative DOM updates. Angular, on the other hand, does not separate the two. It uses the same mechanism, directives, to construct the DOM and define declarative view behavior.

View Logic

Angular, however, draws a line between declarative and imperative view logic. The former is done by the view, and the latter by the controller.

This separation may seem arbitrary, but it is actually quite important.

First of all, it clearly identifies what has to be unit tested. The declarative logic encoded in the template (such as using ng-repeat) does not need tests. Writing tests for the controller, on the other hand, is usually a good idea.

Second, all dependencies go in one direction: from the view to the controller. Thus, the controller is unaware of the view or the DOM. It enables code reuse and simplifies unit testing. Contrast it with Backbone.View that often manipulates DOM nodes and rerenders large parts of it using template engines.

Syncing Up the Model and View

Angular has a built-in support for data bindings, which, in contrast to most client-side frameworks, does not rely on observable properties and, instead, uses dirty checking.

The Angular dirty checking approach has some nice properties:

  • The model is oblivious of the fact that it is being observed.
  • There is no need to specify dependencies between observable properties.
  • Functions are observable as well.

But it also has some drawbacks:

  • When integrating third-party components or libraries, you have to make sure that Angular sees the changes those make to your models.
  • In some situations it can have a negative effect on performance.

Managing Complex UI Interactions

As already mentioned, the controller is responsible for implementing the imperative logic of UI elements. On top of that, it can be used as a Supervising Presenter to coordinate complex UI interactions.

Managing State and Routing

Similar to Backbone, the built-in router in Angular is very basic and not sufficient for building real applications. Thankfully, there is the AngularUI Router project. It manages the application state, views, and supports nesting. In other words, it does everything you would expect from the router. But you are not limited to it. As with Backbone, other routing libraries (e.g., router.js) can be used as well.

Creating and Wiring up Components

Angular has an IoC container, which, like dependency injection in general, forces you to write modular code. It improves reuse, testability, and helps get rid of a lot of boilerplate. The downside is increased complexity and reduced control over how components get created.

Summing Up

That was a short overview of how Backbone and Angular address the main problems we deal with everyday when building web applications. The two frameworks have very different solutions to some of these problems. Backbone gives you more options when it comes to rendering templates, setting up data bindings, or wiring up components. Angular, on the other hand, has prescribed solutions for these problems, but is less opinionated when it comes to how you build your models or controllers.

About the Author

Victor Savkin is a software engineer at Nulogy. He is interested in functional programming, the web platform, and Domain Driven Design. He works on large applications written in JavaScript. Being a language nerd he spends a lot of his time playing with Smalltalk, JS, Dart, Scala, Haskell, Clojure, and Ioke. He blogs about building large applications in Ruby and JS at victorsavkin.com. You can follow Victor on Twitter @victorsavkin.

Hello stranger!

You need to Register an InfoQ account or to post comments. But there's so much more behind being registered.

Get the most out of the InfoQ experience.

Tell us what you think

Allowed html: a,b,br,blockquote,i,li,pre,u,ul,p

Email me replies to any of my messages in this thread

Good article also comparing the two by Adam Buggia

Conclusions? by Arturo Hernandez

Backbone like the name suggests, was attempting to not get in the way by doing less but very well. It is a good starting point. For simple applications the ideas may still apply. Syncing the view with the model, is actually part of managing the state of your app. Angular provides much better tools to manage the state of your app, with more declarative style programming. Directives extend HTML, so you can create a <date ng-model="mydate"> custom tag. They also better connect the model (state) changes with the DOM changes. Angular also provides testing support via IoC.

Application development is unpredictable, Linux started off as a play OS. So it is hard not to choose a tool that will scale like Angular does. But there are exceptions where a smaller application could stay small and be well served by backbone.

vs Sencha by Chris Dawes

Would be great to see a comparison of Sencha frameworks and angular for larger apps. It seems to have all of the above (Arturo's comment+article) for MVC (and MVVM and MVP and width DeftJS IoC)... would be an interesting comparison.

How about tests by Denilson Telaroli da Silva

A good and mandatory comparation is the test engine.

Re: vs Sencha by Nicholas Boll

I've recently worked with both ExtJS + DeftJS as well AngularJS. I have not used Sencha Touch. Some quick observations:
ExtJS + DeftJS weighs about 2.5 MB including CSS and images while AngularJS core is around 100KB and around 250KB with a UI library. So Angular uses less code.
ExtJS uses a structured classical inheritance for DRY as well as mixins, plugins, and configs (classical OOP) while Angular uses services built as JavaScript functions (i.e JavaScript).
ExtJS abstracts HTML from you while Angular embraces it
DeftJS gets promises wrong (wraps thrown errors and immediately calls resolved promises instead of next tick) while Angular doesn't
DeftJS views are imperative while AngularJS directives are declarative
DeftJS ties a view to a controller (controller in a view config does not work) while AngularJS allows controllers to be bound declaratively in any view
ExtJS doesn't have binding while AngularJS does with JavaScript objects and functions

AngularJS makes development easier, faster and with far less code that does ExtJS + DeftJS. DeftJS adds a lot to ExtJS, but is limited by the class life-cycle in ExtJS (cannot provide a controller as a config to a view). And DeftJS drives me crazy with wrapping promise resolution in a try-catch block - making simple user errors difficult to track down. AngularJS is much easier to re-use components since UI behavior is wrapped up in small and intuitive directives.

ExtJS is powerful, but is a behemoth framework geared for app developers who are more familiar with Java and who don't want to mess with any HTML or CSS - it was built for a time when Web Applications were new and not well understood. AngularJS is a framework built for front-end web developers who know HTML, JS and CSS and can do wonderful things.

For large applications, both have advantages and disadvantages.

ExtJS scales well with the more complexity - the structure helps keep the codebase maintainable and allows many developers to work with minimal conflicts. But since ExtJS doesn't have native binding, there is a lot more code to keep the view in sync, which means many defects filed and a lot of time wasted keeping the view performant and in sync due to edge cases.

AngularJS is more difficult to scale and requires careful architecture to do so. Angular can also have scaling issues do to limitations of its dirty checking used for binding. If architecture and scoping is done properly, AngularJS is pretty easy to maintain through its modular approach and forcing separation of concerns. Bindings keeps the view and model in sync and avoids defects and edge cases related to data changes.

Overall I would recommend giving Angular a try. It is wicked fast for prototyping and maintainable through re-usable and extendible components (Like adding a sorting directive through ui-sortable).

Allowed html: a,b,br,blockquote,i,li,pre,u,ul,p

Email me replies to any of my messages in this thread

Allowed html: a,b,br,blockquote,i,li,pre,u,ul,p

Email me replies to any of my messages in this thread

5 Discuss

Educational Content

General Feedback
Bugs
Advertising
Editorial
InfoQ.com and all content copyright © 2006-2013 C4Media Inc. InfoQ.com hosted at Contegix, the best ISP we've ever worked with.
Privacy policy
BT