Depuis plusieurs mois, le JavaScript est le langage le plus actif sur github, loin devant le Java ou le PHP. Outre une forte présence sur le côté « Front » des applicatifs, le JavaScript commence à gagner ses lettres de noblesse côté « Serveur ».
En témoigne aujourd’hui les nombreux projets autour de Node.js qui est de plus en plus choisi pour expérimenter des problématiques de temps réel ou de quasi-temps réel.
L’objectif de ces projets est de proposer des expériences utilisateurs dans des environnements très connectés (jeux vidéo, mobiles, sondage grand public, notification, etc.). A titre d’exemple, le chat et le moteur de recherche de Facebook sont développés en partie avec Node.js. L’application mobile de LinkedIn repose en majeure partie sur NodeJS.
Les premiers retours d’expérience montrent que cette technologie est encore jeune donc complexe à maitriser, en particulier sur des projets en production, mais très prometteuse. Elle a déjà trouvé un public et une communauté passionnée et dynamique.
Node.js pour des projets « temps réels » mais pas seulement…
V8, le moteur JavaScript de Chrome, est au coeur de Node et il est très performant grâce à son compilateur JIT (Just In Time). Dans Node.JS, il est associé à libuv, une librairie asynchrone. On obtient alors un ensemble très performant capable de traiter simultanément des milliers de requêtes. En effet, la conception asynchrone de Node.JS évite une programmation itérative « bloquante » et limite les attentes d’entrée/sorties (filesystem, appels HTTP, etc ..). Ce modèle asynchrone / événementiel n’est pas nouveau, il est même au coeur du serveur Web Nginx, l’un des serveurs Web les plus populaires sur Internet.
Au delà de la performance pure, c’est surtout le très bon ratio performance/taux d’utilisation des ressources qui est nouveau. Il rend Node.js capable de traiter une volumétrie importante de requêtes sur des machines basiques. A titre d’exemple, AF83, lors des élections présidentielles, a développé une solution de sondage en Node.js qui a permis de tenir 20 000 connexions à la seconde avec 1 seul processus attaché à un vCPU. De plus, la capacité de traitement de Node.JS peut facilement être répartie sur plusieurs vCPU grâce au mode cluster.
La réduction du temps de traitement et la capacité à traiter de nombreuses requêtes sont les critères majeurs qui amènent une équipe projet à choisir Node.js. Jusqu’à présent, il fallait faire du C, du C++ ou du Java pour se lancer dans de tels projets. Aujourd’hui, même si Node.JS ne permet pas de concurrencer ces langages sur certains besoins ultra temps réels, il le met à portée de beaucoup d’équipes.
Mais attention, faire des choses peu performantes en Node.JS arrive et il est tout à fait possible de coder des choses bloquantes sans s’en rendre compte par exemple.
Enfin, les librairies et modules exposés par l’écosystème Node.js facilitent la mise en œuvre d’API REST capable d’interagir dans des univers multi-devices : mobile, desktop, tv, etc. Cet avantage, couplé avec un langage qui offre une portabilité côté serveur, navigateur ou tout terminal doté d’un moteur JS, fait du couple Node.js/JavaScript un choix de prédilection pour certaines applications multi-devices ou pure web.
Ses qualités
Performances, ou plutôt capacité à gérer de très nombreuses requêtes simultanées.
Modèle événementiel / asynchrone,
Gestion native du HTTP et plus généralement de tous les protocoles réseaux (TCP/UDP)
Multi-plateformes (mobile, desktop, tv),
Portabilité du code JavaScript aussi bien côté serveur que client,
Une communauté très active.
Node.js nécessite une bonne maitrise du langage JavaScript : exit les (Java)Script-kiddies.
Node.js, c’est du JavaScript. Or, la vraie compétence JavaScript est rare : savoir utiliser Jquery ne veut pas dire être compétent en JavaScript. Un développeur JavaScript compétent est à minima capable de faire de la programmation objet (à partir des prototypes), fonctionnelle et événementielle.
La courbe d’apprentissage est donc longue, Node.js et JavaScript recèlent de nombreuses subtilités (scope, fonctions, this, événements).
La montée en compétence est vite consommatrice de temps. Pour les novices en programmation, il faut compter 4 à 5 mois pour commencer à maitriser l’environnement.
Son passé associé à l’animation de page HTML, l’a rendu impopulaire auprès des développeurs expérimentés. Mais, même si les aprioris sont encore forts sur ce langage, il est normalement très accessible pour des développeurs chevronnés. Après avoir expérimenté un premier projet, ils sont souvent convaincus et même très enthousiastes à propager la bonne parole !
Les limites de Node.JS
– la complexité de la programmation événementielle
Le modèle asynchrone est un concept très important : il est omniprésent dans le fonctionnement de Node.JS.
Même après quelques utilisations, on peut facilement tomber dans des pièges de conception asynchrone.
A titre d’exemple, même une fonction d’écoute de port est asynchrone :
var server = require(‘http’).createServer(
server.listen(8080, function (){console.log(‘listening on 8080’)})
console.log(‘hello’);
donnera
hello
listening on 8080
Cette programmation événementielle rend le débogage plus compliqué : il faut faire des callbacks, bien passer les contextes, gérer les exceptions… et surtout leur contexte. Pour la gestion des exceptions, 2 possibilités s’offrent aux développeurs : attraper toutes les exceptions et correctement les traiter ou simplement redémarrer. Chez Fasterize, toutes les exceptions sont attrapées sans que les process ne s’arrêtent mais par contre, ces exceptions sont ensuite remontées. Heureusement, pour faciliter la tâche, on retrouve des outils comme node-inspector basé sur le debugger JavaScript de Chrome (breakpoints, stacks, etc.).
– Une v1 qui se fait attendre
Nouvelle lib HTTP, SSL performant, cluster clean, execution des child process en mode synchrone et des tonnes d’améliorations tournées vers la performance, c’est peu de dire que cette nouvelle version est attendue (et depuis plus longtemps que les précédentes) !
– Trop de modules tue le module
De 5000 à 65000 en deux ans ! Presque 300 nouveaux modules par jour ! L’écosystème des modules est fantastique, on trouve tout ce qu’on veut mais le revers de la médaille est qu’il faut chercher et trouver le bon module, à savoir un module testé, utilisé et maintenu.
– Windows ?
La très grande majorité des développeurs NodeJS sont sous Mac ou Linux et Windows fait étonnamment figure de parent pauvre dans ce monde. Les développeurs sous Windows galèrent régulièrement à cause de modules ou de fonctionnalités qui ne sont pas pensés pour leur OS …
Architecture
– Une architecture logicielle adaptée à Node.js
Node.js exige de réaliser des applications simples et spécialisées pour maîtriser la complexité induite par l’asynchrone. Il faut concevoir une architecture logicielle adaptée à Node.js avec un découpage des actions complexes en applications simples et spécialisées. La philosophie est d’ailleurs assez proche d’Unix/Linux avec une multitude de petits programmes faisant une seule chose mais qui le font bien, avec une entrée, une sortie et qu’on peut chainer entre eux (cf. awk | grep | sort | uniq). Par exemple, Fasterize a conçu son moteur de webperformance en SaaS en distribuant des tâches sur des workers asynchrones ou bien au niveau du proxy, en injectant des middlewares chacun responsable de la modification d’une partie de la requête.
En fait, assez rapidement, on en vient à créer ses propres modules et à les assembler. Comme dans tous les langages, la gestion des modules est quelque chose de complexe (dépendances) mais NodeJS a réussi dans la majorité des cas à en faire quelque chose de simple grâce à npm (Node Package Manager), l’outil de gestion des modules intégré à Node. Reste que cette gestion n’est pas parfaite et qu’il existe des débats sur l’utilisation de npm / git / node_modules.
– En production
En production, comme tout process server, il faut prévoir un mécanisme de surveillance. Chez Fasterize, vu l’immaturité des outils, tout le cablage classique a été redéveloppé : gestion des PID, logs, des services, etc…. Aujourd’hui, de nombreux modules existent pour ça.
Il faut encore être très vigilant sur les mises à jour de vos modules. La communauté enrichit (trop) rapidement l’éco-système de modules prêts à l’emploi et cela peut avoir un impact sur les performances ou même le fonctionnel. Il faut donc rester prudent sur la montée en version et avoir une politique rigoureuse de tests.
Scaler ses applications NodeJS n’est pas plus compliqué que pour les autres langages, il faut juste bien concevoir son application pour qu’elle soit distribuée, stateless et asynchrone. Par contre, grâce au module cluster, NodeJs peut scaler facilement d’une machine à une autre plus puissante et disposant de plus de coeurs CPU. Comme chaque NodeJS est monothreadé, il ne tourne par défaut que sur un seul coeur. Le module cluster permet de déployer le même process sur tous les coeurs de la machine. Par contre, ce module n’est pas encore nickel et la distribution sur les process n’est pas parfaite (une option round robin gérée par le Kernel arive) et il faut gérer beaucoup de choses à la main (pas de graceful restart intégré par exemple).
Le debugging/profiling n’est pas évident à mettre en place mais commencent à apparaître des outils comme intégrés comme StrongOps après Nodetime ou TraceGL. En production, et NodeJs est magique pour ça, existe la possibilité de se connecter au process directement et d’inspecter tout ce qui a été exposé (node-repl), c’est extrêmement pratique pour comprendre ce qui peut se passer uniquement en production !
Déploiement d’un projet Node.JS
Pour déployer un projet NodeJS, il existe principalement deux manières : la première et la plus simple est d’utiliser un PaaS, la seconde est d’utiliser ses propres serveurs et de tout cabler soi même.
Parmi les PaaS acceptant NodeJS, on peut citer : Heroku, NodeJitsu, CleverCloud, dotCloud, Azure, Engine Yard.
Chacune de ces plateformes permettent de développer en local, de déployer très simplement (soit avec un git push soit avec un client spécifique) puis de configurer le lancement de ces applications.
Sans PaaS, il existe quelques outils de déploiement pour node mais aucun n’a franchement émergé, il faut donc souvent soit utiliser des outils non spécifiques à NodeJs, soit coder ses propres outils. Chez Fasterize, c’est Capistrano qui a été utilisé et adapté car il avait déjà fait ses preuves dans les environnements RubyOnRails (possibilité de rollback, versionning des déploiements, etc …)
Bonnes pratiques
D’abord les bonnes pratiques que tout développeur doit respecter : mettre en place des tests unitaires. Les frameworks sont nombreux (mocha, sinon, should, etc …), fonctionnent très bien et sont bien documentés, c’est donc obligatoire !
NodeJS c’est de l’asynchrone et il est très facile de tomber dans le piège de « race conditions », même après des années de pratique. Dans les cas complexes, il peut être intéressant et utile de passer par des libs de de flow control comme async ou bien par les promises.
Ensuite, NodeJS c’est du JavaScript et il faut donc faire attention au problème de scope, de this, aux closures, aux erreurs dues au typage dynamique, etc …. C’est du Javascript qui tourne sur V8 et les développeurs ont souvent tendance à faire de la micro-optimisation contre-productive vu la façon dont le compilateur fonctionne. Il faut donc tester et mesurer pour prouver.
D’ailleurs, c’est une constante : il faut mesurer le plus possible. Consommation mémoire pour détecter les memory leaks, temps passé dans la boucle événementielle pour détecter les blocages, etc … Par exemple, c’est comme ça que Fasterize a détecté des memory leaks dans la lib HTTP et dans la lib Gzip.
La communauté et la pérennité de Node.js
Beaucoup de personnes de la communauté prennent un véritable plaisir à expérimenter et construire autour du projet. Elle est incroyablement dynamique. Les modules sont arrivés très tôt et sont un véritable vecteur pour la communauté. Ils suscitent un fort engouement des développeurs qui dynamise le participatif : les évolutions sont donc très rapides et aussi maîtrisées. Par exemple, le développement du noyau est séparé des modules et ce qui confère une bonne stabilité au cœur de Node.js.
Aujourd’hui, Node.js est comme un nouveau continent à explorer, les contributeurs se permettent d’inventer ou réinventer des concepts. Il est peu étonnant qu’elle constitue l’une des communautés les plus actives sur GitHub. En revanche comme toute communauté naissante, elle se structure pour gagner en maturité et ces dernières semaines, les premiers drames entre acteurs importants de cette communauté sont apparus …
——————————
Notre stack technique
Un schéma du moteur
Et encore plus général
Cet article a été rédigé en collaboration avec notre partenaire Oxalide, acteur de premier plan en infogérance et hébergement.