Jérémy Le Piolet - Blog

Petit retour d’expérience sur NodeJs

Arrivé comme un éléphant dans un magasin de porcelaine, la technologie NodeJs bouscule depuis plusieurs années le monde du web. Véritable « révolution », c’est la techno à la mode, celle qui fait rêver les jeunes, celle qui résout tous les problèmes et fait repousser les cheveux.

D’ailleurs, tous les grands y sont passés : Netflix, Paypal, Linkedin, tous ont mis en place avec succès la technologie pour des gains hallucinants. Ne pas développer sous NodeJs en 2019 est inconcevable tant tout le monde devrait déjà y être.

Mais derrière toutes ces félicitations, qu’en est-il réellement ? Est-ce vraiment la technologie parfaite ? Petit retour d’expérience.

Mise en contexte

J’ai commencé à utiliser NodeJs en 2011. La technologie avait deux années et on commençait à voir des projets intéressants se mettre en place (ExpressJs par exemple, l’un des plus anciens frameworks, avait quelques mois). C’était clairement le temps des Proof Of Concept (PoC), des petites démonstrations rigolotes, du prototypage en tout genre.

Il faut dire que NodeJs dénotait avec le serveur web phare de l’époque, Apache (Nginx commençait doucement à le titiller). Des temps de réponse ultra-rapides sans faire grand-chose, une consommation mémoire plus faible et surtout de nouvelles opportunités d’interaction.

Mes premiers projets portaient sur de la mise en place de chats (le dialogue entre deux personnes, pas l’animal), des salons de discussion via WebRTC, de la communication avec Websocket, tout un tas de technologie qu’il était quasiment impossible de mettre en place avec un serveur Apache sans s’arracher quelques cheveux. C’était clairement plaisant de défricher toute cette nouveauté et les possibilités étaient énormes.

Petit à petit, l’engouement a pris pour la technologie et beaucoup de nouvelles choses ont émergés. Désormais, NodeJs n’est plus utilisé que comme serveur web mais sert de base à des applications bureautiques (Atom ou VsCode reposent dessus). Il y a une quantité impressionnante de modules et d’outils disponibles et il est à peu près possible de faire tout et n’importe quoi avec. Les frameworks web modernes (VueJs, React, Angular) reposent tous sur NodeJs comme outil de build.

Logo d'electron, plateforme pour application desktop reposant sous NodeJs
Electron, plateforme pour application desktop reposant sous NodeJs

Bref, sur le papier, NodeJs semble être la technologie unique, celle qui va réussir à toutes les lier (en tout cas, lier toutes les technologies web).Sauf qu’il y a toujours une différence entre la théorie et la pratique et que faire de gentils prototypes dans un coin n’est pas développer pour de la production. Et là, clairement, la marche n’est pas franchie, malgré la liste importante de grandes sociétés qui ont soit-disant migré.

Une technologie stable…

Si je ne prends en considération que le cœur de NodeJs, ce qui est uniquement accessible de base, je pense qu’on peut dire qu’en 2019, on est arrivé à une certaine maturité et une certaine stabilité de la plateforme.

Comme dans tout projet OpenSource, il y a eu des hauts et des bas, des divergences sur la gouvernance, des forks puis des réintégrations : très classique. Actuellement, il y a une fondation derrière, les releases se font selon un planning annoncé largement en avance, il y a de la prise en charge de version Long Term Support (LTS), il y a des comités dédiés à certains aspects (par exemple, sur la sécurité), … Pour moi, le cœur est stable.

J’ai d’ailleurs eu l’occasion de reprendre mes premiers codes réalisés avec NodeJs en 2011 et j’ai eu l’agréable surprise de constater qu’il n’y avait pas grand-chose à toucher pour qu’ils fonctionnent sur les versions plus récentes. Certes, on était sur du code simple, peu ou pas de dépendances, mais ça montre qu’il y n’y a pas eu de changements majeurs sur la plateforme, qu’il y a une volonté de pérennité.

De la même façon, NodeJs étant multi-plateforme, j’ai rarement été confronté à des problèmes de compatibilité entre Linux et Windows. Il y a toujours des petites subtilités dès qu’on touche au système de fichier ou aux variables d’environnement mais là encore, c’est ultra-classique comme problème, inévitable et quasi transparent quand on a un peu de bouteille.

En résumé, NodeJs est pour moi mature.

Son écosystème pas du tout.

… pour un écosystème pas fiable

Quiconque a dépassé le stade de prototypage avec NodeJs sait de quoi je parle : développer et maintenir son application est une horreur.

L’enfer des 10 000 modules

Ça commence dès l’initialisation du projet. Comme le cœur de Node est relativement basique, on en vient très vite à devoir utiliser des modules complémentaires. Et c’est là que les ennuis commencent : il y a des milliers de modules différents, s’y retrouver est presque impossible.

Il y a au moins 10 modules différents pour le même problème et aucun consensus réel sur lequel utiliser ; c’est un peu du pile ou face en fonction des dates de derniers commits, du nombre de contributeurs, du nombre d’étoiles github et de son référencement dans des listes des « meilleurs modules » (par exemple, awesome node : https://node.cool ).

Même chez les plus suivis, il n’y a rien de commun : pour un framework web, dois-je plutôt utiliser Express ou Hapi ? Peut-être Meteor, qui semble différent ? Ou Next.js, qui semble être la nouveauté du moment ? C’est clairement du hasard une bonne partie du temps et on serre très fort les doigts pour qu’à un moment donné du projet, on ne tombe pas sur un module incompatible. Parce que oui, bien entendu, il y a des problèmes de compatibilité (je passe sur les documentations incomplètes et les erreurs non documentées).

Pérennit quoi ?

On pourrait croire qu’une fois sa stack trouvée, ce serait plus simple. Que nenni ! La communauté NodeJs/Javascript a une fâcheuse tendance à tout casser tous les 2 mois sans prévenir et surtout sans assurer de rétro-compatibilité. Si c’est moins vrai sur les plus gros projets (et encore, le passage d’Angular 1 à 2 en est un bon exemple), certains modules plus spécifiques ne se privent pas de le faire et c’est aux utilisateurs de se débrouiller pour mettre à jour, quitte à devoir reprendre une bonne partie de leur code.

C’est tout bonnement inconcevable pour un projet en production. J’ai eu un projet de 6 mois où il a fallu reprendre 3 fois en intégralité les scripts de production parce que les outils nécessitaient une mise à jour (correctif de bug, sécurité) et qu’à chaque fois il y avait de grosses corrections à faire.

Alors oui, c’est de l’Open-Source, c’est mis à disposition bénévolement, tout ça. Mais ce n’est pas la seule communauté Open-Source et d’autres fonctionnent très bien. Pourquoi développer chacun son module dans son coin au lieu de se mettre à plusieurs sur le même ? On éviterait ainsi la jungle et on assurerait un peu plus de pérennité plutôt que de redévelopper quelque chose à chaque fois.

Logo de Npm, le gestionnaire de module de NodeJs. CC By SA @Boboss74
Logo de Npm, le gestionnaire de module de NodeJs. CC By SA @Boboss74

Réinventons la roue

D’ailleurs, cette tendance à réinventer la roue est assez symptomatique de la communauté. Du côté des outils de génération, j’ai connu Grunt, Gulp, les scripts Npm, Browserify et maintenant Webpack (et j’ai passé mon tour sur certains). Ce sont des outils qui permettent d’automatiser bon nombre de traitements : minification des css, optimisations diverses, transpilage (conversion des nouveautés du langage javascript vers des versions plus anciennes), tests unitaires, etc.

Si cet outillage est un véritable apport dans les processus web (surtout côté front), il faut systématiquement changer d’outil tous les ans. Parce qu’une fois le nouveau sorti, il n’y a plus grand monde qui maintient l’ancien.

Pire que ça : votre module qui fonctionnait très bien avec l’ancien outil, dans sa nouvelle mise à jour, il n’est plus compatible qu’avec le nouveau. Donc, même en voulant limiter le changement, on y est obligé. Et bien entendu, chaque nouveauté ajoute une bonne surcouche de complexité. Ce n’est pas compatible avec de la production.

Là encore, on pourra me dire que des sociétés comme Netflix ou Paypal l’utilise bien en production. D’abord, si ça fait au moins 5 ans que j’entends dire que Netflix utilise NodeJs, en pratique, ils ne l’utilisent que pour la moitié de leur service et ce depuis moins de deux ans.

Ensuite, il faut comparer ce qui est comparable : Facebook, Microsoft, Google, Netflix, ce sont des monstres, des applications avec des millions de connexions simultanées, avec de grosses équipes qui peuvent se permettre d’avoir des personnes qui maintiennent à jour.

Ils ont d’ailleurs trouvés la parade : ils développent leurs propres outils, comme ça ils restent maîtres des évolutions (coucou React). Rien de comparable avec une entreprise de taille standard qui va avoir, au maximum, une équipe de 5 personnes sur son application, chef de projet et testeur inclus. Il y a bien souvent des applications internes sur des intranet qui ne sont maintenus que par une seule personne à 40%.

Donc non, NodeJs n’est pas mature ni prêt pour le passage en production. Si mes premiers projets simples en NodeJs datant de 2011 tournent encore sans trop de modifications, ce que j’ai fait il y a 2 ou 3 ans, c’est quasiment certain que non. Ou alors en gardant des anciennes versions sans appliquer de correctifs et en laissant des trous de sécurité.

Je m’étends beaucoup sur les problèmes de l’écosystème de NodeJs car c’est probablement le gros point noir de la technologie. Il faut en être conscient lorsqu’on démarre un nouveau projet : pour un prototype jetable, il n’y a aucun soucis. Pour de la production et de la pérennité, il faut y réfléchir à deux fois.

Standards et qualité

Ce qui m’amène d’ailleurs à parler de standards de développement et de qualité de code. Je ne vais pas m’étendre longuement sur javascript en lui-même, tout le monde sait qu’il a des problèmes, ce n’est pas nouveau. On aime ou on n’aime pas le langage, là encore, ce sont des problématiques de goûts et de couleurs : si on utilise NodeJs, on sait qu’on va avoir à jongler avec, on n’y coupe pas.

L’une des difficultés lorsque l’on est sur un projet NodeJs (et javascript en général), c’est le manque de standardisation dans la conception. Il n’y a aucune réelle bonne pratique qui se dégage, c’est un peu au bon vouloir des développeurs. Si cette liberté semble intéressante, c’est aussi un frein. Je ne crois pas avoir fait un seul projet NodeJs qui était structuré de la même façon. Même moi, je ne structure pas mes projets de la même façon.

Parce qu’on utilise pas les mêmes dépendances, les mêmes frameworks, les mêmes outils, on essaye d’adapter ce que l’on connait aux nouveautés. C’est très mouvant et même quand il semble y avoir un semblant de cadre, ça reste soumis à interprétation (il suffit de prendre Flux et Redux).

Cela rend très difficile l’intégration de nouvelles personnes aux projets, qu’ils soient des débutants ou non. À chaque fois, il faut prendre le temps de comprendre la logique sous-jacente, de comprendre comment tout fonctionne. Il y a quelques petites choses communes mais chaque nouveau projet que j’ai pu reprendre m’a donné l’impression de démarrer quelque chose de complètement nouveau.

En comparaison, j’ai eu l’occasion de travailler sur quelques projets PHP avec des frameworks différents, je n’ai jamais été perdu, j’ai toujours retrouvé mes petits rapidement. Tout n’est pas identique mais il y a des patterns communs, des standards. En NodeJs non.

Le mythe de l’équipe unique

Et je pense que le manque de standardisation est beaucoup plus important sous NodeJs car on a des populations radicalement différente. En promettant de réunir front-end et back-end sous la même bannière du javascript full-stack, NodeJs amène des publics différents à travailler sur des problèmes auxquels ils ne sont pas formés.

Les problématiques front-end et back-end sont différentes : les uns s’adressent à des utilisateurs, les autres gèrent des traitements et des interactions entre machines. Ce n’est pas parce que tout le monde utilise la même technologie que tout va magiquement fonctionner ensemble.

Je ne connais pas, personnellement, de personne qui soit réellement compétente dans les deux domaines (personnellement, s’il m’arrive de faire du PoC sous NodeJs, je ne me considère pas comme développeur back-end). Pareillement, je n’ai presque jamais vu de projet NodeJs/Javsacript qui avait du code partagé entre le front et le back, même si les deux utilisaient javascript. On a, au mieux, quelques bouts qui peuvent être mutualisées mais c’est extrêmement rare, même en utilisant des approches Server Side Rendering pour le front (SSR).

Javascript des deux côtés simplifie la communication et les échanges. On peut partager des configurations d’IDE, on peut partager des astuces du langage mais ça s’arrête là. Ce n’est pas parce qu’on sait jouer au poker qu’on sait jouer à la belote, même si les cartes sont identiques. Chacun sa spécialité.

Je suis assez critique parce que la plateforme m’est régulièrement sur-vendue, souvent par des personnes ayant moins d’expérience que moi. Mais elle a aussi de bon côté et il faut les noter.

Une rapidité et une gestion de la charge excellente

NodeJs est très facile à prendre en main et multiplateforme. On peut sortir quelque chose d’acceptable en très peu de temps sans grande connaissance. Le ticket d’entrée pour les débutants est très faible et c’est un compagnon idéal pour les PoC et les prototypes : on peut maquetter très rapidement pour tester de nouvelles choses, ça se fait tout seul. La contrepartie est ce que je présentais plus haut : peu de standards, de la maintenance ardue et de réelles difficultés à passer du prototype à la production.

NodeJs est également extrêmement rapide, de part son fonctionnement avec I/O non bloquantes. Un serveur Apache, quand il lance une requête à la base de données, il reste reste attendre le résultat. Si la requête prend 300ms, il restera attendre 300ms. NodeJs lui va lancer la requête et faire autre chose. Pendant les 300ms, si d’autres requêtes arrivent, il va les traiter et, lorsque le résultat de la première requête est disponible, il conclura ce qu’il avait initié.

Comparaison du fonctionnement du serveur Apache et du serveur NodeJs pour la lecture d'un fichier. Sous apache, le traitement est lancé puis le serveur se met en attente du retour de la lecture du fichier. Sous NodeJs, le traitement est lancé mais le serveur fait autre chose en attendant le retour du fichier.
Comparaison de fonctionnement entre Apache et NodeJs

Ce fonctionnement lui permet d’encaisser de nombreuses requêtes tout en proposant des temps de réponse courts sans faire grand chose. Il faut toutefois faire attention à la façon dont le code est structuré.

NodeJs est non bloquant uniquement sur les entrées/sorties. Hors, si vous avez un traitement lourd qui s’exécute et ne nécessitant pas d’accès I/O (un tri sur un gros tableau par exemple), il va être « bloqué » sur l’exécution de ce code. Là où Apache va lancer plusieurs processus/thread pour traiter les demandes en parallèle, NodeJS est mono-threadé. C’est à dire que s’il est bloqué sur l’exécution du code, les autres requêtes ne sont pas traitées tant que l’exécution du code ne sera pas terminée. Donc des temps de réponses qui explosent.

Je le sais, je l’ai fait 🙂 Et la première fois que ça arrive, on se pose des questions parce que jusque là, ça ne posait pas de soucis. Et on regarde un peu plus ce qu’il y a sous le capot et on comprend très vite qu’il faut déporter un maximum de traitement. Souvent, c’est juste avoir une seconde instance de Node qui tourne et qui exécutera les traitements lourds pendant que la première gère les requêtes.

Mais il faut le savoir : NodeJs est bon comme passe-plat, moins pour le travail de longue haleine. En cela, il est particulièrement bien adapté au monde des objets connectés. Les objets connectés envoient régulièrement (via websocket par exemple) de nombreuses informations très courtes avec de très courts traitements à effectuer. Par exemple, le capteur de température envoie la température et NodeJs regarde si elle tombe sous un seuil ou non. Si oui, elle déclenche le chauffage. C’est court, c’est simple, c’est très rapide et NodeJs excelle là-dedans.

Son côté passe-plat est également intéressant pour la mise en place d’une architecture sous forme de micro-service. C’est d’ailleurs ce qui est mis en place chez Netflix : de petites instances qui font juste une chose et qui se délèguent les traitements les unes les autres. On a ainsi une bonne scalabilité horizontale qui permet d’encaisser les montées en charge.

Attention en revanche à ne pas prendre le problème dans l’autre sens : les architectures en micro-services qui favorisent la scalabilité horizontale se marient bien avec NodeJs, ce n’est pas parce que vous utilisez NodeJs que vous allez avoir une plateforme scalable et bien architecturée.

Conclusion et perspective

Finalement, que penser de NodeJs ?

C’est une technologie ô combien intéressante, avec de réelles capacités mais malheureusement sur-vendue et toujours immature.

Si votre objectif est un prototype ou un PoC, vous pouvez utilisez NodeJs sans problème. Vous allez souvent être plus rapide et les problèmes de compatibilité/mise à jour ne vont que rarement vous concerner (si un PoC dépasse un an de vie, c’est peut-être que ce n’est plus un PoC).

Si votre objectif est de refondre un système complet type Intranet/SI, oubliez NodeJs, on trouve bien mieux et plus stable ailleurs, que ce soit en PHP, Python ou même Java. Démarrer un gros système sous NodeJs implique de chercher tous les composants qui vont bien, de la gestion de l’internationalisation à la validation des données en passant par l’ORM, les gestionnaire d’API, la librairie de tests unitaires, en priant pour que tout soit compatible et que la mise à jour de l’un ne casse pas tous les autres.

Si votre problème c’est la rapidité et la consommation de ressources, remplacez Apache par Nginx, ça fait des miracles. De la même façon, une architecture scalable peut se mettre en place avec n’importe quel technologie donc ce n’est pas forcément utile de passer à NodeJS. Surtout si vos équipes ne sont pas familières avec le développement javascript : il faut bien se former et évoluer un jour mais pour Node, ça peut attendre encore quelques années je pense.

Là où NodeJs commence à se justifier en production, c’est dans le cas de systèmes qui vont gérer beaucoup d’entrées/sorties. Pour de la gestion de domotique et d’équipement connecté, c’est un outil qui est pertinent et excellent.

Attention quand même à la sécurité : le nombre d’objets connectés qui sont truffés de faille est légion et NodeJs, si on n’y prête pas particulièrement attention, ne propose rien de sécurisé par défaut. Les ressources sur la sécurité en Node ne sont pas légions et qui n’a pas le réflexe d’aller de temps à autre sur le site de l’OWASP par exemple passe à côté de beaucoup de choses. Les frameworks PHP ont de positifs qu’ils incluent quasiment tous par défaut des protections contre les injections SQL via leurs ORM par exemple ; les frameworks NodeJs, c’est beaucoup plus aléatoire (avec forte tendance vers le non).

Il est bien évidemment possible de n’utiliser NodeJs que partiellement dans une architecture plus complète. Vous pouvez très bien avoir un site web classique en PHP ou Python et avoir un module de chat qui repose sur NodeJs. Le chat nécessite une forte réactivité d’où l’utilisation de Node mais le reste, plus classique, peut tirer partie des meilleurs outils disponibles en PHP ou Python.

C’est d’ailleurs la solution qui me semble la plus pérenne à l’heure actuelle : n’utiliser NodeJs que lorsqu’il apporte vraiment quelque chose, pas juste pour la hype !

Compléments

Si vous voulez en savoir plus sur quelques points évoqués dans cet artcile, voici une petite sélection de liens et de vidéos :