La face cachée d’AngularJS

Logo AngularJSAngularJS est une technologie très en vogue actuellement qui bénéficie depuis sa sortie d’une grande popularité dans le monde du développement web. Cette popularité est d’autant plus remarquable que l’écosystème dans lequel s’inscrit AngularJS est un des plus actifs en termes de nouveaux outils, évolutions, révolutions. Le tweet suivant tourne d’ailleurs cela à la dérision et nous propose quelques explications :

Sa popularité est d’ailleurs telle aujourd’hui qu’il est courant de rencontrer des développeurs web qui ne jurent plus que par AngularJS.

Un concept innovant pour un outil très productif

AngularJS est de toute évidence une technologie innovante qui se positionne en rupture par rapport à ses prédécesseurs. En tirant pleinement profit du binding bidirectionnel qu’il prend entièrement à sa charge, il permet de créer une application web en écrivant très peu de code Javascript.

L’effet wouah est garanti ! J’ai personnellement été bluffé quand je l’ai découvert et je crois que je ne suis pas le seul. Il permet de développer une application web avec une telle productivité qu’il a donne l’impression de quelque chose de magique.

Comme la plupart des outils modernes, AngularJS a pris très au sérieux la question de la testabilité et permet ainsi de tester ses contrôleurs de manière enfantine. Ceci est notamment possible grâce à l’utilisation d’injection de dépendances pour les différents services, mais aussi au fait que les objets AngularJS (et particulièrement $scope) sont des objets Javascript simples.

En fin de compte, une application AngularJS, c’est très simple. Les contrôleurs sont séparés des vues par une cloison bien étanche qui est représentée par le scope. Le contrôleur a pour vocation de faire évoluer l’état de la vue en fonction des événements, les tester revient donc à vérifier l’état des données du scope. De leur côté, les vues sont codées entièrement de manière déclarative grâce à du HTML enrichi de directives AngularJS. Ces directives permettent d’exprimer notamment les règles de binding entre les différents éléments de la vue et les données du scope. Le binding bidirectionnel permet, quand il le faut, d’avoir une synchronisation permanente entre la vue et le scope, que les modifications viennent d’un côté ou de l’autre.

Tout cela fait d’AngularJS une manière très simple et redoutablement efficace de concevoir des single page applications.

Une puissance qui peut être à double tranchant

Un peu trop dynamique

Même si je n’ai pas pu le vérifier dans le cadre d’un projet de taille conséquente, j’ai le sentiment qu’un peu à l’image d’une application écrite dans un langage dynamique, AngularJS tire de moins en moins bien son épingle du jeu au fur et à mesure qu’une application grossit.

Déjà, même si AngularJS permet de limiter drastiquement le nombre de lignes de code à écrire, il reste du code à écrire. Et malheureusement c’est en Javascript qu’il faut l’écrire. Javascript est un langage dynamique, et j’ai déjà eu l’occasion d’exprimer mes réticences relatives à l’utilisation d’un langage dynamique dès qu’on dépasse les quelques milliers de lignes de code. Mais en plus d’être un langage dynamique, Javascript repose sur un paradigme qui lui est propre et que peu de développeurs maîtrisent et savent exploiter, ce qui fait que nous produisons globalement du code Javascript de mauvaise qualité. AngularJS n’a pas choisi ce langage par hasard, Javascript est simplement (et malheureusement) le seul langage qui tourne nativement dans un navigateur.

AngularJS est un outil puissant, il élimine beaucoup de complexité, mais cela ne signifie pas pour autant qu’on peut ignorer toute considération relative au génie logiciel, ce que beaucoup de développeurs ont manifestement très vite tendance à faire. AngularJS permet de tester très simplement le code, mais encore faut-il écrire les tests. De manière similaire à l’ensemble des technologies existantes, passer d’une petite application telle un hello world ou guère plus à une véritable application avec des dizaines de pages nécessite de l’organisation et de la rigueur. Thierry Chatel a d’ailleurs proposé un ensemble de bonnes pratiques dans sa présentation Au secours mon code AngularJS est pourri à Devoxx France 2014 (et peut-être ailleurs) dont un résumé se trouve ici.

L’équipe de développement d’AngularJS semble avoir pris en compte ces considérations dans la prochaine version majeure du framework, Angular 2.0. Exit le Javascript, c’est dans un langage à typage statique que s’écriront les futures applications Angular. Depuis son annonce, cette nouvelle version du framework fait couler beaucoup d’encre, notamment parce qu’elle remet en question les principes mêmes sur lesquels repose la version actuelle de l’outil. La rétro compatibilité ne sera d’ailleurs pas assurée. Je n’ai pas eu le temps d’analyser l’intégralité de la polémique, mais pour ce qui concerne le typage statique, j’ai l’impression que ces changements importants sont nécessaires pour amener l’outil à sa maturité.

Attention aux performances

Par son extrême simplicité du point de vue de l’utilisateur, AngularJS a un côté magique. Mais il me semble imprudent de se lancer dans l’écriture d’une application AngularJS sans avoir percé le mystère de cette magie, car vous l’imaginez bien, la magie n’existe pas en développement logiciel. En l’occurrence, le sentiment de magie que procure AngularJS réside en grande partie dans le binding bidirectionnel. C’est lui qui permet d’éliminer une grande partie du code à écrire. Pour utiliser efficacement AngularJS et ne pas se heurter très rapidement à des gros problèmes de temps d’exécution, il est nécessaire de savoir comment fonctionne le mécanisme de synchronisation bidirectionnel des données.

J’avais une idée vague du fonctionnement interne d’AngularJS, mais elle s’est clairement précisée quand j’ai participé à l’atelier AngularJS from scratch à Mix-It 2014. Cette session consistait à implémenter les fonctionnalités de base d’AngularJS en partant de rien. On se rend à la fois compte que c’est assez simple mais qu’à chaque événement on fait pas mal travailler le navigateur en exécutant plusieurs fois si c’est nécessaire la digest loop pour répercuter les changements du modèle dans la vue et vice-versa (dirty checking).

Le problème de conception que j’ai rencontré le plus souvent dans du code AngularJS est un piège dans lequel on tombe facilement : on a tendance spontanément à publier systématiquement dans le scope les données telles qu’elles sont renvoyées par le web service qui les fournit.

En effet, pour des raisons de performances, il est important que la structure de données exposée par le contrôleur dans le scope soit aussi proche que possible de la façon dont les données sont utilisées dans la vue, de façon à limiter au maximum les calculs qui peuvent être faits à chaque exécution de la digest loop. L’utilisation de fonctions dans le binding peut coûter très cher, mais est nécessaire si les données n’ont pas la structure attendue dans la vue.

Il faut également prendre en compte le fait que le contrôleur et la vue communiquent via les données du scope. Il ne faut pas oublier que l’état de la vue ne se résume pas toujours à ce que le contrôleur publie dans le scope. L’état des vues (par exemple un panneau ouvert ou fermé) ne peut être stocké que dans le scope. C’est une raison supplémentaire qui pousse à avoir une structure de données dans le scope aussi adaptée que possible à la vue. Le bémol de cette pratique réside dans le fait que le contrôleur n’est du coup pas totalement indépendant de l’implémentation de la vue, mais c’est le prix à payer pour avoir une application réactive pour l’utilisateur. Cela implique également qu’il est peut-être nécessaire d’appliquer une transformation lorsque le contrôleur récupère des données dans le scope avant de les envoyer à un web service.

Adapté à certains usages seulement

Il existe rarement des outils capables de couvrir tous les cas d’utilisation. AngularJS n’échappe malheureusement pas à la règle. Ce n’est pas parce qu’il excelle dans certains domaines qu’il faut s’en servir à toutes les sauces car il peut assez rapidement devenir plus un boulet qu’un atout.

Mais alors, dans quel cas faut-il utiliser AngularJS ? AngularJS est un outil fait pour construire des applications orientées gestion de données. Il excelle lorsqu’il s’agit d’afficher des données dans une page web et avoir un arbre DOM synchronisé en permanence avec les données. Pour le dire de manière un peu plus triviale, il est particulièrement adapté aux single page applications dont les fonctionnalités se résument plus ou moins à du CRUD.

A l’inverse, AngularJS n’est par exemple pas du tout adapté lorsqu’on s’éloigne de l’arbre DOM, ce qui est le cas par exemple lorsqu’il s’agit de manipuler des canvas. En effet, un canvas se dessine de manière programmative (en utilisant une API) plutôt que de manière déclarative (là où AngularJS excelle). En fait, dès qu’on sort du cadre du binding bidirectionnel sur un arbre DOM, AngularJS n’apporte plus grand chose, et je dirais même qu’il est plus pénalisant qu’autre chose, parce qu’il faut se lancer dans l’écriture de directives qui représentent le seul moyen qu’offre AngularJS pour interagir directement avec l’arbre DOM.

J’ai également le sentiment qu’AngularJS n’est pas très adapté quand il s’agit de faire une interface graphique assez complexe et riche, avec par exemple des interactions entre différents composants d’une application. C’est peut-être dû au fait que je n’ai pas beaucoup de pratique en AngularJS, mais j’ai vraiment du mal à voir comment il serait possible de faire avec AngularJS l’application sur laquelle je travaille depuis quelques temps qui comprend des particularités comme un scroll infini assez évolué ou encore beaucoup d’interactions entre les différentes parties des pages à travers de nombreux événements qui circulent dans un event bus (page visible ici).

Conclusion

AngularJS est de toute évidence un outil aux qualités multiples. Développer avec AngularJS est quelque chose de plaisant, surtout pour des petites applications, parce qu’en restant très simple, on arrive très rapidement à un résultat satisfaisant.

Quand AngularJS est sorti, j’ai bien cru qu’on tenait enfin le framework qui allait révolutionner le développement web. Mais après m’en être un peu servi, même si je reste emballé par la simplicité et la productivité de l’outil qu’il doit au concept de binding bidirectionnel, j’ai un sentiment de frustration par rapport à l’implémentation actuelle d’AngularJS qui n’est pas encore suffisamment mature pour devenir la plateforme de développement de demain.

Le concept est génial, mais à mon idée pas encore assez mature. Pour cette raison, j’attends beaucoup d’Angular 2.0 qui est censé entre autres corriger les problèmes de jeunesse de l’outil. Je ne me suis pas encore suffisamment penché sur la question pour savoir si cette nouvelle version sera vraiment l’outil de développement web de demain. Les polémiques du moment quant à Angular 2.0 semblent en tout cas montrer que cette nouvelle version est loin de faire l’unanimité.

L’image d’en-tête provient de Flickr.

Laisser un commentaire

Votre adresse de messagerie ne sera pas publiée. Les champs obligatoires sont indiqués avec *