Saturday, June 21, 2014

An Example of Modern Single Page Web Application

Everybody knows that the transition from desktop application to web application hasn't been without issues : lack of responsiveness, high latency, never-ending loading time, ... These drawbacks impact significantly interactivity and user productivity.

During several years, I've spent my time testing existing web frameworks that could bring desktop experience to the web. All my attempts were unsuccessful. I've first started with frameworks from interpreted languages like Ruby on Rails but despite of their ease of use, they couldn't match expected performance. Therefore, I've switched to a Java back-end and Flex client-side system. This configuration provided a much better solution, with good responsiveness. But there was a disadvantage : Flex works on Flash, a propriertary plugin owned by Adobe. Flash showed utf-8 encoding bugs on Linux platform that were only fixed after several months. This kind of situation is very embarassing especially when you know that web applications must be cross-platform. Meanwhile ermenging technologies saw the light of the day : JIT Javascript engines and HTML5. The browsers evolved in the right way and facilitated richer web application development. The choice of the client technology was finally fixed !

Writing large single-page web applications requires a very well structured code, spreaded on multiples files. As we know, Javascript modules will be part of the ECMAScript 6 specifications but are not yet implemented on current browsers. In order to fill the gap, I've chosen RequireJS (thanks to James Burke), a wonderful Javascript library able to load asynchronously files in a clean way.

I also needed to bring object-oriented programming to my code. Fortunately, Javascript has the capability to do it like others programming languages such as C++, Java, Python, ... do. The main difference is that Javascript defines class like a function. This notation can be disruptive, but can be fixed easily :

function Base(methods) {
 
    var key, object = function() {
        if (typeof this.init === 'function') {
            this.init.apply(this, arguments);
        }
    };
 
    if (methods !== undefined && methods !== null && methods.constructor === Object) {
        for (key in methods) {
            object.prototype[key] = methods[key];
        }        
    }
 
    object.inheritsFrom = function(methodsExt) {
 
        var key, objectExtended = function() {
            if (typeof this.init === 'function') {
                this.init.apply(this, arguments);
            }
        };
 
        objectExtended.prototype = Object.create(this.prototype);
 
        if (methods !== undefined && methods !== null && methods.constructor === Object) {
            for (key in methodsExt) {
                objectExtended.prototype[key] = methodsExt[key];
            }
        }
 
        objectExtended.prototype.constructor = objectExtended;
        objectExtended.inheritsFrom = this.inheritsFrom;
 
        return objectExtended;
 
    };
 
    return object;
 
}
Class creation and inheritance in Javascript can be written like this :

var Person = Base({
    // Constructor
    init: function(name, age) {
        this.name = name;
        this.age = age;
    },
    // Method
    sayHello: function() {
        alert('My name is ' + this.name + ' and I\'m ' + this.age + ' years old.');
    }
});

var Student = Person.inheritsFrom({
    // Constructor
    init: function(name, age, subject) {
        // Call the parent constructor with the right context "this"
        Person.prototype.init.call(this, name, age);
        this.subject = subject;
    },
    // Methods
    // Replace the parent "sayHello" method
    sayHello: function() {
        alert('My name is ' + this.name + ' and I\'m ' + this.age + ' years old. I\'m studying ' + this.subject + '.');
    },
    sayGoodbye: function() {
        alert('Goodbye !');
    }
});

// Usage :
var john = new Person('John', 24);
john.sayHello(); // "My name is John and I'm 24 years old."

var sarah = new Student('Sarah', 21, 'journalism');
sarah.sayHello(); // "My name is Sarah and I'm 21 years old. I'm studying journalism."
sarah.sayGoodbye(); // "Goodbye !"
Now scripts are easier to read and understand. It should be noted that class is also implemented in ECMAScript 6 and will be supported natively by browsers in the future.

Next, I needed to create a MVC framework that could structure the application and simplify repetitive tasks. In short, my idea was to create UI elements that work in conjunction with storage elements in order to set up a MVC pattern. These UI elements are integrated into HTML templates allowing the design of complex layout easily. Once the base of the framework created, I have built my client-side application while completing the framework with required functionalities. The result was responsive and fulfilled all my requirements.
But I have kept in mind that a responsive application doesn't only need fast client UI, but a performant back-end. I opted here for Java : the language is fast, give reliable and scalable solutions and own a wide range of mature libraries. My objective was to write a simple and secured REST server. In place of using Spring framework or Java EE stacks which I felt too over-bloated for my needs, I moved tovards smarter alternatives : Google Guice for dependency injections and Apache Shiro for the security in conjonction with servlet containers. I also needed a database for the data persistence. PostgreSQL was my first choice because it's a powerful, reliable and complete database that fits very well enterprise application. After all the ingredients gathered for a good recipe and after spending thousand hours of hard work, I have achieved the following result :


This is a single page web application (a lab management system) that presents the following characteristics :
  • The application is very responsive. In fact, you have the feeling to deal with a desktop application. It reacts up to one order magnitude faster than "traditional" web application which means better productivity.
  • The modules are loaded only once when required, saving a lot of bandwidth.
  • The application emphasizes upon internationalization : purchase orders, reports, labels, ... can be generated with a selected language, which means targeting broader audience.
  • The application is multi-platform and was tested on Windows and Linux (Chrome, Firefox, Opera and IE >= 10).

In summary, IT technologies are constantly evolving. Over the last few years, I always put in doubt my work, forcing me to improve it continually. I think Javascript will not be replaced any time soon on client-side but I see new contenders on server-side like Go able to overtake Java. The future'll give us a response ...

No comments:

Post a Comment