Accueil > Web > Applications web grand public en JavaScript : REX sur Ember

Applications web grand public en JavaScript : REX sur Ember

Voilà maintenant 2 ans que j’utilise Ember pour les développements front d’une application web grand public. Ember fait partie des pionniers des frameworks basés sur le Design Pattern model-view-controller (MVC), faits pour gérer complètement l’interface utilisateur d’une application en Javascript (JS) et sans rechargement. Il sera donc question dans ce billet, de vous faire un retour d’expérience sur l’intégration d’un framework MVC Javascript next gen dans un projet d’entreprise.

Pourquoi s’appuyer sur un framework MVC JS ?

L’architecture d’une application est déterminée en fonction des contraintes fonctionnelles et techniques d’un projet.

Dans cette application, il s’agit de proposer un service de streams d’itinéraires en train, en avion ou en voiture. Autrement dit, les trajets sont transmis au fil de l’eau, on n’attend pas la fin de la construction de tous les trajets pour les afficher à l’utilisateur. Chaque recherche utilisateur (origine, destination, dates…) déclenche une série de streams qui alimentent le navigateur avec toutes les propositions de voyages disponibles. Le client en quête du trajet idéal manipule alors ces données à travers les multiples fonctionnalités de l’application sans (presque) jamais solliciter le serveur.

En parallèle, ce projet présente des contraintes techniques fortes. L’application doit être purement stateless afin d’être déployée sur une infrastructure hautement scalable.

Ainsi, on ne souhaite pas sauvegarder l’état des transactions côté serveur, et on reçoit tous les trajets disponibles aller-retour en une seule requête. Une application web monopage (SPA) semble dans ce cas être la meilleure approche pour répondre à ces contraintes.

Au début du projet, quelques frameworks Javascript facilitant le développement de telles applications sont connus : BackboneJS, EmberJS, KnockoutJS, AngularJS… Alors si toutes ces solutions semblent, a priori, répondre aux besoins, sur quels critères sélectionner la plus performante d’entre elles pour notre « use case » ?

EmberJS, la voie de la raison ?

Définir une liste de critères n’est jamais chose aisée. Néanmoins certaines contraintes fonctionnelles ou règles de bon sens font émerger quelques éléments qui permettent ainsi de faire un choix de framework pertinent.

Dans le cadre de notre projet, le framework MVC JS doit :

  • Pouvoir supporter IE7 et IE8 : l’application est grand public.
  • Permettre de développer un site dynamique : les interactions avec l’application sont nombreuses, et le temps de réponse instantané.
  • Permettre de présenter des informations complexes : un comparateur de voyage peut générer beaucoup d’informations.
  • Gérer plusieurs états : la recherche d’itinéraire de voyage, la sélection, la consultation, et la réservation.
  • Être productif : 6 mois pour produire une version bêta de l’application.
  • Pouvoir durer dans le temps

Alors quels sont les éléments qui nous permettront d’évaluer les différents frameworks par rapport aux critères précédemment énoncés ?

Le framework doit disposer des fonctionnalités suivantes pour satisfaire nos besoins techniques :

Le développement d’application dynamique : le Data-Binding est utilisé pour synchroniser les valeurs des variables entre les objets et les vues, de façon à ne pas avoir à gérer le rafraîchissement de l’HTML.

La présentation d’informations complexes : les Composed View permettent de créer des vues réutilisables et modulaires pour la programmation interface utilisateur (des templates Layout). On peut aussi composer des interfaces en imbriquant plusieurs vues (templates). Ce qui simplifie la restitution de l’information sur plusieurs niveaux.

La gestion des états : le Router permet de distribuer des pages côté client en fonction d’événements ou d’actions via des URLs.

Et pour évaluer la productivité et la pérennité d’un framework MVC JS, nous nous basons sur les éléments suivants :

La productivité : sur GitHub, le projet todomvc permet de comparer les implémentations d’une simple « todo list » avec différents framework MVC JS connus. On peut alors évaluer la quantité de lignes de code produites pour arriver au même résultat. Cela donne une bonne idée de la complexité syntaxique.

La pérennité : la taille de la communauté est un bon indicateur de la dynamique d’évolution du produit. On peut observer le nombre de stars sur les repository GitHub des frameworks, pour se faire une idée de la taille de la communauté.

Le tableau ci-dessous résume les avantages et les limites de quelques framework en 2012 (début du projet).

 BackBone Ember Knockout Angular
Router check check / check
Data-Binding / check check check
 Composed View / check  /  /
Support IE7 check check check /
Communauté Forte Moyenne Moyenne Faible
Productivité Faible Forte Moyenne Forte

Dans ce tableau, Ember se révèle être le meilleur compromis pour modeler l’architecture de notre SPA.

EmberJS, créateur dapplications web ambitieuses 

Ember est un framework Javascript open source créé en décembre 2011 qui résulte des années d’expertise et des connaissances acquises lors de création d’applications web à grande échelle. C’est un concentré des meilleurs pratiques et concepts de développement, facilitant la conception et la construction d’applications basées sur le pattern MVC.

En plus de ces concepts de base (Routes, Models, Controllers, Views), il dispose d’un système de classes riches (ContainerView, CollectionView, ArrayController, Component, Array) qui sont autant de solutions adressant les problématiques les plus complexes du développement web.

Avec son moteur de template intégré, Handlebar, qui permet les liaisons entre templates et modèles, tout changement fait sur les modèles se répercute sur les vues et inversement.

 

Si nous semblons avoir choisi le framework idéal pour notre application, la mise en production n’est envisageable que s’il est possible d’intégrer le code produit avec cette technologie JS aux processus d’industrialisation du projet d’entreprise. Nous allons alors nous intéresser particulièrement à deux process d’industrialisation : l’intégration continue et la gestion des ressources.

Vous avez dit intégration continue en Javascript ?

Dans le processus intégration continue nous allons nous intéresser à deux éléments cruciaux, les tests unitaires et leur l’intégration avec Jenkins, notre serveur d’intégration continue favori.

Comme en Java, les règles métier implémentées avec Ember doivent être testées. Pour nos tests, nous avons retenu le framework de tests unitaires QUnit, une valeur sûre au début du projet.

QUnit est un HTML Runner, il exécute les tests dans un navigateur. Le développeur produit alors des fichiers HTML pour y inclure les cas de test rédigés en Javascript. On peut automatiser l’exécution des tests avec Jenkins. À chaque mise à jour des fichiers source, un script JS (qunit-runner) joue les tests unitaires avec PhantomJS (un navigateur sans affichage, scriptable avec une API JS) et génère un rapport sous forme de XML ; un rapport que Jenkins peut exploiter pour nous alerter des éventuelles régressions du code applicatif.

Gestion des dépendances des fichiers JS

Autre problématique de taille rencontrée : la gestion des dépendances des fichiers JS.

Avec une architecture SPA et Ember, le but est de créer une application web se rapprochant d’une application desktop. Pour se faire, on est amené à produire de nombreux fichiers JS dont il faut gérer l’ordre d’initialisation dans le navigateur.

Tout comme Ember dépend de JQuery, certaines classes Javascript dépendent les unes des autres. Et il se peut que pour un contexte particulier de l’application on souhaite un comportement différent, dans le cas d’une version mobile par exemple. Pour résoudre ces problèmes, le plugin ressources de Grails (côté serveur) permet de créer des bundles de fichiers sources, que l’on peut organiser et composer en fonction du contexte et des dépendances.

Exemples :

Bundles mobile → version mobile

Bundles desktop → version desktop…

 

Évidemment l’industrialisation d’une application web ne se résume pas à ces deux processus, la minification et la précompilation des templates Handlebar sont des sujets tout aussi importants, que je vous invite à consulter dans la section « pour aller plus loin ».

Maintenant que nous avons défini notre environnement technique, nous pouvons commencer à concevoir et construire notre application web.

Un voyage vers l’inconnu

Une architecture complexe

Ember s’est avéré être un framework difficile d’accès pour les novices en Javascript.

Les concepts d’architectures proposés étaient avancés et basés sur les conventions de nommage mais manquaient cruellement d’explications.

Notre principale difficulté était de comprendre les mécanismes de ce framework. Et malheureusement la documentation d’Ember n’était pas suffisamment complète et claire pour permettre à un développeur peu familiarisé avec le Javascript de comprendre ces concepts de base.  Les plus érudits en Javascript savaient scruter le code source d’Ember pour y trouver les bonnes pratiques. Et les autres y trouvaient plutôt des moyens de contournement en utilisant des méthodes privées, ou pire, des raccourcis qui supplantaient le mécanisme du framework, créant un fonctionnement un peu hybride avec l’écosystème d’Ember, où même les meilleurs d’entre nous ne s’y retrouvaient plus. De plus, souvent nous avions à peine eu le temps de comprendre un concept qu’il avait déjà évolué dans la version suivante.

Un produit instable

La première version du framework intégrée à l’application a été la V0.9,  qui a connu de nombreuses évolutions majeures durant l’année. Ces évolutions ont valu des changements souvent abrupts : signature des méthodes ou fonctions déplacées dans des objets différents, etc… Et les refontes de certains concepts ont donné lieu à des montées de version un peu sportives, notamment la migration router V1 puis V2 (~2 semaines dev), puisqu’il nous obligeait à revoir entièrement des éléments structurants de l’application.

Une industrialisation fastidieuse

Qu’en était-il de notre intégration continue et de nos tests unitaires ?

Après quelques mois de développement on pouvait déjà constater que la couverture de test demeurait plutôt basse par rapport à la quantité de code Javascript produit. Cela était dû, à priori, aux caractéristiques de Qunit, qui rendaient la maintenance et la rédaction des tests fastidieuses.

En ce qui concerne la gestion des dépendances JS, le plugin resources cohabite difficilement avec les plugins Grails de compilation less et handlebars. Ces deux plugins complexifient la rédaction des bundles et sont souvent sources d’erreurs.

 

Les premiers développements applicatifs nous permettent d’éprouver notre environnement technique et de repérer quelques axes d’amélioration. 

Pour trouver du nouveau

Malgré quelques désagréments dus à la jeunesse d’Ember, ce framework nous permet de booster les développements fronts. Une version bêta du site est d’ailleurs sortie en seulement 6 mois.

Grâce à un refactoring rigoureux de notre implémentation, au fur et à mesure des versions, on s’est familiarisé avec l’architecture et on a maintenu des livrables de qualité. Maintenant, Ember en version 1.5.0 est un produit stable qui n’a aucune mise à jour structurante prévue à ce jour. Et la documentation en ligne est actuellement suffisamment riche et accessible pour se familiariser rapidement aux concepts de base du framework et démarrer un nouveau projet.

En ce qui concerne les problématiques d’industrialisation des développements Javascript, nous avons apporté quelques améliorations.

Principalement au niveau des tests unitaires, désormais avec l’outil Karma nous disposons d’un véritable environnement de test. Ce dernier lance un serveur web (NodeJS) qui exécute les tests sur différents navigateurs, et affiche le bilan des tests en ligne de commande. Le développeur rédige son test en Javascript avec le framework de son choix (plugins existants : JasmineJS, QUnit, Mocha). L’occasion rêvée de remplacer notre ancien framework de test QUnit par JasmineJS qui a une syntaxe plus lisible et qui surtout ne nécessite pas la création de fichiers HTML difficiles à maintenir et sans valeur ajoutée. De plus, la fonction autowatch de Karma permet d’exécuter tous les tests à l’enregistrement d’un fichier.

L’intégration dans Jenkins est aussi simplifiée, Karma prend en charge PhantomJS. Nous n’avons plus qu’à configurer notre environnement de test pour qu’il génère un fichier de reporting xml à l’exécution des tests.

Malgré une nette amélioration de nos processus de test JS, un feedback rapide, aucun fichier HTML à maintenir, et une intégration continue simplifiée, notre couverture de test demeure toujours aussi basse…

Quant à la gestion des fichiers Javascript, nous nous appuyons toujours sur le plugin ressources de Grails. Le projet étant dans une phase de stabilisation, intégrer une meilleure solution de gestion des ressources web serait inapproprié. Mais si nous en avons l’opportunité, l’outil Grunt pourrait mieux répondre à nos besoins.

Conclusion

Bien choisir son framework

Il y a toujours une part de risques quand on s’appuie sur un jeune framework MVC JS pour construire une application d’entreprise. En sélectionnant judicieusement un framework, on est capable de réduire suffisamment ces risques pour s’assurer qu’ils ne remettront pas en question le succès du projet.

Malgré un effort certain pour élaborer une liste de critères, nous avons sous-estimé la problématique de la documentation lors de notre choix technique. Dans l’avenir, si des frameworks MVC JS aussi complets qu’Ember venaient à se multiplier, cela pourrait être un paramètre déterminant. D’ailleurs Ember s’est déjà mis à niveau avec une documentation de bien meilleure qualité aujourd’hui.

Refactoring et réactivité

En ce qui concerne l’instabilité d’Ember, nous savions en intégrant la version V0.9 qu’il serait amené à évoluer. En revanche nous ne pouvions imaginer que les évolutions seraient aussi cassantes.

Dans ce contexte, il est important que l’équipe de développement ait la possibilité, donc le temps, de réadapter l’implémentation au fur et à mesure des versions. Il ne faut notamment pas hésiter à passer en nightly builds, intégrer les dernières sources compiler du framework disponibles chaque semaine pour corriger les bugs au fil de l’eau.

Utiliser les bons outils

Actuellement beaucoup d’outils semblent répondre aux problématiques d’industrialisation des développements Javascript. Il est donc nécessaire de rester à l’écoute de la communauté pour intégrer les meilleures solutions. Il y en a d’ailleurs déjà quelques-unes qui font l’unanimité : Karma et Grunt/Bower.

Cependant nous avons constaté que l’intégration d’un meilleur outil de test (Karma), n’a pas provoqué une augmentation significative de la couverture de test JS.

Tout laisse penser qu’il faut se concentrer d’avantage sur l’initiation des développeurs à cette nouvelle pratique du développement web, pour améliorer l’intégration continue du code JS.  Privilégier le travail en binôme, au moins, pour la rédaction des tests unitaires Javascript aide également l’équipe de développement à se familiariser avec l’environnement technique de test JS. Une bonne pratique qui nous vient de l’agilité…

 

En somme, s’approprier ce type de framework MVC JS permet ainsi d’augmenter considérablement sa productivité. La montée en compétences est coûteuse mais rapidement rentabilisée. Ainsi, fort des connaissances et compétences que nous avons capitalisées au cours de cette expérience, nous avons produit une version mobile de cette même application en seulement 3 mois !

Dans le but de toujours choisir les solutions les plus adaptées aux exigences de nos projets, nous devons porter un regard de néophyte (mais pas naïf) sur les nouvelles technologies. Javascript et les frameworks qui tendent à démocratiser son utilisation sont suffisamment matures pour être considérés.

Pour aller plus loin:

Categories: Web Tags: , , ,
  1. Pas encore de commentaire
  1. Pas encore de trackbacks


8 + sept =