Wednesday, May 1, 2013

Logic in templates

Template engines have seen a recent rise in use with the popularization of the MV* model of programming. It's easy to see why, we are no longer writing websites where content is key, but creating dynamic applications where user interaction decides what is on screen. Because of this we don't want to download html from the server every time, instead we want to take our data and put it in a template that we can reuse for the layout. It's an obvious choice and one that works well. However we've started to run in to a bit of a problem, but first a recap on some HTML history:

Event Handlers in HTML

Not so long ago we were writing things like this:

<a href='#' onClick='window.open("http://rhysbrettbowen.com");'>open site</a>

okay, not a good example but that's not the point. The point was that we were littering our HTML with code that only run on an interaction with the element. The issue wasn't the element interaction, it was where we put the actual logic. The issue is that putting actual implementation logic in the HTML gave us a whole other place to hunt for bugs and find where logic was, plus it looked ugly. Sometimes the code you wanted to write had to be more than a few lines long, and things really got bad. It also meant that any change to the implementation logic would have to be changed in the HTML, and changing the HTML may change the behaviour of the page so it meant less people could alter it.

Event Handlers in Scripts

So then we put our event handlers in the scripts. This was great and solved all sorts of problems. It meant that we could get a handle to an element and attach functionality there. This meant we could also change the functionality based on different circumstances. This worked great, while we knew what HTML was on the page. Then we started to get clever and made our pages dynamic.

Event Handlers in Templates


So we started using templates which could have data passed in to them. This meant we had the power to inject data directly in to the DOM before adding it to the page. We also put in functionality in things like data attributes that would declare what functionality an element should have, and all this is a good thing. (Also please note the difference in declaring the functionality, we now declare something on elements but the actual implementation lives in libraries like Knockout or Angular).

Back to the issue at hand

The problem though is that with the ease of using templates we forgot about the bad old days and reintroduced logic in to the template. By logic I mean things like "IF" statements. The issue with IF statements is that they increase code complexity, and they're doing it in the template which is a place that we would like people like designers and other non-professional coders to write. Every time you nest and IF statement you increase the factor of code paths through your code by 2. So if you have 3 IF statements then you suddenly have 2 ^ 3, or 8 different paths your code can take. Because it's logic you should then be writing 8 different tests for your template to get 100% coverage. Do you really want to do that?

So how do we fix it?

The fix is usually quite easy. In most cases you can compute a value and pass it in to the template. This works for things like adding on a class depending on a value. You can use things like rivetsjs to declare your intent in the data attributes in a manner easy enough for a non-professional coder altering the template to understand and use (DSLs like this are great for a while team to learn so they can collaborate together).

In pure OOP there are no IF statements - there is even a website about it. Basically instead of an if statement with two paths you have two different objects. These object share a function name and dependent on which object you call a that function will run. In the case of MV* we've already got objects that come out as DOM, and that is our views (or controls dependent on how you look at it). So all you need to do is write your top view and pass in to it the subview that should be shown in that spot, now dependent on which subview you pass in you will have different things appear in the dom (as they themselves have different templates). The disadvantage to this is no you have a view hierarchy, but if you already have a view manager this should be easy to use. The advantages though are great, you've removed complexity from the templates and what's more you've also broken out the templates in to more logical pieces. Now you can work on those subview templates individually (and I bet they'll increase in complexity over time so you'll be saving yourself a headache).

The other great thing is now there is no logic in the template you shouldn't need to run it any time there is a change in the data. A problem is an if statement may not put some elements in the page, that you'll want to show on the data change, so you would have to re-run the entire template. If you've split out in to a smaller view, you only have to replace the view and the rest of the template can remain untouched. That's a big win not having to re-render DOM and reset all event handlers. Also because you no longer have to re-render the entire DOM you can now use bindings between elements, as those elements won't change.

So just say no to logic in templates.

Wednesday, April 17, 2013

a Library or a Framework?

I've heard this question asked many times: "is it a framework or a library?" and even "what is the difference?". It's quite tricky to differentiate between the two and often the difference doesn't really matter. I've heard a few concerns about using frameworks because they lock you in to their style and way of programming, but this should be seen as a good thing, not a bad one. I'll go over that later, but first - just what is the difference?

The way I like to think of it is that a framework is something you build on (decides structure) and a library is something you build with (has little influence on structure).. It's a simple distinction and one which can get a bit gray or fuzzy. The real reason is that people try to define these projects as one or the other, but what defines them as a library or a framework is how we use them.

The other issue is that we can split frameworks and libraries in to categories. Frameworks tend to span multiple categories and so they are more likely to have an impact on what other tools you can use. Here is a list of categories that libraries/frameworks work on (though it may not be exhaustive):


  • Application Layer (e.g. initialization)
  • Communication (e.g. mediator)
  • Storage (e.g. localstorage)
  • Events
  • DOM
  • UI (widgets)
  • Timing
  • Data (models)
  • Inheritance
  • Animation
and so on. It might be easier to have a look at a few libraries/frameworks and see how they fit in:

jQuery

library. Although using it can litter your code with dollar signs and many people start with it, you can just as easily pull out jQuery, put in vanilla javascript (although it will be longer) and there shouldn't be much worry.

Ember


framework. Try pulling out any ember related code and see how much of an application you have left.

AngularJS


framework. If you have a look on their website they even call it an MVW framework.

Backbone

library or framework. It depends on how you use it. Backbone can be easily added to projects and if you're just using the models then I'd call it a library because they can be easily replaced. However Backbone does also give you an events system and views and give you a way to inherit from from it's view. If you're using all this then it's become a framework because you're using these tools to build your application and they're not so easily replaced (by easily replaced I mean you can go to the backbone specific code in your project and pretty much just replace code at that point).

Closure

library & framework. Closure is a bit different. It has a library full of utility methods that are easily replaced so that part is a library. However it has dependency management and inheritance goog.ui.component which will defined how you structure your application so it's both.

Knockout

library. It gives you data binding which may influence how you structure your application but in no way controls it.

So what do you use? is it a library or a framework? 

Wednesday, April 3, 2013

Backbone at Dataminr

I started working at Dataminr a couple of months ago and I've had to make the switch across from using Closure and PlastronJS to jQuery and Backbone with Backbone.LayoutManager. The switch was frustrating as there was a lot of functionality missing, just rendering a list of items was a pain and the code showed it too. So I set about changing it with Backbone plugins which work extremely well for our situation.

The first change was to change where the logic was executing, there were lists that had all the logic for each child it contained and views were generating their own collections rather than allowing them to be passed in, so to customize there were large parts of code that was essentially a copy of what it extended but for a single line. That was the first thing to change, to push the logic down to where it should go and inject in dependancies. That already cut out a huge amount of code and cleaned things up, but there was still functionality that was copied over across multiple view. The solution? Why not create generalized mixins and have them applied to views, and so Backbone.Advice was born.

Backbone.Advice

Backbone.Advice is based on the advice functional mixin work of Angus Croll. It's made working with views a pleasure and allowed me to cut off huge chunks of code. By having the mixins as functions we could then call more mixins from within a mixin, basically setting up a chain of inheritance (more like a requires) with mixins. So for example we have a mixin that makes a view selectable:

  /**
   * MIXIN
   * adds on a selected paramenter for a view as well as methods to deal with
   * selected state and changes to the state.
   */
  Mixin.view.makeSelectable = function() {

    this.setDefaults({
      selectable: true,
      selected: false,
      select: function(sel) {
        if (!this.isSelectable())
          return;
        var temp = this.selected;
        this.selected = sel === undefined || !!sel;
        if (temp != this.selected) {
          if (this.selected)
            this.onSelect();
          else
            this.onDeselect();
        }
      },
      deselect: function() {
        this.select(false);
      },
      toggleSelect: function() {
        this.select(!this.selected);
      },
      isSelected: function() {
        return this.selected && this.isSelectable();
      },
      isSelectable: function() {
        return this.selectable;
      },
      onSelect: function() {},
      onDeselect: function() {}
    });
  };

Now we can actually build mixins on top of this. For example I might want a click to Select mixin:


  /**
   * MIXIN
   * toggle selection state on click.
   */
  Mixin.view.clickSelect = function() {

    this.mixin(Mixin.view.makeSelectable);

    this.addToObj({
      events: {
        'click': 'onClick'
      }
    });

    this.after('onClick', function(event) {
      if (!document.getSelection().isCollapsed)
        return;
      if (this.selectableElement(event.target))
        this.toggleSelect();
    });

    this.around('selectableElement', function(fn, el) {
      return fn(el) ||
        el == this.el ||
        this.$el.contains(el);
    });
  };

Now all I have to do is add the click to select to a view to make it selectable by clicking:

var ClickableView = Backbone.View.extend().mixin(Mixin.view.clickSelect);

The great thing about these mixins is that we don't have to recode our old code base to add them in, I can just mix them in on existing code! Want to see something even more excellent? well there are mixins to make a list navigatable by keyboard. So I can just do something like this:

var NavigatableList = Backbone.View.extend().mixin(Mixin.view.keyboardNavigatableList);

And that's it! I now have a list that I can navigate with the keyboard and it's going to select the appropriate child. The keyboardNavigatableList mixin actually uses other mixins that you could use on their own which include getChildren (allows you to return the child views of a view - its made to work with layoutManager and componentView but can easily be swapped out for whatever view manager you use),selectableChildren (keep a record of the selected children), singleSelectChild (only allow one child to be selected at a time) and keyboardNavigation (which actually extends focusable and gives you functions like onKeydown and onKeyup that you can mixin with instead of creating new events and potentially overwriting functionality as you extend your view).

So this was all pretty sweet but my biggest annoyance was that there was no way to just have a list, so I made a mixin for that as well. It was made to work with layoutManager but I was soon finding problems with layoutManager so I made another plugin...

Backbone.ComponentView


The main issues I ran in to with LayoutManager was around it's asynchronous code. In the code there were functions everywhere and deferreds being passed around that would be used to modify views in completely different parts of the code base. There was no way to know what would be happening to a view just by looking in the constructor, you'd have to trace all the code at run time, and even then it was hard to track down. One of the things that Google's Closure Library does well is with components, so naturally I wrote a port to use underscore instead of the Closure Library utilities.

Components have a lifecycle and a very definite way they should be used. Within a component you have an enterDocument and that is where you put the code to run after rendering. After writing a couple of extra methods to allow ComponentView to be used with setView and insertView (LayoutManager methods) I found all I really had to do was grab everything in beforeRender and afterRender and put them in enterDocument. To my surprise it took very little tweaking to get it running with this and allowed a good structure to clean up any asynchronous code, because now I could put it in to run synchronously.

The one thing it doesn't do is asynchronous loading of templates, but we use requireJS, so I just put them up there and we were away. In fact doing that was a good thing as now we can have the templates in the build system rather than what we had before where they were all compiled in to a single file and brought in first (this way we only have to bring in what we need).

So with ComponentView I also made an autolist mixin which I converted over from PlastronJS and now to get a full list I only have to do:

var List = Backbone.ComponentView.extend({
  itemView: SelectableItem
}).mixin([
  Mixin.view.keyboardNavigatableList,
  Mixin.ComponentView.autolist
]);

But we're still not done. In the interface we had a list split up in two, one for endorsed items and one for normal items. They both make separate server requests and are both lists, so they were both collections. The issue though is when an endorsed item comes in we want the item in the other list to know it's now endorsed and to change. So there was spaghetti code in the view to run through the models and match items across the two collections - it was a mess. The solution? we only want to use one instance of the model:

Backbone.ModelRegistry

Models in our application only last a certain amount of time, once they are out of all the collections we don't need them anymore. I wanted to share a model instance across collections, but I didn't want the register to hold a reference because then I would have to write logic to test whether a model should be removed periodically. The answer was pretty simple. On our page we always show these two collections so there isn't a problem keeping a handle to them, so why not just register the collections and then search through them for an existing model instance. So Backbone.ModelRegistry was born.

To make this work though I would need to override the Backbone.Collection.prototype._prepareModels to first check for the existence of a model and pass that back instead. So to do this I just wrote a mixin that would register a collection then augment it's _prepareModel method to check the registry for an existing model. So it became as simple as this:

var registery = new Backbone.ModelRegistry();
var Coll = Backbone.Collection.extend().mixin([
    Mixin.collection.modelStore
], {
    register: registry
});

Then I can extend coll, or mixin more things but any new instances will be registered with the registry and share model instances. I could even put that mixin on different constructors and as long as I pass the same register object through they will all share model instances. In fact we have two panes in our product that have lists that need to share their models but we don't want to share the models between panes, so we just create two model registers and use one for the top pane and the other for the bottom. Now we have the same models between them, but we were told that now we want to hide the models in the second collection if they are endorsed. So basically we want to update our collection to remove models that are endorsed - the problem is that there may have been a mistake and we need to put them back in. What we really needed was a filtered collection to make things easy for us.

Backbone.CollectionFilter

The main issue was that I don't want to know that the collection I'm getting is a filtered version. I want to still be able to interact with it as if it's the original collection with all it's original function calls. So what we have to do is create a new collection that extends our old one and then bind all of it's functions to the original context. Then we need to do have a look at the events getting passed through and choose whether they should fire at all (a model being added to the original but not passing a filter should not fire any event). And so Backbone.CollectionFilter came in to being. To use it we just need to pass in the original collection which will be used as a basis for inheritance, a filter function and an optional comparator that will allow you to sort your collection in a different way if necessary. This meant that to get the collection we just need to do this:

var NonEndorsed = new Backbone.CollectionFilter(endorsed, function(mod) {
    return !mod.get('endorsed');
});

And that's it, we can just pass along that collection and use it as normal. And that's it, we've got a great scalable system that we can mix and match to get what we need.

The Future


We're not stopping there though, there is heaps in the pipeline.

Nerve

which is a mediator that allows communication at the application level for Backbone. We're not using it yet but it's there when we need it.

Underscore.Extras

is still in the early stages. It'll be extra functionality that we can use to write clean functional code. The plan is it'll replace code that does a lot of existential testing.

HandlebarRivets

At the moment we're using Handlebars templates but we haven't got a way to hook up the data binding to that. Rivets.js allows good two way data binding and allows custom generators so work has begun on a handlebars to rivets converter which should give us the data binding from rivets and the ease of use of handlebars. Still very early (less than a day of work) but big plans for this one.

a quick note on CI


Going forward the plan will be to have all these as git submodules which will be hosted with JenkinsCI so we can develop them alongside our normal code. If you have a look in the above projects you can already see there is testing setup with Testacular (now Karma) and mocha with chai. It was an absolute pain getting it all running with requireJS so I'm hoping in the near future to switch over to Mantri