If you have spent any time looking at Backbone.js, like many others, you are probably amazed by how lightweight, flexible and elegant it is. Backbone.js is incredibly powerful, but not prescriptive in how it should be used. With great power comes great responsibility, and if you’ve tried to use Backbone.js for a large project you might be asking yourself: how do I organize my code?
When thinking about “code organization” the questions you might be asking are:
All good questions! Is there an accepted answer? Nope.
Having said all this, let’s dive into some of the details. First, you need to put your files somewhere on your file system. The physical layout is an important question often overlooked, but the days of “all code in a single file” are over, folks.
Here’s how you might layout your application structure:
. ├── assets │ ├── css │ │ └── main.css │ ├── images │ │ └── header.gif │ └── js │ └── libs │ ├── backbone.js │ ├── jquery.js │ └── underscore.js ├── index.html └── src ├── application.js └── modules ├── friend.js └── message.js
Your application code should be under its own directory, such as a
src directory. To enable a single point of entry,
you should have a single file responsible for initializing the application (perhaps firing on DOM ready?) That file
may also contain utility and helper methods, or those may live in their own util.js or helper.js respectively.
The rest of your application code should be divided into modules that can live under their own
A module is an encapsulated group of structures (for the purposes of our post, Backbone structures) that work cohesively
to provide a subset of functionality in your application.
Your index file should import libraries in the following order:
Your Application.js has several important roles. It serves as the entry point for your application by doing the following three things:
It defines the namespace of your application. For example, if your chat client application is called FireTalkChat, your namespace might be
chat. All your application source should live under chat to prevent any collisions with other libraries.
When referencing a module anywhere in your code, you need to make sure that those references all point to a single shared object. There are several ways to do that:
First, a namespace object can be created underneath which each property serves as a “module”.
While this method works (and is the simplest way to start organizing your code,) there are several drawbacks to this approach. Each time a new module is added, the original “namespace” object needs to be updated with a new property. Additionally, the initialization is repetitive in this case, especially if we know each of our modules should have the same base structure. Lastly and most importantly, calling
chat.friend = null, will obliterate your friend module. While modules should be in a mutable state, they should not be exposed in a way that will allow for their overwriting.
To address these issues you can create a reusable function that can retrieve the shared object reference when called. This function will create the shared object and “remember” it internally in connection with a key. This technique is called Memoizing. This way, every subsequent call will return the same object. By creating a closure around the module’s objects, you guarantee that it can’t be tampered with, and create a private scope for your module where you can define module-specific data.
3. Last but not least, this file defines the DOM ready callback. Once all the scripts are loaded, this function will execute and can initialize your application.
After having written your application.js, you’re ready to begin writing your modules. The modules should be named in a way that describes their intended purpose, for example:
When asking yourself whether to create single or multiple files to contain your modules, keep in mind that for development purposes, having multiple files is cleaner. However, that requires paying special attention to load order and having a build tool that can combine all the files for your production environment as downloading many files can bottleneck a page load.
Defining your module using the above memoizing technique requires the following steps:
Create an immediately invoked function expression (IIFE) to create a module-specific scope:
Define your dependencies at the top of the module, so that they are all grouped in a single location. Make sure to include the script tags for any dependencies before the script tag of the module that requires them. This is also a good opportunity to shorthand any application references that would be long otherwise.
3.Define the Backbone structures contained within your module. Note that you shouldn’t use the “new” keyword when referencing other modules as they might not have loaded yet. Save all the code that must run on page load for the jQuery ready function in your application.js.
While there are many approaches to this, we found this to be a useful set of guidelines to work within. Given that the conversation about organizing your Backbone.js code is flourishing in the community, we’d love to hear your thoughts about this approach.
This post focused on the foundations of code organization, but given Backbone’s flexible nature, there are many best-practices we could tackle, such as build process, subrouting, stubbing etc. Stay tuned for additional posts and if you are interested in diving deeper, find out more about our “Building Web Applications with Backbone.js” training here: https://bocoup.com/education/classes/building-web-applications-with-backbone/