Having spent the last 18 months or so working with Backbone.js, I’ve formed the following opinion: Backbone is not enough for building large single-page applications (SPAs).
Sure, you and your team may be able to get your app across the line, but you’ll probably end up with a lot of code and may even reinvent a couple of wheels unless you’re extremely diligent about refactoring, code reviews, documentation, testing and keeping up with an ever-evolving suite of best-practices.
This was not an easy conclusion for me to reach: I’ve put a bit of effort into learning the ins and outs of Backbone. And I don’t consider myself particularly adventurous when it comes to technology choices.
For example, if you were to ask me right now to pick a framework to build a traditional web app, I’d still choose Rails over something sexy like Node. But if you were to ask me to pick a framework to build a single-page app, I’d be very circumspect about choosing Backbone and would be taking a serious look at Angular and Ember.
It’s Not Backbone’s Fault
As Thoughtworks put it in last October’s Technology Radar, Backbone is an ‘example of an abstraction pushed too far’. I don’t think this is a criticism of Backbone itself – it doesn’t aspire to be anything more than a lightweight library. But people are pushing Backbone too far and in doing so, ignoring decades of prior experience building rich clients.
How Hard Can It Be?
Well, as it turns out, it’s kinda hard. This is because building a single-page app has more in common with frameworks like Cocoa, Flex and Swing than it does with traditional request-response web app development – a fact that many web developers are unprepared for.
When you pick a library like Backbone for a large SPA, sticky questions quickly arise. For example:
- How do I structure nested views and controllers? This is usually the first question I get asked by beginners. And I can honestly say after all this time: I don’t know – I’d have to do it myself for your particular use-case and then get back to you.
- How do I test my views? Backbone hasn’t got testing baked into it, so you have to piece together testing yourself. For views, this is hard – so hard that many people don’t bother to do it.
- Why is my app leaking memory? In SPAs, objects can hang around for a long time, rather than being recreated on a page refresh. This can be really useful, but also means that you have to make sure those objects that are not actually being used don’t take up memory.
- Why is my rendering so slow? With Backbone, it’s really easy to make many small updates to the DOM for a single user interaction. For large data sets, this lead to a poor user experience.
There are many Backbone plugins, frameworks and techniques for dealing with these sorts of things, but I’m not sure there’s much point trying to take things much further with Backbone, because out-of-the-box it doesn’t do one thing that I think is critical to building large-scale SPAs – automatic two-way data bindings.
Bind All The Things, All The Time
If there’s one piece of advice I would want to give people building a new single-page application it would be this: bind all the things, all the time.
Automatic data-bindings give you a way to tell the framework to automatically update the view whenever a model (or a collection of models) changes.
Bindings are important because they take care of the biggest day-to-day concern you’ll have when building a single-page app: automatically keeping your models and collections in sync with the DOM. You don’t have to make sure that your view updates in response to a model change – it just does.
With Backbone, you have to set these links up yourself, and everybody does it slightly differently, often with (at least at first) little consideration for performance.
There are binding plugins for Backbone, but I believe that bindings must be core to a framework because how they are implemented affects rendering performance and memory usage – they’re not something that can just be bolted on later if you want your app to perform. Concepts like run loops and digest cycles have to be put in place. That’s why I consider frameworks like Angular and Ember to be the way of the future.
But say you don’t care about performance: let’s get back to the code.
The Backbone implementation has around twice the code of the Ember and Angular implementations. Furthermore, I believe this discrepancy will hold for much larger apps. This is a problem because from the perspective of documentation, testing and defects, less code = good, and more code = bad.
In short, with Backbone, it’s easy to end up write lots and lots of code, and any meaningful refactoring you do is going to require that you reimplement a lot of the things that Ember and Angular already give you.
Of course, there’s a tradeoff to all of this, and that is that you have to learn to use the particular framework.
Backbone doesn’t have a steep learning curve. The problem, however, is that its curve keeps climbing and climbing as you have to work through all of the things that it doesn’t give you.
Frameworks like Ember and Angular have a much steeper initial learning curve, but once you’re up it, you and your team can produce more functionality with less code, and also be more confident that people much smarter than you and I have already thought long and hard about how to make things performant.
Look before you leap
So if you are thinking about diving into single page application development, think twice before you bet the farm on Backbone. You’ll write a lot of code and, as your app and team size grows, it’ll become harder and harder for anybody to keep it under control. Seriously consider looking at a framework that supports automatic two-way bindings like Ember or Angular. Otherwise, there’s a risk that you’ll just end up reinventing the wheel.