D'un site mobile à une véritable application Web

le 03/09/2012 par David Friquet
Tags: Software Engineering

La navigation mobile (smartphone ou tablette) s’est sans conteste accaparée une partie non négligeable du trafic Internet, et son augmentation ne fait pas de doute. Pour répondre à l’arrivée de ce nouveau support de consultation, nombres de sites ont commencé par adapter leur présentation pour une lecture agréable. Aujourd’hui, le mobile fait l’objet d’une véritable stratégie d’entreprise et ce sur de nombreux fronts : organisationnel, marketing et technologique notamment.

Ce dernier point amorce aujourd’hui un virage naturel mais peu évident à négocier, tiré par la démocratisation des usages et donc d’attentes plus élevées de l’utilisateur : il ne cherche plus seulement une déclinaison mobile d’un site web, mais une véritable expérience comme attendue dans une application native.

La WebApp mobile, le défi gagnant-gagnant

Aujourd’hui, on consultera dans la majeure partie des cas d’une version mobile qui n’est finalement qu’un affichage dégradé du site principal. Cette version, que l’on nommera “site mobile”, peut être un site web à part entière, ou pour les plus évolués reposer sur l’utilisation des MediaQueries CSS3, permettant de conserver le même moteur sous-jacent tout en adaptant l’affichage à la résolution de l’écran. On arrive assez facilement par ce biais à proposer un site mobile, mais pas encore l’expérience maintenant attendue par vos visiteurs.

Pour atteindre cet objectif, de nouvelles solutions logicielles ont fait leur apparition afin de gérer la complexité d’une application riche, exclusivement coté client, consciente des problématiques mobiles. On assiste aujourd’hui au retour en grâce de JavaScript, longtemps utilisé seulement ponctuellement et avec réticence. Mélangez des paradigmes laissant le champ très libre aux développeurs, peu de lignes directrices communautaires, des implémentations très inégales entre les navigateurs, ajoutez au milieu quelques cowboys du Far Web, vous obtenez alors souvent du code source immaintenable et des effets de bords incontrôlables.

Mais ce JavaScript n’est plus. Suite à la montée en puissance fulgurante du JavaScript côté serveur avec l’avénement de Node.JS, ce socle technique gagne en maturité grâce aux contributeurs de tous bords rapportant les bonnes pratiques des mondes Java, Ruby, Python... Ainsi, on peut voir fleurir des frameworks de test et de mock pour sécuriser des développements, ou encore des outils de gestion de dépendances à la Maven, pour rapatrier des bibliothèques proposées par la communauté disponibles sur des dépôts publics. Bref, on atteint aujourd’hui un niveau de maturité tout juste atteint par le socle iOS par exemple, malgré une plus forte notoriété et une profusion de développeurs et d’applications.

Vous l’aurez compris, l’écosystème JavaScript est dans une dynamique vertueuse et il faut un bon guide pour se retrouver dans cette dense jungle d’initiatives émergeantes, toujours en mouvement. Parlons alors d’un défi technique, mais à l’issu duquel vous obtiendrez un produit web avant-gardiste et vos utilisateurs une satisfaction bien plus complète.

Cet article vous propose donc quelques pointeurs vers ce qui est pour nous l’état de l’art du développement d’une WebApp mobile full-JS.

Les briques pour une WebApp d’aujourd’hui

Frameworks Web

Dans l’optique d’apporter ce niveau d’interactions, de nombreux framework web JavaScript ont vu le jour. En effet, 100% coté client, ils apportent une réactivité et de nouvelles possibilités que ne peut offrir un fonctionnement client-serveur standard, comme un mode hors-connexion par exemple. L’utilisation de frameworks tout-en-un engendre un gain de productivité sensible.

Considérons dans un premier temps l’accès aux données. Celui-ci se fera directement en JS, depuis le navigateur client, via des WebServices. Dans le cas d’une API REST, ces frameworks sont si bien outillés que c’est un vrai plaisir d’échanger des données avec le serveur : on ne manipule plus des URLs et des paramètres de requête, mais des objets métier directement. Une sorte d’ORM sur WebServices, en somme. [1]

var Note = Backbone.Model.extend({
});

var Notes = Backbone.Collection.extend({
  model: Note,
  url: '/notes'
});

var notes = Notes.fetch()
// Avec cette seule ligne, le framework va :
// - rentrer en contact avec le WebService à l'URL spécifiée
// - récupérer et parser le tableau retourné par le serveur
// - pour chaque élément du tableau, instancier le modèle associé et renseigner ses valeurs

Une fois les données récupérées, il faut pouvoir les présenter à l’utilisateur. Là encore, ces frameworks ont hérité de l’expérience des autres langages et proposent eux aussi des bibliothèques de templating. Favorisant la clarté, la maintenabilité et la réutilisabilité, on ne forge pas du HTML directement en JS, mais on insère des petites touches de JS dans des fichiers HTML. Une meilleure séparation des responsabilités pour un code de meilleure qualité.

Pour terminer, le liant entre modèles et vues est à la discrétion des frameworks. C’est en effet la partie où diverses approches coexistent, avec chacune leurs avantages/inconvénients. Vous trouverez donc souvent la notation MV*, l’étoile pouvant être le désormais répandu C de Contrôleur, simpliste R de Routeur ou encore le récent VM de VueModèle...

[1] L’exposition de ces données est donc un prérequis ; mais pas de panique, la plupart les socles Web coté serveur (Spring, Ruby on Rails, Django...) permettent ces évolutions à moindre coût et risque.

Nos petits préférés

Notre ambition ici n’est pas de présenter de manière exhaustive tous les frameworks JS disponibles, ni même un tutoriel pour certains d’entre eux. Ceci pourra faire l’objet d’articles entiers. Non, il est question de vous fournir quelques pointeurs sur les solutions que nous suivons assidument et avec lesquelles nous travaillons.

Intéressons-nous donc à Backbone.js, probablement le framework le plus accessible et le plus répandu aujourd’hui. Il peut se targuer d’avoir de très bonnes références comme LinkedIn, Walmart ou Basecamp qui lui ont fait confiance pour leur dernières versions mobiles. Fort d’une documentation élaborée et d’une communauté active, reprenant des concepts bien connus dans le développement Web tels que les modèles, vues et routeurs, Backbone.js est un choix judicieux pour offrir une expérience nouvelle à vos visiteurs avec un coût d’apprentissage raisonnable pour les équipes de développement.

Un de ces récents concurrents à l’avenir très prometteur s’appelle Ember.js. Ember.js est en fait la nouvelle version d’un framework très populaire : Sproutcore. Plus jeune, ce framework met en oeuvre des concepts moins commun dans le dev web, se rapprochant plus de client lourd et de l’événementiel : gestion d’état plutôt que gestion d’URL, data binding... La montée en compétences des équipes sera moins immédiate mais une fois ces concepts bien assimilés, Ember.js promet une productivité plus grande. *

* Ember.js, en embarquant des composant Sproutcore, peut cependant revenir vers des concepts MVC plus traditionnels.

Gestion des dépendances

L’introduction de nouvelles bibliothèques, qui elles-mêmes utilisent d’autres bibliothèques (pour du templating de vue ou de parcours de DOM par exemple), amène à des problématiques de gestion de dépendance. Ces problèmatiques bien connues et déjà outillées dans de nombreux langages (Maven [2], RubyGems...) prennent une nouvelle dimension avec cette (r)évolution de JavaScript.

Pour nous aider, nous pouvons regarder du côté de Require.js dont c’est la raison d’être. Cet outil sera capable de charger vos dépendances externes tout en vous assurant qu’elles seront bien présentes à l’exécution de votre code. Il saura même gérer les dépendances imbriquées et ordonnancer leur chargement de manière optimale. Vous pouvez ainsi modulariser proprement vos applications JavaScript et gérer vos dépendances internes et externes simplement.

Mais ce découpage a un coût non négligeable dans le monde du Web mobile : plus de fichiers JS implique plus de ressources à charger depuis le navigateur. Or, chaque nouveau fichier est une nouvelle connexion à ouvrir, et en 3G, ça prends du temps et ça échoue facilement. Comme personne ne souhaite sacrifier la productivité des équipes en développant tout dans un seul gros fichier, nos amis de Require.js ont concocté un outil de minification/unification des fichiers JavaScript, r.js. En une ligne de commande, vous pouvez passer de 82 fichiers JS pesant plus de 2Mo à un seul fichier atteignant à peine 500ko.

[2] Nous limiterons ici le parallèle avec Maven à ses fonctionnalités de gestion de dépendance, son périmètre complet ne trouvant pas d’équivalent dans le monde JS, tout du moins pas dans un seul outil.

Outil de test

L’arsenal se serait bien évidemment pas complet sans un outil de test, afin de sécuriser les développements et évolutions futures. Avec une base de code qui se déplace du serveur vers le client, il fallait que les outils de test suivent pour continuer d’assurer une haute qualité et haute productivité des développements.

On se tournera aujourd’hui vers Jasmine, outil de Behaviour Driven Development, qui ne sera pas sans rappeler le très populaire RSpec du monde Ruby. Passée la barrière du DSL de test un peu particulier pour des habitués des xUnit, on découvre un code de test très explicite, auto-documentant le code source qu’il couvre, tout en assurant évidemment la non-régression.

describe("Article domain", function() {
    describe("#from_json", function() {
        it("fills in the title field", function() {
            var raw_json = '{title: "My test article title"}'

            var article = Article.from_json(raw_json)

            expect(article.title).toBe('My test article title')
        })
    })
})

Ce framework de test a également le bon goût d’embarquer directement des tests doubles permettant de créer des mocks. Les mocks apporte le grand avantage de découpler nos tests des composants extérieurs en simulant leur comportement sans les appeler directement : des tests plus rapides à exécuter, du code plus facile à faire évoluer.

Ce que ça change pour vous

Déployez simplement et sans douleur

Une fois préparée avec r.js, votre application Web tient en trois fichiers, en tout et pour tout : une page HTML, coquille vide incluant une feuille de style et votre fichier JavaScript (je ne compte pas les images, celles-ci étant à la discrétion de votre graphiste). Ainsi, une mise en production consiste à déplacer ces trois fichiers dans le bon répertoire de votre frontal Web. Ne reposant sur aucune technologie serveur, cela peut être un simple serveur de fichier statique !

Considérez maintenant la possibilité d'exposer ces fichiers via un CDN type Akamaï... Vous pouvez alors lancer votre nouvelle WebApp sans crainte de surcharger un serveur d'application : la logique est portée par vos WebServices (éventuellement mis en cache également), la génération des vues par le navigateur client. Bref, vous obtenez une application réactive et peu consommatrice de ressources serveurs à moindre coût.

Formez-vous/vos équipes

JavaScript, longtemps considéré comme un langage malsain, plantogène, archaïque, devient aujourd’hui un langage de première zone. Son fonctionnement maintenant (relativement) homogène entre navigateurs font de ses faiblesses des forces : langage prototypal interprété aux accents fonctionnels, asynchronisme et fermetures, fonctions anonymes...

Qu’on ne s’y méprenne pas, il est toujours possible de faire du code illisible, aux effets de bord incontrôlables. Ceci dit, l’émergence de tout cet écosystème a fait naître des standards, des bonnes pratiques, une littérature dense et même de très bonnes formations pour les enseigner.

Il est recommandé à tout développeur d’apprendre au moins un nouveau langage par an. Pourquoi s’attaquer à un n-ième langage procédural orienté objet quand on peut découvrir de nouvelles façons de penser ?