What are the real-world strengths and weaknesses of the many frameworks based on backbone.js?

Most of (all of?) the frameworks that you're looking at solve the same problems, but they do it in slightly different ways with slightly different goals.

I think it's fair to say that all of these projects would solve the problems in these categories:

  • Provide sensible set of defaults
  • Reduce boilerplate code
  • Provide application structure on top of the BackboneJS building blocks
  • Extract patterns that authors use in their apps

Marionette, which I've been building since December of 2011, has a few very distinct goals and ideals in mind, as well:

  • Composite application architecture
  • Enterprise messaging pattern influence
  • Modularization options
  • Incremental use (no all-or-nothing requirement)
  • No server lock-in
  • Make it easy to change those defaults
  • Code as configuration / over configuration

I'm not saying none of the other frameworks have these same goals. But I think Marionette's uniqueness comes from the combination of these goals.

Composite Application Architecture

I spent more than 5 years working in thick-client, distributed software systems using WinForms and C#. I built apps for desktop, laptop (smart-client), mobile devices and web applications, all sharing a core functional set and working with the same server back-end many times. In this time, I learned the value of modularization and very rapidly moved down a path of composite application design.

The basic idea is to "compose" your application's runtime experience and process out of many smaller, individual pieces that don't necessarily know about each other. They register themselves with the overall composite application system and then they communicate through various means of decoupled messages and calls.

I've written a little bit about this on my blog, introducing Marionette as a composite application architecture for Backbone:

  • http://lostechies.com/derickbailey/2011/11/17/introduction-to-composite-javascript-apps/
  • http://lostechies.com/derickbailey/2011/12/12/composite-js-apps-regions-and-region-managers/

Message Queues / Patterns

The same large scale, distributed systems also took advantage of message queuing, enterprise integration patterns (messaging patterns), and service buses to handle the messages. This, more than anything else, had a tremendous influence on my approach to decoupled software development. I began to see single-process, in-memory WinForms applications from this perspective, and soon my server side and web application development took influence from this.

This has directly translated itself in to how I look at Backbone application design. I provide an event aggregator in Marionette, for both the high level Application object, and for each module that you create within the application.

I think about messages that I can send between my modules: command messages, event messages, and more. I also think about the server side communication as messages with these same patterns. Some of the patterns have made their way in to Marionette already, but some haven't yet.

  • http://lostechies.com/derickbailey/2011/07/19/references-routing-and-the-event-aggregator-coordinating-views-in-backbone-js/
  • http://lostechies.com/derickbailey/2012/04/03/revisiting-the-backbone-event-aggregator-lessons-learned/
  • http://lostechies.com/derickbailey/2009/12/23/understanding-the-application-controller-through-object-messaging-patterns/ (WinForms code, but still applicable)

Modularization

Modularization of code is tremendously important. Creating small, well encapsulated packages that have a singular focus with well defined entry and exit points is a must for any system of any significant size and complexity.

Marionette provides modularization directly through it's module definitions. But I also recognize that some people like RequireJS and want to use that. So I provide both a standard build and a RequireJS compatible build.


MyApp = new Backbone.Marionette.Application();

MyApp.module("MyModule", function(MyModule, MyApp, Backbone, Marionette, $, _){

  // your module code goes here

});

(No blog post available for this, yet)

Incremental Use

This is one of the core philosophies that I bake in to every part of Marionette that I can: no "all-or-nothing" requirement for use of Marionette.

Backbone itself takes a very incremental and modular approach with all of it's building block objects. You are free to choose which ones you want to use, when. I strongly believe in this principle and strive to make sure Marionette works the same way.

To that end, the majority of the pieces that I have built in to Marionette are built to stand alone, to work with the core pieces of Backbone, and to work together even better.

For example, nearly every Backbone application needs to dynamically show a Backbone view in a particular place on the screen. The apps also need to handle closing old views and cleaning up memory when a new one is put in place. This is where Marionette's Region comes in to play. A region handles the boilerplate code of taking a view, calling render on it, and stuffing the result in to the DOM for you. Then will close that view and clean it up for you, provided your view has a "close" method on it.


MyApp.addRegions({
  someRegion: "#some-div"
});

MyApp.someRegion.show(new MyView());

But you're not required to use Marionette's views in order to use a region. The only requirement is that you are extending from Backbone.View at some point in the object's prototype chain. If you choose to provide a close method, a onShow method, or others, Marionette's Region will call it for you at the right time.

  • http://lostechies.com/derickbailey/2011/12/12/composite-js-apps-regions-and-region-managers/
  • http://lostechies.com/derickbailey/2011/09/15/zombies-run-managing-page-transitions-in-backbone-apps/

No Server Lock-in

I build Backbone / Marionette apps on top of a wide variety of server technologies:

  • ASP.NET MVC
  • Ruby on Rails
  • Ruby / Sinatra
  • NodeJS / ExpressJS
  • PHP / Slim
  • Java
  • Erlang
  • ... and more

JavaScript is JavaScript, when it comes to running in a browser. Server side JavaScript is awesome, too, but it has zero effect or influence on how I write my browser based JavaScript.

Because of the diversity in projects that I built and back-end technologies that my clients use, I cannot and will not lock Marionette in to a single server side technology stack for any reason. I won't provide a boilerplate project. I won't provide a ruby gem or an npm package. I want people to understand that Marionette doesn't require a specific back-end server. It's browser based JavaScript, and the back-end doesn't matter.

Of course, I fully support other people providing packages for their language and framework. I list those packages in the Wiki and hope that people continue to build more packages as they see a need. But that is community support, not direct support from Marionette.

  • https://github.com/derickbailey/backbone.marionette/wiki/Available-packages

Easily Change The Defaults

In my effort to reduce boilerplate code and provide sensible defaults (which is an idea that I directly "borrowed" from Tim Branyen's LayoutManager), I recognize the need for other developers to use slightly different implementations than I do.

I provide rendering based on inline <script> tags for templates, using Underscore.js templating by default. But you can replace this by changing the Renderer and/or TempalteCache objects in Marionette. These two objects provide the core of the rendering capabilities, and there are wiki pages that show how to change this out for specific templating engines and different ways of loading templates.

With v0.9 of Marionette, it gets even easier. For example, if you want to replace the use of inline template script blocks with pre-compiled templates, you only have to replace one method on the Renderer:


Backbone.Marionette.Renderer.render = function(template, data){
  return template(data);
};

and now the entire application will use pre-compiled templates that you attach to your view's template attribute.

I even provide a Marionette.Async add-on with v0.9 that allows you to support asynchronously rendering views. I continuously strive to make it as easy as possible to replace the default behaviors in Marionette.

Code As Configuration

I'm a fan of "convention over configuration" in certain contexts. It is a powerful way of getting things done, and Marionette provides a little bit of this - though not too much, honestly. Many other frameworks - especially LayoutManager - provide more convention over configuration than Marionette does.

This is done with purpose and intent.

I've built enough JavaScript plugins, frameworks, add-ons and applications to know the pain of trying to get conventions to work in a meaningful and fast way. It can be done with speed, but usually at the cost of being able to change it.

To that end, I take a "code as configuration" approach to Marionette. I don't provide a lot of "configuration" APIs where you can provide an object literal with static values that change a swath of behaviors. Instead, I document the methods that each object has - both through annotated source code and through the actual API documentation - with the intent of telling you how to change Marionette to work the way you want.

By providing a clean and clear API for the Marionette objects, I create a situation where replacing the behavior of a specific object or Marionette as a whole is relatively simple and very flexible. I sacrifice the "simple" configuration API calls for the flexibility of providing your own code to make things work in the way that you want.

You won't find a "configure" or "options" API in Marionette. But you will find a large number of methods that each serve a very specific purpose, with clean signatures, that make it easy to change how Marionette works.


I'm currently using backbone with the layout manager module and handlebars as templating engine and I found really easy to set up a little application using an already existing Grails backend. Before starting using layout manager I read about Marionette and Chaplin and both seemed to me really powerful but complex. Then I remembered why I originally choosed backbone.js: simplicity. All those frameworks are adding what backbone has left out by design. I'm not saying that a framework is bad, but if I need something more complex I'll try other projects, like ember.js or sproutcore, since they have a unique codebase, written with a goal in the mind of their developers. Here we have frameworks on top of another one. Of course, backbone is a backbone not only for building applications, but also for writing some more powerful library, but the only thing I think is really poor with it is the view layer, since is missing a layout manager and the possibility of nesting views. With layout manager that gap is filled quite well.

So, my answer to your question is: start from using backbone as is, and ask yourself what is missing and what were your expectations about the framework. If you find there are too many things left out by backbone, then go and search for them in the other frameworks and choose the one is nearest your needs. And If you are still not confident in the choice, maybe backbone is not for you and you have to look some other solution (ember.js, sproutcore, ExtJs, JavaScript MVC are all good). If you have experience in writing client apps, you don't really need experience on all the framework out there to choose the right one (for you, of course)


I have studied the various frameworks build with Backbone.js and built the Vertebrae for a project at HauteLook. The project goals included... dynamic script loading, AMD module format, dependency management, build with mostly open source libraries, organize code in packages, optimize and build for one or many single page apps, host on fully cached server, e.g. no server-side scripting using only an API for data, and the funnest for me, use behaviour driven development for the project. There is a description on the project at : http://www.hautelooktech.com/2012/05/24/vertebrae-front-end-framework-built-with-backbone-js-and-requirejs-using-amd/

Our Problem:

Selected libraries (jQuery, Underscore.js, Backbone.js, RequireJS, Mustache) provide module loading, dependency management, application structure (for models, collections, views and routes), asynchronous interactions with API, various utilities and objects to manage asynchronous behaviors, e.g. (Promises) Deferreds, Callbacks. The remaining logic needed to complete the framework includes:

  • an object (model) to manage state of the single-page application;
  • a layout manager to present, arrange/transition and clear views, and
  • controllers which respond to routes, get/set application state, and hand off work to layout manager.

Our Solutions (implemented in Vertebrae):

Application State Manager -

The application manager stores data in memory and also persists data in browser storage to provide a resource for common data/metadata. Also provides data (state) to reconstruct the page views based on previous interactions (e.g. selected tab, applied filters). The application state manager provides a strategy for resources to retrieve state. Meant to act as a state machine.

Layout Manager -

The layout manager has one or many views as well as document (DOM) destinations for each (rendered) view. A page may transition between many views, so the layout manager keeps track of view states, e.g. rendered, not-rendered, displayed, not-displayed. You may use the layout manager to lazy load and render (detached) views that a site visitor is very likely to request, e.g. tab changes on a page. The transition between view states is managed by this object. An entire layout may be cleared so that view objects and their bindings are removed, preparing these objects for garbage collection (preventing memory leaks). The layout manager also communicates view state with controller(s).

Controller -

A controller object is called by a route handler function, and is responsible for getting relevant state (application models) to generate a page (layout), (also responsible for setting state when routes change). The controller passes dependent data (models/collections) and constructed view objects for a requested page to the layout manager. As a side-effect the use of controllers prevents the routes object from becoming bloated and tangled. A route should map to a controller which then kicks off the page view, keeping the route handling functions lean.

The Todos app is hosted both in dev mode and optimized on Heroku...

  • http://vertebrae-framework.herokuapp.com/
  • http://vertebrae-optimized.herokuapp.com/

Many of the concepts in the other frameworks are borrowed, e.g. the need to destory views to preview memory leaks as pointed out by Derick Bailey - http://lostechies.com/derickbailey/ ; the Layout Manager by Tim Branyen http://tbranyen.github.com/backbone.layoutmanager/

In summary, Backbone.js is meant to be a tool in your application the Backbone.js library does not provide all the architecture you will need to build an application, but does provide great interactions with an API and solid code structure for... Views (act like controllers too) and your data layer Models and Collections, and finally Routes. We built Vertebrae to meat the goals of our project, and decided to extract the code as a framework for others to use, learn, or whatever.

The answer to your question in my opinion is to learn from all the frameworks and use what you need to meet your goals, if you find that your project goals fit closely with one of the frameworks built with Backbone then great, otherwise built your own framework there are great examples being shared by the community. Or if you find yourself a bit lost in the direction of your application then choose something more opinionated and structured perhaps Ember.js. The great thing is there are a good assortment of choices to help you code using an (MVX) MVC like pattern with JavaScript.