Nouvelle application, la décision de partir sur Node.js est prise. L'application commence petite puis le nombre de features et de développeurs augmentent. Les 1ers refactoring cossus arrivent et ne se passent pas vraiment comme prévu pourtant nous avons 100% de coverage… Est ce lié au manque de typage de JS ? Est ce que TypeScript aurait évité ça ? Ou finalement est ce que c'est notre façon d'écrire notre code (et les tests) qu'il faut remettre en cause ?
Après quelques refactoring et bugfix l'application part en prod. Les utilisateurs commencent à remonter quelques soucis, en regardant les logs on prend peur, très difficile de s'y retrouver… Venant du monde Java on est surpris par le manque de maturité des frameworks et librairies Node.js, notamment au niveau de la gestion des logs et des erreurs.
Toutes ces (mes)aventures nous ont permis de prendre du recul sur le développement avec JS, nous vous proposons un retour d'expérience sur cette odyssée qui est toujours en cours.
32. • Passer les attributs dans chaque méthode
• Async Hooks API (experimental)
• ¯_(ツ)_/¯
P.32
Comment ajouter des attributs à tous les
logs ?
33. Logging
• Identification des éléments qui peuvent aider au debug (différents identifiants….)
• Convention pour les nommer de la même façon
• Librairie interne
- Partage de la configuration du Logger à tous nos projets
- Outillage permettant de respecter les conventions
P.33
46. TypeScript
• Typage statique permettant un feedback immédiat :
- Pour notre code de production
- Pour le code des librairies externes
- Pour nos tests
• Fonctions de refactoring des IDE
• Lib TS -> Api JS
• Lib JS -> Api TS
P.46
47. "Avoir des types c’est bien.
Avoir des types juste c’est mieux."
Développeur Anonyme
P.48
48. TypeScript
• Chaque API expose un package de types publics
• Utilisés par les autres APIs et les applications fronts, pour le typage :
- Des paramètres de requêtes HTTP
- Des contenus des messages RabbitMQ
P.49
63. Multi-stage builds
# Runtime image
FROM node:10.14.0-alpine as production
ENV API_PATH /usr/bridge/bridge-api-pm
WORKDIR $API_PATH
COPY --from=production-builder $API_PATH .
EXPOSE 8020
CMD ["node", "-r", "tsconfig-paths/register", "src/api-start.js"]
P.64
64. Multi-stage builds
# Runtime image
FROM node:10.14.0-alpine as production
ENV API_PATH /usr/bridge/bridge-api-pm
WORKDIR $API_PATH
COPY --from=production-builder $API_PATH .
EXPOSE 8020
CMD ["node", "-r", "tsconfig-paths/register", "src/api-start.js"]
P.65
143 Mo
65. Unhandled rejection
• Warning lorsqu’une promesse en erreur n’est pas
catchée
• Forcer l’arrêt du process Node dans ce cas
• Log pour aider au debug
process.on('unhandledRejection', error => {
logger.logUnhandledRejection(error);
throw error;
});
P.66
68. Inversify JS
P.69
A powerful and lightweight
inversion of control container for
JavaScript & Node.js apps powered
by TypeScript.
https://inversify.io/
71. Nest js
P.72
• Même principes qu’Angular (module, service, ioc)
• TypeScript (utilisation massive de decorators)
• REST et Messaging
• Enfin un framework Node digne de ce nom
https://nestjs.com/
72. Nest js
P.73
• Assez jeune
• Il reste quelques bugs mais rien de bloquants
https://nestjs.com/
Pourquoi Node.js /JS ?
Même language Front et Back
Apprentissage rapide pour les devs non web
Pourquoi Mongo?
Bonne perf en lecture
Aggregation pratique pour faire des stats ?
S’intègre bien avec JS, la creation des endpoints api qui lisent de la data très simplement (spoiler alert: fausse bonne idée)
Pourquoi Mongoose ?
Schema qui permet de valider les models
Pourquoi Express ?
- LA référence à l’époque
GAETAN
On partait de 0 donc on a bien fait attention à tester correctement nos apis.
Nous avons choisi Jasmine comme framework. Il a l’avantage d’être tout en un. Contrairement à Mocha qui demande une librairie pour les expectations (chai par ex) et une autre pour jouer avec des mocks (sinon).
ESLint
Assure le respect de standard (single quote, point virgule en fin d’instruction, …)
Evite les mauvaises pratiques (ex éviter de faire crasher l’application sur IE8 à cause des virgules sur le dernier élément d’un objet/tableau)
JULIEN
Et là le 1er bug arrive sans prévenir.
On regarde nos logs dans Kibana et on ne comprend rien.
On n’arrive pas à suivre ce qui se passe en prod.
Vu que Node.JS est mono threadé les logs sont « mélangés » il est donc difficile de s’y retrouver.
Et là le 1er bug arrive sans prévenir.
On regarde nos logs dans Kibana et on ne comprend rien.
On n’arrive pas à suivre ce qui se passe en prod.
Vu que Node.JS est mono threadé les logs sont « mélangés » il est donc difficile de s’y retrouver.
Partager
GAETAN
Pas de verif des variables
Les tests qui etaient toujours verts (alors que tout était casse)
Nous avons utilisé la lib proxyquire pour nous aider à « remplacer des dépendances des modules ». Ça nous a aidé à nous passer d’inversion de dépendance.
Nous avions tous une expérience différente sur les tests unitaires. Certains plus que d’autres, les tests ont été écrit après l’implémentation et dans l’idée de mocker toutes les dépendances. Ça combinait avec l’objectif de 100% de coverage, on s’est retrouvé à écrire pas mal de tests mais on était fier de cette couverture !
Manque de test d’integration => ajout quand le projet était encore en JS
Migration vers Jest :
- Snapshot testing -> super utile pour faire du refactoring
- --onlyChanged ou watch avec seulement les tests failed
MAIS TOUJOURS pas de typage
Ne pas se reposer sur Typescript pour les donnees en entree d’API
IO-TS
Ne pas se reposer sur Typescript pour les donnees en entree d’API
IO-TS
Ne pas se reposer sur Typescript pour les donnees en entree d’API
IO-TS
JULIEN
Remplacement par TSLint
TSLint bientôt déprécié
CommitLint
pour garantir les standards sur la forme des commits
ne fait pas tout reste à la charge du dev de réfléchir à comment synthétiser son commit
Prettier
plus de querelle de clocher pour savoir s’il faut mettre des points virgules…
S’occupe de formater les fichers automatiquement
Husky
Permet de configurer facilement des hook GIT.
Exemple:
exécution du ESLint et Prettier sur pre-commit (impossible de committer un fichier mal formaté)
Exécution de Commitlint sur commit-msg (contrôle le message écrit par le dev)
Ça n’empêche de configurer la CI pour s’assurer que tout va bien dans le cas où le dev by-pass ces validations
K8S peut tuer des pods quand il veut. On veut s’assurer qu’on ferme l’application correctement
GAETAN
GAETAN
Scope request non testableBug injection avec des symbols
GAETAN
Légèreté
Les apis utilisent peu de mémoire
Elles sont rapides à démarrer ce qui est très pratique dans notre environnement élastique
gestion dépendance -> monté de version mineur mais en fait non