понеділок, 13 серпня 2012 р.

Backbone.JS Model classes

Intro

In this post I wanted to describe guideline for models' classes that are used in my project at work.

As I have said in my previous post, Backbone gives you a freedom of choice, so you need to pay the price for this. You can find a lot of good tutorials in internet that will point you to a good way of writing backbone-based apps, nevertheless thare are some problems that are left behind and you still need to solve them somehow. I would recommend you to start with this seria of articles. It covers almost all basic steps to build backbone app from scratch and gives clear vision of Backbone fundamentals.

Model class role

Inside your web app you may find four basic roles of modules and classes:

  • Domain model
  • Business logic
  • Various infrastructure classes
  • UI layer
I divided the app classes by responsibility criteria. Standard MVVC pattern defines the anatomy and mechanics of application.

Model class in Backbone app is responsible for domain entity representation and business logic related to I/O operations. It also covers life-cycle states of an entity. The same refers to collection classes but they are meant to be used with the items that belongs to the same model class.

Life cycle of model begins with the instantiation and fetching data. Attributes changes trigger change event that could be used for handling states changes.

Implementation

Let's develop very sample class for the article entity that may react on tagging.

Generic tips

  1. Initialize method is for declaration of handlers and data init. Do not put heavyweight logic there.
  2. Do not mix everyhting in one single method. Parse is for parsingm fetch is for fetching, save is for saving. Keep an eye on that during the code reviews ;)
  3. Url as attribute is good when url is static, but it's a very rare casem better to use url as method 

States handling

So here is a sample model that is built according to the things I described above:


  1. var ArticleModel = Backbone.Model.extend({
  2.         initialize: function() {
  3.                 //Handler for tags changes
  4.                 this.on('change:tags',function(value){
  5.                         var id = this.id;
  6.                         //Iterate over changed tags
  7.                         _.each(value, function(item) {
  8.                                 //Add id of article to them
  9.                                 Tags.getByName(item).add(id);
  10.                         });
  11.                 });
  12.         }
  13. });


  1. Usually, when newcomers start to write application they are trying to put all checks and triggers into model methods, cause it's more obvious to debug. But in this sad case code is getting messy day by day and one morning it will explode.



I/O

Another point is that server side may be designed for native apps that can use CURL library and work with all types of responses without any limitations. HTML5 is different, less powerful and more naughty.

You have two options when developing I/O methods for your model and the server side is not REST+JSON:

  1. To override sync method and implement own Create/Read/Update/Delete calls to server. Good option when the server is still REST but gives different response format. Just override parse method and handle the response there.
  2. To implement own fetch/save/destroy methods. Good when server is not REST at all.
    1. var ArticleModel = Backbone.Model.extend({
    2.         initialize: function() {
    3.                 //Handler for tags changes
    4.                 this.on('change:tags',function(value){
    5.                         var id = this.id;
    6.                         //Iterate over changed tags
    7.                         _.each(value, function(item) {
    8.                                 //Add id of article to them
    9.                                 Tags.getByName(item).add(id);
    10.                         });
    11.                 });
    12.         },
    13.  
    14.         url: function() {
    15.                 return "http://api.com/articles/" + this.id + "?responseFormat=xml";
    16.         },
    17.  
    18.         fetch: function(options) {
    19.                 $.ajax({
    20.                         url:this.url(),
    21.                         success:function(response) {
    22.                                         this.set(this.parse(response));
    23.                                         options.success && options.success.call(options.context || this,this);
    24.                                 },
    25.                         context: this,
    26.                         method: "GET",
    27.                         dataType: "xml"
    28.                 });
    29.         },
    30.  
    31.         parse: function(response) {
    32.                 return {
    33.                         journalist: $(response).find("> journalist").attr("name"),
    34.                         published: $(response).find("> published")
    35.                 }
    36.         }
    37. });

  1. As you can see everything depend on your circumstances and requirements. 

    Outro

    I outlined some aspects of models classes development that may save your nerves in your projects. I add more posts about views and routers classes guidelines soon. 

    Thanks for your attention!

неділю, 12 серпня 2012 р.

Backbone.JS: When it's worth to use it?

Intro

Backbone.JS is not a new kid in town and is being discussed during the previous year.

Gordon L. Hempton has reviewed its' competitors with the conclusion that Ember.JS is the only framework that has everything out of a box. 

I just want to analyze when Backbone is good choice for an enterprise product.

Borders of Backbone

By saying "borders" I meant limitations of Backbone.JS implementation and use cases, so this will define a comfort zone for this framework.

Aspects of usage

Firstly, Backbone.JS is an web framework for single-page web-applications that have view-states. Each state could be represented by hash-route. This means that application could be reloaded with a given hash-route as an entry point. Unlike Adobe Flex it does not provide native support for state-management infrastructure out of a box. So it's up to you how to implement the state handling mechanism.

Secondly, BB is not a MVC framework in it's classic way. View class acts as the view and the controller at the same time. You have no special guidelines to class itself but when rendering is not linked to model changes by using events view acts as a passive representer of data and it's not clear when to trigger render method. 

Thirdly, this framework is highly-adopted to a flat domain model architecture. It provides us with model and collection classes for organization of business logic and domain model. For more complex cases when deep and nested models are required you will need to use the Backbone-Nested plug-in. I would not recommend you to reinwent a wheel in your projects cause in the end you will come to the same idea. 

Fourthly, Backbone is designed to de used with a single data provider, REST web server with JSON output by default. If you have legacy backend that is not designed for REST API and/or uses XML as an output, then you will need to implement custom sync mecanhism. If you have more than one data-provider beside this, you might consider usage of Backbone.localStorage or Backbone.WebSQL plugins as helpers.

And finally, Backbone is not a dictator that allows only way to build an application. It provides you with a skeleton and it's up to you how to organize muscles, nerves and bones.

What need to be considered before to start


  1. UI components library usage vs custom components via templates and CSS.
  2. DOM library: jQuery or Zepto.JS
  3. Underscore templating or something more advanced
  4. Synchronization with the backend
  5. Caching of data for offline usage
  6. Localization: Moment.JS for date/time stuff, i18n aspects are covered here
  7. Modularity: LAB.js and Require.JS
  8. ORM when you need to implment persitence of data
  9. Global events pub/sub: offline, change locale at runtime, login/logout, etc..

So what?

As you can see you need to pay the price for the freedom of choice when you are composing your backbone based stack for your application. Again, backbone does not provide you with a single proven way to build an app. So, let's describe cases when it's worth to use Backbone.JS stack and when to look into the other side of the moon.

When to use it

  1. The requirements are changing frequently and you ned to adopt your architecture to them
  2. The UI is based on templates and you just need to react on standard events in views. Usage of UI components is an advanced topic and will not be covered here.
  3. The server provides client with the REST API. Exotic legacy servers that were designed for native apps need to be discussed separately.
  4. You are comfortable with the getters/setters and the events concepts.
  5. You are comfortable with the BB implementation of OOP via prototype.
  6. And the main one: you have time for the research

Outro

I'm going to write more about this framework and it's usage for building cross-browser mobile web apps.

Further reading

Plugins

  1. Backbone.Marionette - first plugin I ever met that allows to implement application without mess of own infrastructure classes.
  2. Backbone.Nested - plugin for organization of complex models