JavaScript MVC or MVVM?

Reprint courtesy of Jeff Deville

BackboneJS is not the best option for MVC in the browser

UPDATE – Sept 4, 2011
Most of the negative feedback I’ve seen regarding knockout had to do w/ the verbosity of the data binding expressions.  Many times, that was because users didn’t create helper methods, but the criticism was not without grounds.  Enter Knockout 1.3, which should have been named Knockout 10, for all the features Steve has packed in.  I won’t even summarize it, because the blog posts explains everything extremely well, including code examples.

I’ve been doing a lot of research into javascript mvc frameworks and microframeworks lately, and I seem to have reached some different conclusions about what the best options out there are.  I’ll walk through the MVC / MVVM model, and go through the various choices I’ve evaluated, and why I’ve gone the way I have.

Views & View Models

There are 2 main competitors here, and they have a very different philosophy.
Backbone brings all of your view logic into special classes.  This includes wiring your your DOM events, defining tag names and templates, and optionally even rendering the views using string concatenation.  This is where you’re code will include a lot of $(“…”).  This feels a bit foreign to me.  In server-side MVC frameworks, you bind your data inline inside of the views themselves.  So long as you don’t require anything more complicated than an if statement, I think this works fine.  Pulling all of that logic out gives development an unnecessarily disjointed feel, in my opinion.
Knockout takes a very different approach.  Knockout has created observable wrappers that fire events anytime their target values change.  It’s coupled these wrappers with data-binding expressions that are integrated into the HTML of your page itself.  The end result is that the data bindings are ‘live’.  You can simply work against the data in your viewmodel at that point, and no jquery ever intrudes on your code.  There are several advantages:

  1. The DOM-less nature of your code makes it easier to write independent of your views.
  2. Unit testing your code is a lot easier as well.  (I highly recommend Jasmine BDD)
  3. What’s more, the overall code involved in writing something with Knockout is going to be a lower than in Backbone, because the view logic is more succinctly captured in the data binding expressions.

Winner: Knockout (and by knockout.  This one isn’t even close)

Controller (Routing)

Backbone: I merged these two topics simply because Backbone’s controller is where routing takes place.  Personally, I don’t feel like this is a proper separation of concerns.  More on that shortly.
Briefly though, let me say that routing is exactly what it sounds like.  It maps urls to controller actions.  Since you’re on the client, the portion of the url we’re talking about is what’s after the hash tag.  This is probably new to a lot of client-side developers.  What does it buy you?  History support in the browser.  Slick.
I mentioned that I was not a big fan of how Backbone integrated routing into the controllers themselves.  There are a few reasons.

  1. I’m not sure why, but all of the walk-through backbone apps save the models directly from the views.  This is a huge no-no, exacerbated by the lack of ViewModel support.  I don’t think there’s any reason that you couldn’t have the view alert your controller that a save was required, but I think the walkthrough’s should be updated so as not to muddy the separation between views and controllers.
  2. Routing simply isn’t a controller responsibility.  I haven’t tried, but I’m not sure what happens if you need multiple controllers on a page.  Regardless, it’s not a very clean SoC, and there is a better option…

PathJS externalizes your routing from your controller and lets you define routes external to your controllers.  There are some really cool advantages to this.

  1. AoP:  With PathJS, I define my routes outside of my Controllers, and can set before-/after- triggers.  This can be really helpful for things like logging.  I integrated Google Analytics into my javascript MVC app trivially with the capability.  It’s a great solution for orthogonally dividing responsibilities.
  2. I can have as many controllers as I want, and define my routes in one location to trigger all of them.

So PathJS is not a controller, which may seem misleading.  That said, a controller is really just a collection/namespace of related actions anyway.

Winner: PathJS

This, in my mind, is where Backbone really shines.  They’ve created a conventions-based way of handling persistence to your underlying server.  It isn’t flexible, but like Rails, if you can adhere to the standards, you get to skip a lot of verbose, repetitive, error-prone persistence logic.  I didn’t really find any competitors to Backbone here other than rolling your own, but it seemed to handle things quite capably.

Winner: Backbone

I haven’t had any trouble picking the pieces of the different frameworks out that I want, and I really commend Backbone for their fantastic documentation.  It shows the framework code, and a detailed description of exactly what it’s doing.  They do the same thing with their walk-throughs, and it makes understanding the framework and concepts very straightforward.