3 Stages Of A Backbone Application’s Startup

Most Backbone application examples that you find on the web are very small and very simple. They tend to use a very simple idea of an application “init” method to start up a router and have the router kick off the real application code. I find this path to be very constraining, though. For the most basic of applications it works perfectly fine, but when you get in to anything of any real size and complexity, it becomes difficult to work with.

My Backbone.Marionette add-on helps to alleviate this problem by introducing the idea of application initializer callbacks. I’ve talked about these before, and I use them quite extensively in my applications. It really helps to keep my code clean and separated. And I recently realized that there’s an unintended benefit to using initializers like this: explicitly identifying the different stages of starting an application.

The 3 Stages

The three stages that I have identified in my own applications are (in order):

  1. The Application’s Foundation
  2. The Application’s Initialization
  3. A Contextual Start (optional)

Honestly, I could break this down in to a significantly larger number of stages if I really wanted to get fine-grained and detailed. More specifically, it’s the 2nd stage that can be broken down in to pre-initialization, initialization, and post-initialization. But I think as a general place to start, identifying 3 primary stages for an application’s startup is a good idea. It gives us a better understanding of what code should go where, helps us keep our code clean, improves re-usability and flexibility, and will likely help us scale our apps as well.

Stage 1: The Application’s Foundation

Consider this to be the stage where the browser is simply grabbing all of the specified resources from the server and running through the first pass of parsing the HTML, laying out what the static HTML has provided, styling it with the basic CSS definitions, displaying any images and text from the static HTML, and parsing the JavaScript files so it can get ready to run them. I’ve never seen an HTML application that didn’t have this stage in it, because without it, your browser doesn’t have anything to do or show.

This is the one step the everyone does, and does well.

Stage 2: The Application’s Initialization

Every application has an initialization stage. Some are more elaborate than others. At times you can get away with the over-simplified “app” object with an “init” method on it, like many of the sample apps and boilerplate codes will suggest:

App = {
  init: function(){
    // app initialization and startup goes here
  }
}

App.init();

But when you get in to an application of any significant size and complexity, the single “init” method becomes a junk drawer where you tend to throw code because you haven’t yet identified where it should belong. Using a series of small initializer functions for each area of your application will help to alleviate this problem, as I’ve mentioned before. But the real question is:

What goes in the initializers?

Initializers are the bits of code, functionality, data and display that are absolutely required for your app to do it’s job, no matter what part of the application the user is trying to load up and use. They are the bits that must be initialized before the user can do anything meaningful with your application.

If your app has a menu structure generated by Backbone code, and it must always be present in the application, this should be in an initializer. If you’re building a multi-room chat application and you need to list the rooms that the user has favorited in a small block on the screen that is always visible to the user, this should be an initializer. If you’re building an image gallery and you need to load a thumb-nail list of images to show, no matter which image the user is trying to view, this is an initializer.

Other parts of your application code that the user doesn’t directly see may also be contenders for initializers, too. For example, if you have a router that needs to be up and running, the router probably needs to be instantiated inside of an initializer. But – and this is an important but – the routes on that router should not be executed during initialization. Instantiate the router and wait until after initialization has completed to call the “Backbone.history.start()” method, kicking off your route handlers.

Stage 3: A Contextual Start (optional)

I call this stage optional because not every application has a contextual kick off. Sometimes an application only needs initializers. The classic “todo” application is a great example of this. There is no contextual start up for this app. When the application is loaded, it initializes itself with the list of to do items and then it waits for the user to interact with the list.

When a Backbone application uses a router to respond to url pushState or hash fragment changes, though, it does have a contextual starting point. Each route that a user is allowed to bookmark or copy as a direct link will provide the context that our application needs to use, to get the user back to where they want to be. Even if a Backbone app has a router and contextual start, though, it may not be used. If there user hits the root of the application, there may not be any additional code to run for the empty (“”) route. When the user hits a route, though, that route must server up the context and application state that the user expects to see.

The problem that I see in most routed Backbone applications, though, is that they bundle the application initialization with the contextual start. That is, people tend to use the router and it’s callback methods as the sole place to get the application initialized and get the user back to the context of the route that they requested. For trivial applications, this may be fine. The initialization code may be so small that it doesn’t really matter if it’s crammed in to the router. But for any real application with any amount of complexity, this is a bad idea. It couples two very distinct parts of the application startup very tightly, and it can lead to bloated and unmaintainable routers with limited entry points in to the application.

So… what goes in the contextual start, other than just saying route callbacks?

Your route callbacks should be as simple as possible. They shouldn’t initialize your system as a whole. Rather, they should be used to determine the state of the application that the user wishes to see. Therefore, the code that goes in to a route callback should be the smallest amount of code that you can write, to get your application from it’s initial state (the state that it was in when the initializers completed) to the desired state.

In an image gallery application, a user may hit a bookmark that points to a specific image. For example, “#images/4″. The route callback that executes should load the requested image and display it on the screen:

Backbone.Router.extend({
  routes: {
    "image/:id": "imageById"
  },
 
  imageById: function(id){
    var image = imageCollection.get(id);
    App.showImage(image);
  }
});

In a multi-room chat application, a user may hit a bookmark that should take them directly in to a specific chat room. For example, “#backbone”. The route callback that executes should take this room name and call the code that is necessary to enter the chat room.

Chances are this is a fairly involved set of code. You’ll need to load the list of users in the chat room. You’ll need to clear the current chat windows and possibly pre-load recent messages to be displayed. You may also need to change a browser’s websocket event listeners to pick up events for this specific room instead, so that messages for this room can be displayed as they come in.

This is a lot of code to run, and it’s fare more code than should be allowed in a route callback method. It should, then, be encapsulated in an object that is responsible for registering the user as having entered that chat room. This object is then called from the router:

Backbone.Router.extend({
  routes: {
    ":roomname": "chatroom"
  },
 
  chatroom: function(roomname){
    ChatApp.enterRoom(roomname);
  }
});

Furthermore, there’s a high likelihood that the user will be able to enter chat rooms using some interaction on the web page. They may click on a chat room name in their favorite’s list, or they may type in a command like “/join #backbone” in to the chat application’s command area. For any of the the multiple ways to enter a chatroom, the code that is executed should be the same. Having the route callback be as simple and stupid as possible will promote code re-use and allow these three options to be easily implemented. If you only need to call “ChatApp.enterRoom(‘someRoom’)” to enter any room that the user specifies, providing options for how the user enters a room becomes trivial.

Putting It All Together

There are many different ways of stringing these different stages together. There are many different tools that help us to easily create the HTML that we need, include the CSS and JavaScript assets, and kick things off. Some applications are small enough that an initialization step and contextual start step can be combined. Most applications of any significant size, though, should think about separating these in to explicit steps in order to promote better architecture, clean code, and re-use of code.

For me, I’m accomplishing stages 2 and 3 with my Backbone.Marionette add-on. It provides a very clean way to create initializers:

App = new Backbone.Marionette.Application();

App.addInitializer(function(){
  // add some app initialization code, here
});

App.addInitializer(function(){
  // more initialization stuff 
  // for a different part of the app
});

// run all the initializers and start the app
App.start();

At the time of this writing, though, I don’t have an explicit “startup” callback mechanism in place. I have a “start” method on my Marionette.Application object. But right now this really only fires up the initializer callbacks. So, I’m currently using the “initialize:after” event to run my start code. I see this as a problem, though – not of a technical nature, but of a semantic nature. And yes, semantics are important.

App = new Backbone.Marionette.Application();

/* ... initializers go here ... */

// contextual startup
App.on("initialize:after", function(){
  Backbone.history.start();
});

I’m not sure what the new implementation will look like, but it may end up being a “startup” callback method, similar to the initializer methods. The startup callback (or callbacks?) would execute after all of the initialization is done. This will provide a cleaner separation between the two concerns of initialization vs startup. I’ll have to see where this leads me, though, as right now, the majority of what I do for a contextual start is simply call “Backbone.history.start()”, as I showed in the above example.


Post Footer automatically generated by Add Post Footer Plugin for wordpress.

About Derick Bailey

Derick Bailey is an entrepreneur, problem solver (and creator? :P ), software developer, screecaster, writer, blogger, speaker and technology leader in central Texas (north of Austin). He runs SignalLeaf.com - the amazingly awesome podcast audio hosting service that everyone should be using, and WatchMeCode.net where he throws down the JavaScript gauntlets to get you up to speed. He has been a professional software developer since the late 90's, and has been writing code since the late 80's. Find me on twitter: @derickbailey, @mutedsolutions, @backbonejsclass Find me on the web: SignalLeaf, WatchMeCode, Kendo UI blog, MarionetteJS, My Github profile, On Google+.
This entry was posted in Backbone, Javascript, Marionette, Semantics. Bookmark the permalink. Follow any comments here with the RSS feed for this post.
  • Navy92f

    thank you for you article.
    is it right that I “.fetch” my collection in the app init step,and i make a “onReset” call back in my contextual step?
    personById: function(id){  App.persons.onReset(function(collection){    var person = collection.get(id);    App.showPerson(person);  });}

    • http://mutedsolutions.com Derick Bailey

      yeah, that’s what i did for the situation where i wrote the “onReset” code originally. it worked out really well. 

  • Gregg

    Sorry for going kinda off-topic…have you tried KnockbackJS (BackboneJS + KnockoutJS)? If so, what are your thoughts on it? I’m about to give BackboneJS a try but am wondering if it’s best to go straight to KnockbackJS. There are almost too many choices for JS frameworks/libraries! ;)

    • http://mutedsolutions.com Derick Bailey

      I used it in some test scenarios when it was first being developed and really liked what i saw. I haven’t had a chance to use it in a production app, though. But it does bring the best of backbone and knockout together, which is a good thing. I can’t speak to it’s scalability or performance, though.

  • Lars

    Hi Derick

    How do your organize your backbone apps into files and dirs?  Do you use and tool to build/compresss/minify  and/or serve your app with a dev server or anything like that?

    • http://mutedsolutions.com Derick Bailey

      I have another post that covers file / folder organization: http://lostechies.com/derickbailey/2012/02/02/javascript-file-folder-structures-just-pick-one/

      as for minify / compress – depends on the environment. in ASP.NET MVC, I’m using SquishIt. In Rails apps, I’d suggest the Asset Pipeline (or for Rails < 3.1, the Jammit gem). In NodeJS, there are several minifiers available. RequireJS can do that with the addition of the R.js optimizer, too. It largely depends on what tools your using on the back-end, and whether you want to do a build step or a runtime compression. I don't think it makes much difference if it's build or runtime, though. just as long as your using one :)

      • Lars

        Thanks! The problem I have mostly is that I dont have any backend. So I end up using various node.js tools trying to find something that suits for building and pre compressing only.    ”my backends” are just http apis.

  • http://twitter.com/craftbluedev Craft Blue

    I know it’s quite popular, but you might consider linking directly to the github project whenever you reference Marionette for the unfamiliar (or adding a one line explanation of what it does).

    https://github.com/derickbailey/backbone.marionette

  • Gorkem

    Hi,

    Where do you create the router object in the example? Backbone.history.start() doesnt work unless you create a router object.

  • suraj007

    Thanks for the Article . I am making this application for backbone for first time in this company.They are fetching data from server in router and from multiple collections they are setting up the data in model and passing it to view.View does not know about Model .But all this model set up is done in router.So router is far more bulky.This application is done in requirejs .Could you please give an idea that how can i manage the contextual part with requirejs?Thanks in Advance