5 Ways to Level-Up Your Backbone.js Code

Backbone.js is nearing five years old, and yet it remains my framework of choice for client-side MVC applications. Its light footprint and easy extensibility have allowed it to adapt to changing best practices over the years.

Here are five strategies—compiled from Backbone’s router, view engine, and core classes—that can level-up your code and help you get the most out of the framework.

1. Define Class Methods the Right Way

One little known fact is that Backbone accepts class methods as the second argument when extending any of its classes.

To review, class methods are useful when:

You need to write logic tied to a specific domain model, and That logic doesn’t involve an instance of that class

For example, a Car class might have instance methods to return a car’s manufacturer, year, and color. But if you want a list of all manufacturers in a certain country, it doesn’t make sense to operate on a specific car instance.

A common way to add class methods in Backbone is the following:

// anti-pattern
var Car = Backbone.Model.extend({});
Car.manufacturersByCountry = function(country) {
	// custom logic to query manufacturers
}

Here, the extra statement is unnecessary. Backbone accepts class methods as the second argument when extending any of its classes:

var Car = Backbone.Model.extend({
  // instance methods

}, {
  // class methods

  manufacturersByCountry: function(country) {
	// custom logic to query manufacturers
  }
});

2. Preserve Backbone Functionality When Overriding Lifecycle Methods

Sometimes you need to override a core Backbone method, like fetch or initialize. In these instances, you usually want to perform your own actions, while still preserve the underlying mechanics of the native Backbone methods.

To do this, call Backbone.View.prototype.initialize.call(this) after your custom code:

var Car = Backbone.Model.extend({
	initialize: function() {
		// my custom stuff
		// ..
		// ..

		Backbone.View.prototype.initialize.call(this);
	}
});

This code calls the original prototype’s method initialize, with your current this set as its context.

3. Make Private Methods Actually Private with Local Scoping

This one is not Backbone specific, but applies to JavaScript modules in general.

It’s common to denote a private method in JavaScript with a leading underscore. A method called _persistAuth is understood to be an internal utility, not to be called outside that module.

For example:

var Session = Backbone.Model.extend({
	_persistAuth: function() {
		// sensitive auth code
	}
});

module.exports = Session;

If you mean that to be private, then it’s important to actually enforce it as such. In the code above _persistAuth() is a public method since any instance of session can call the method directly.

You can turn off outside access to a function by making it a local variable:

var persistAuth = function() {
	// sensitive auth code
};

var Session = Backbone.Model.extend({
	initialize: function() {
		// setup code
		// …
		if (this.isValid()) {
			persistAuth.call(this)
		}
		
	}
});

module.exports = Session;

Any consumer of that module will no longer have direct access to persistAuth directly since you’re no longer exposing it. This gets rid of the pseudo-private underscored method names and enforces a thoughtful public API for your class.

4. Play to Backbone’s Strengths

Backbone is a powerful framework for managing models and syncing with a RESTful service, but it’s not the best when it comes to view rendering. Backbone’s .render() method does not perform model diffing to determine which DOM nodes it needs to update; it simply re-renders the entire view.

Newer view frameworks like React offer greater efficiency in this area due to their sophisticated state management that connects model properties (or more specifically: state and props) with their specific DOM nodes. This means that when you update a user’s name, React only renders the DOM node containing that name, not the whole view that represents that user model.

Fortunately, you can pick and choose what Backbone components you want to use. You’re never stuck with the whole suite if it doesn’t fit your specific needs.

This enables you to choose a view framework of your choice while keeping Backbone’s solid model, syncing, and routing mechanisms. React sits nicely on top of a Backbone view to handle all of its DOM manipulation and event delegation.

Here’s an example of how to plug React into Backbone:

var UserView = Backbone.View.extend({
  render: function() {
    React.renderComponent(new UserComponent(), this.el);
    return this;
  }
});

5. Keep Your Router Tidy with backbone-route-control

It’s easy for a Backbone router file to become a project’s junk drawer. Since it’s often the place you fetch data, set up collections, and instantiate views, the file often becomes unwieldy. backbone-route-control, a module by Brent Ertz, enables a cleaner and more RESTful approach to the Backbone router.

The module extends Backbone’s router to enable Rails-style routes, in which you specify a controller and an action for each route:

var Router = BackboneRouteControl.extend({
  routes: {
    users:		users#index,
    users/:id:		users#show,
    users/:id/edit:	users#edit
  }  
});

var myRouter = new Router({
  controllers: {
    users: new UsersController()
  }
});

When a visitor hits any of those routes, backbone-route-control will look for the users controller you passed in when calling new Router().

Now you can define all your user routes in that one controller file:

var UsersController = function() {
  return {
    index: function() {
	...
    },
    show: function(id) {
	...
    },
    edit: function(id) {
	...
    }    
  };
};

Note how the route parameter (the user ID) is passed through to each controller action. This approach to routing enforces separation of concerns and, in my experience, results in clean implementations that are easy to understand and pass off to other developers.

Conclusion

The methods above represent improvements to the many different components that make up a Backbone app. These small tweaks to the router, the view engine, and the core Backbone classes are just five of the many reasons why Backbone is my client-side framework of choice.

P.S. What are some tips you’ve learned as a Backbone developer? Let us know in the comments!

About David Aragon

David is a software engineer at Quick Left in Boulder, Colorado. He has extensive experience building and scaling applications of all types. Most of his work is in Node, Ruby on Rails, JS frameworks like Backbone and React, and recently iOS and Swift. In May he graduates from the University of Colorado with a Master’s in Computer Science. David has spoken at conferences nationally and internationally, most recently at JSDay in Verona, Italy. He values working with beginner developers and has enjoyed leading trainings on frameworks like Rails and Backbone.