sábado, 15 de agosto de 2015

CAM-ICU: the first mobile web app of a desktop developer

CAM-ICU is a tool used to assess delirium development  in critical care patients. When a friend of mine asked for an application to use in his Intensive Care Unit, i decided to write it as mobile web app. It was the perfect fit to learn how to program with HTML and Javascript: an application that has actual usage / challenges, unlike most demos out there, but not as big that would make unpractical to develop.

As a long time desktop developer, starting with web development, i faced a bunch of issues developing the app. More than a guide to create an app this post aims to record the development process, how i overcome the found problems and what i learned for my future web development projects.

The source code can be found here and a live demo here

General application structure


The application was built using Backbone with some plugins (StickIt, Validation, Computed). Bootstrap was used as the CSS framework, Handlebars as template engine and JQuery for DOM manipulation. The Backbone Yeoman generator was used to scaffold and create models and views. The backend is a CGI application developed with Freepascal and Lazarus that implements a REST service.

The (not so) good old Backbone


As already explained, i choose to structure the app using Backbone. It forces me to learn the basics of HTML/DOM/JS unlike Ember or Angular that abstracts them with a lot of "magic" behind the scenes. Other Backbone advantage is its usage pattern which is similar to what i already do in desktop.

But...

Having to write boilerplate code like render in View "classes" is annoying and error prone. To avoid memory leaks is necessary to keep track of child views, another bothersome step. The natural step was to create base classes handling these problems but than i would recreate the wheel.

    render: function () {
      this.$el.html(this.html);
      this.stickit(this.model);
      return this;
    }
You get tired of writing such code early

On the other hand, Backbone's Model/Collection/Events layer is at the same time easy to grasp and powerful, providing the elements to structure the code in a organized, maintainable way.

The bless and curse of Backbone plugins


As soon as the newbie Backbone developer try to learn more about the library, he/she is confronted with tons of plugins adding tons of features on top of the bare components.

This is a good thing because allows the programmer to pick the extensions that provides the needed features and better adapt to his/her work flow. But, given the great number of choices, is necessary to spend some time evaluating those libraries. As an example, i needed to extend Backbone.Model with computed fields. I found four plugins: Mutators, compute, computed-properties and computedfields. Mutators is complete and well maintained but too intrusive for my taste, compute seems dead, computed-properties misses a needed feature (toJSON handling) and patches Backbone.Model constructor, finally computedfields was the choose one because of its good balance of feature and light weightiness.

Can use it !== must use it


Not necessarily related to Backbone or web development, but having so many features/extensions at disposal makes easy to overuse or misuse them. I felt in this temptation. In the code below i registered a computed field dependent of an property instantiated at demand (_evaluations). It store the callback function in an property just to be called later.

evaluationcount: {
 get: function () {
   if (this._evaluations) {
   return this._evaluations.length;
   } else {
   return this.get('evaluationcount')
    }
},

 depends: [
 function (callback) {
    this._updateEvaluationCount = callback;
   }],
   toJSON: false}

[..]

evaluations.fetch({
  success: function (collection) {
    self._evaluations = evaluations;
    self._updateEvaluationCount();  
    evaluations.on('add remove reset', self._updateEvaluationCount);
  }
})
Instead of using the computed plugin, i could use the standard Backbone primitives to accomplish the same in a cleaner, smaller way:

   
evaluations.fetch({
   success: function (collection) {
     self._evaluations = evaluations;
     evaluations.on('add remove reset', function(collection){
    self.set('evaluationcount', collection.length);
     });
   }
})
A lot better.

Bootstrap for mobile web applications



To style the application, the natural choice would be a framework like jQuery Mobile but this would mean the need to learn yet another technology. Since Bootstrap has first class mobile support and i already knew its basics, it was the selected.

I learned the hard way that Bootstrap is tailored to mobile pages not mobile apps. Many of the user iterations and common designs of mobile apps cannot be accomplished with a vanilla Bootstrap. The result is the need to change a few behaviors leading to a subpar developer and user experience. MobileAngularUI adapts Bootstrap to have a look and feel better suited to apps. Unfortunately is incomplete and development has been slow.

Yo fail!


In the web programming ecosystem there are a lot of tools aimed to ease the application development process. And every day new tools arrive. This makes hard, specially for newcomers, to learn how to setup a productive environment.

Yeoman is presented as a tool to address this issue by making easy setup best practice development environments ready for consumption. Unfortunately, i hit some issues while using it. I could not get the optimized requirejs build to work out of the box. I had to manually adjust the configuration and even than did not work. After some more tries, i gave up and finalized the build manually. The non official Bootstrap Sass port was discontinued and i had figure myself. No luck making livereload work, had to try browser-sync with no better outcome.

Another problem is that with the myriad of options is hard to find a generator that fits the developer specific needs. I decided to go with MarionetteJs, Webpack, Gulp, FlightJs, Bootstrap for my next projects but could not find a generator that produces such environment. To keep using Yeoman i would need to learn how to create a generator and how to configure the required tools. No thanks. 

Learnings


All in all, it was a rewarding and funny experience. The problems i faced were not insurmountable and should be considered natural stumbles of the learning process. In the end, i've got some lessons:

  • A Backbone extension like Marionette, Chaplin and LayoutManager should be used to bigger than demos apps. Marionette seems to be the one with more traction
  • Plugins are great but must be carefully evaluated to avoid the poor coded ones. A good thing also is to use the plugins only in the really needed cases.
  • Bootstrap is not suited for mobile web apps. jQuery Mobile, Kendo Mobile, ChocolateChipUI, Framework7 or even Ionic css are the real deal.
  • The current JS client application develop/build experience falls short. Lot of options and rapidly changing build tools is a barrier for newcomers. Yeoman is not the right response for this problem.






Nenhum comentário:

Postar um comentário