Snowing Code

Personal notes on software development


Backbone and Knockout- a tale of two frameworks

(Publish date: 17/09/2011)

Recently there's been a lot of talk on knockout.js and backbone.js, two frameworks that provide us with apis of "a clean, extensible foundation on which to build sophisticated UIs without getting lost in a tangle of event handlers" (as the knockout.js homepage states). While a lot of people are saying the two are trying to solve two different problems, it is still rather common to hear both mentioned in the same sentence, and there's a good reason for it I think. Now rather than discussing the difference between the two, I'd like to jump straight into the code and provide my point of view on the subject, but before I do I must say: these ideas, even though I had mulling over them for some time now, I'm not too sure to what extent am I on the spot with them and I would truly appreciate any feedback, critique, questions etc'...

Now let's dig in. Rob Conery has recently published a blog post in which he (rightfuly IMO) rants about knockout tendency to allow code-in-view as one may see in many examples found on the web. Then I stumbled upon a good post by Ryan Niemeyer about how to clean up those knockout views. One of the first examples he gives turns the following bit of view code:

          data-bind="visible: !hiddenFlag()"
          
to:
          data-bind="hidden: hiddenFlag()"
          
Now the code that Ryan uses behind the scene to achieve this is:
          ko.bindingHandlers.hidden = {
            // ... implementation - see Ryan post
          };
          
What makes this the perfect solution is the fact that you get a highly resuable code. This solution is provided as part of knockout extansibility points so that it makes sense to use such a solution when the problem is one that recurrs frequently enough. But what do you do if the case at hand is rather unique and the prospect for reusability is quite low? Does it really make sense to put all these parts of your domain logic inside these extensibility points the api provide? Why not use your model? Well, according to Ryan knockout models tend to get bloated too easily, which is also the reason he provides when discarding a couple of solutions he provides that move code from the view to the model. But then the question that rises is if you have a pattern that fails to provide you a sufficient solution and doesn't do what you need, then you may have come across a smell, something is missing here, maybe another pattern? Enter backbone...

So let's look at how backbone solves one of the problems Ryan discusses. We have a model with a selected or isSelected property and we want to make sure that whenever the property corresponding field on our view gets the focus, selected becomes true and when the field looses focus, selected becomes false and vice versa. the knockout view code looks like that:

          data-bind ="value: name, event: { focus: function() {
          viewModel.selectItem($data); }, blur: function() { viewModel.
          selectItem(null); } }"
          
for Ryan's solution in knockout refer to his blog post. How would we then do that in backbone then? We'll have a model and a view like so:
          SomeModel = Backbone.Model.extend({
            select: function(val){
              // Do whatever you need to do, set the isSelected property or whatever..
              this.trigger("change:selected", val);
            }
          });
          SomeView = Backbone.View.extend({
            model: new SomeModel(),
            events: {
              "focus .myelement": "select",
          	"blur .myelement": "unselect"
            }
            select: function(){
              this.model.select(true);
            },
            unselect: function(){
              this.model.select(false);
            },
            initialize: function(){
              _.bindAll(this, "select", "unselect");
              this.model.bind("change:selected", function(val){
          	  if (val){
          	    $('.myelement').focus();
          	  }
          	  else{
          	    $('.myelement').blur();
          	  }
          	}
            }
          });
          
Ok, so backbone's solution may seem more bloated (10 lines bigger). If the scenario will be repeated, knockout solution will be also much more DRYer. But if the scenario is unique, you get a very nice separation of responsibility- the view object is in charge of changes happening (or supposed to be) on the actual view; the model is responsible only of itself. This feels to me by far more intuitive (esp. for those of us with any kind of MVC experience)- a view object will take care of changes of the actual view, while the model is the data the view represents. Backbone shares the work load between more the model, the view and the collection.

And this leads me to the point I've been driving to throughout this post, which is to put simply backbone and knockout, as so many people have already said, are there to solve two different set of problems altogether. Looking at the code Ryan shows, knockout's api, as I attempted to argue here, was created in order to first and foremost solve the problem of binding the elements on our views to models in the background. And this is also, in my opinion, where knockout may fall short- especially depending what you're trying to solve with it. Backbone boasts an api that is more adapted to build full blown applications, which is why so many people define it as a Model-View-Whatever framework. On the other side, knockout focuses only on the Model and lacks the View-Whatever, hence my assertion that knockout is a model binding framework, and as such accessorizes our applications with model binding only.
On the backbone side of the story things look a bit brighter though. Having the api providing us with all that we need to build our application, all that we need is a just an extensibility point to add some model binding capacity. Now obviously I'm not saying that getting all the capacities of knockout could be easily added to backbone; knockout is an entire framework that specialises in model binding. Still some good efforts have been already put into achieving such a goal by Derick Bailey, and I belieeve that as time goes by his Backbone.ModelBinding add on will get just better and better.

This was my attempt at discussing the difference between the two framework. Hopefully I managed to deliver my train of thought as clearly as possible. Think I'm wrong, that I missed something, that I've oversimplified or misread the difference between the two framework? Feel free to leave me a line and let me know. Looking forward to hearing from you.

blog comments powered by Disqus