Skip to content

Commit

Permalink
Add ESM - part 2
Browse files Browse the repository at this point in the history
  • Loading branch information
octo-topi committed Sep 8, 2023
1 parent 90a541f commit ae4e136
Show file tree
Hide file tree
Showing 6 changed files with 179 additions and 0 deletions.
179 changes: 179 additions & 0 deletions _posts/2023-09-06-migrer-de-commonjs-vers-esm-migration.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,179 @@
---
layout: post
title: "Migrer de CommonJS vers ECMAScript Modules - #2"
date: 2023-09-06 14:04:00 +0200
categories: javascript
excerpt: "Récit d'une aventure : migrer 400kLoc NodeJs en deux mois - Le faire"
cover:
image: "cjs-to-esm.png"
source_url: https://raw.githubusercontent.com/wessberg/cjstoesm/master/documentation/asset/logo.png
authors: pierre_top
---

## Y'a quoi au menu ?

(Cet article est la suite de [la théorie sur la migration ESM](post_url 2023-08-25-migrer-de-commonjs-vers-esm %}.)

Il explique enfin comment nous nous y sommes pris pour migrer l'API du monorepo [Pix](https://github.com/1024pix/pix/tree/dev/api).

Si vous n'avez que cinq minutes, lisez [la stratégie](#la-stratégie).

Si vous avez un peu plus de temps, choisissez dans le menu.

Voilà les plats principaux :
- monter et faire vivre [l'équipe dédiée](#léquipe)
- [la stratégie](#la-stratégie) de migration
- faire de la [mise en production](#en-approchant-de-la-production) un non-évènement

Et si vous êtes gourmands, lisez tout du début à la fin...

## L'équipe

### Traiter les besoins internes
Chez Pix, le développement est effectué par des [Feature Teams]( https://github.com/1024pix/pix-lifestyle/blob/main/organisation/equipes.md) (FT), qui reçoivent les besoins utilisateurs principalement par le Product Owner (PO). Les développeurs peuvent participer au recueil et au raffinement du besoin, et le questionner lors de l'implémentation (le détail est expliqué [ici](https://m.youtube.com/watch?v=r0VmGhjnJr4)).

Les besoins d'amélioration interne au pôle engineering, dont fait partie la migration ESM, suivent un processus particulier, appellé "Impact Team". Des développeurs sont détachés de leur équipe pour un temps défini, en général quelques semaines, avec un objectif clair, même si le sujet est exploratoire.

Pour la migration ESM, un développeur a fait une présentation de 15 minutes à tous les autres développeurs, en exposant le besoin et la solution qu'il proposait. Il a ensuite proposé qu'un autre développeur, volontaire, le rejoigne pour deux semaines afin de réaliser la migration.

### Travailler ensemble

La taille de l'équipe est importante : elle a permis de combiner les connaissances et les absences ponctuelles ; autrement dit, elle évitait les dépendances. Il y avait bien sûr un [surcoût](#coût-de-coordination-et-complexité) par rapport à confier le travail à une seule personne, mais la complexité du sujet était trop grande.

Le développement, dès le début, s'est fait en pair programming, en rotations de 30 minutes, la plupart du temps en présentiel. Le pair programming est [encouragé chez Pix]( https://github.com/1024pix/pix-lifestyle/blob/main/pratiques/pair-et-mob-programming.md ) et il a été crucial ici : répartir la connaissance, trouver les solutions et se soutenir lorsqu'il fallait effectuer des corrections manuelles.

Les corrections manuelles ont aussi été faites en pair programming, même si on pense spontanément à paralléliser les tâches répétitives. En effet, la personne qui ne code pas, pendant que son partenaire modifie les fichiers :
- signale les erreurs d'inattention ;
- pense aux cas qui ne sont pas couverts ;
- suggère de meilleurs moyens d'effectuer la correction (ex: grouper les fichiers) ;
- prend du recul sur ce qui se passe.

Être deux nous a permis de prendre soin l'un de l'autre et de mener à bien la migration ; seuls, nous n'aurions pas reconnu la fatigue et aurions persisté dans des solutions qui étaient des impasses. Mon ressenti est qu'il a été plus facile de prendre soin de l'autre que de moi-même, et que l'autre me rappelait quand je ne prenais pas soin de moi.

En plus de cette boucle de feedback de 30 minutes, il y en avait une aure boucle quotidienne. La journée commençait avec un partage de 15 minutes de l'avancée avec les CTO, sur la base d'un résumé fait en fin de journée sur le Wiki interne. Cela permettait à l'équipe de prendre du recul sur ce qui s'était passé, et aux CTO d'envisager des actions pour enlever des obstacles : suggérer des expérimentations, demander de l'aide aux autres équipes.

Ce partage quotidien a assuré la confiance. Lorsque les deux semaines initialement imparties étaient écoulées, les CTO ont décidé que la migration pouvait être poursuivie, sachant que nous traitions les risques les plus importants en premier. Si la migration s'avérait impossible, ils le sauraient rapidement et pourraient décider d'arrêter le chantier.

Ne gardons pas le suspense plus longtemps, d'autant que la présentation de l'article le mentionne : la migration a pris deux mois au lieu des 2 semaines annoncées ([ce qui était prévisible après tout](#estimation])).


## La stratégie

Parler de stratégie n'est pas tout à fait honnête, car nous n'avions pas de plan, uniquement quelques principes.
Nous partageons ici notre expérience pour vous aider à en avoir une si vous vous lancez dans l'aventure.

### Un feedback rapide
Nous n'avons envisagé la migration que parce que nous avions des tests automatisés avec une bonne couverture.

La démarche classique de refactoring (car c'en est un) aurait été de migrer un fichier (SUT) en ESM et de vérifier que le test passe toujours. Le test (CJS) importerait le SUT (ESM), qui lui-même importerait des dépendances (ESM).
Pour cela, il faudrait que ESM et CJS soient interopérables, et bien que le sujet commence à être [implémenté et documenté](https://github.com/johnloy/esm-commonjs-interop-manual#tooling), l'investissement ne semblait pas être un bon compromis.

Nous pensions procéder en trois étapes :
- migrer l'implémentation et effectuer un test manuel, à savoir démarrer l'API ;
- exécuter [les tests automatisés de bout en bout (front + back)](https://github.com/1024pix/pix/tree/dev/high-level-tests/e2e) ;
- migrer les tests automatisés de l'API puis les exécuter.

La conséquence était la suivante : pendant la première partie, nous n'avions plus aucun test qui nous couvrait.
Autrement dit : nous avons modifié la moitié de la codebase sans savoir si nos modifications étaient correctes. Même la vérification statique (lint) n'a pas fonctionné tout de suite, car un fichier dont le code est invalide ne peut être parsé. Les modifications étant effectuées par des codemods et des modifications manuelles, si elles se révélaient incorrectes et qu'il fallait les rejouer, nous n'étions pas à l'abri de devoir refaire ces actions manuelles.

Au fur et à mesure que les deux semaines se sont allongées, nous ressentions de plus en plus le poids d'une épée de Damoclès. À la prochaine migration de codebase, il serait judicieux de remettre en cause cette stratégie !

Nous avons découvert en cours de route une solution intermédiaire pour retrouver du feedback rapide : remplacer certaines fonctionnalités CJS difficiles à migrer en ESM par d'autres fonctionnalités CJS, elles-mêmes faciles à migrer. On profite ainsi des tests automatisés en développement et de l'utilisation en production.

### Choisir ses combats

On ne pouvait pas gérer toute la syntaxe, on a écrit les codemods obligatoires
Le reste est modifié manuellement. Ce n'est pas un échec.


Cela aboutit, après plusieurs tentatives, à ce ![workflow de développement](/assets/images/posts/migrer-de-commonjs-vers-esm-migration/codemod-workflow.png)

"Codemodception"

CJS=>CJS
https://github.com/1024pix/pix/pull/5715
https://github.com/1024pix/pix/pull/5747


### Le choix des exports nommés

Sondage dans les équipes

Exception : les fichiers qui n'exportent qu'un seul objet (use-case)
https://github.com/1024pix/pix/pull/5787/files#diff-734269ab23f38145d1f6742bd4282022dc6d47a8f57c3e2b372e45da7f1d88f4



Ou alors on transforme les exports anonymes CSJ en exports nommés CJS (et les imports aussi).

Ca permet de lancer les tests en CJS donc d’aller plus vite.

Et du coup il reste plus que deux codemods CJS=>ESM qui ne gèrent que les imports/exports nommés (simples!).

générer un import nommé ESM (on part du principe que le nom de la variable est prévisible, c’est le nom du fichier snake-case transformé en camelCase/PascalCase)

https://github.com/1024pix/pix/pull/5731

### Les tests mockés et l'injection de dépendance


## En approchant de la production

### Le suivi et la motivation
L'équipe de production a affiché l'avancée de la migration sur [Are we ESM yet ?](https://1024pix.github.io/areweesmyet/).

C'est une [Github page](https://github.com/1024pix/areweesmyet) avec un appel à l'API de la CI qui affiche l'avancement des tests, simple, mais efficace. Elle rend le travail et les difficultés visibles à tous.

![dashboard code](/assets/images/posts/migrer-de-commonjs-vers-esm-migration/are-we-esm-yet.png)

### Comment tester hors CI ?

https://1024pix.atlassian.net/wiki/spaces/TC1/pages/3754164240/D+ploiement+de+l+API+en+ESM

On s'est posé la question un peu tard, brainstorming avec les [captains](/organisation/2020/04/14/les-capitaines-de-la-production.html)

Parler du canary
https://github.com/1024pix/pix-dev-tools/tree/main/captain/canary-releases
https://github.com/1024pix/pix/blob/dev/mon-pix/servers.conf.erb#L30

Modification du workflow Slack
![dashboard canary](/assets/images/posts/migrer-de-commonjs-vers-esm-migration/canary.png)

2 semaines de déploiement progressif: front, workers..


## Happy end

Le 1er juin 2023, 3 mois après avoir donné le coup d'envoi, toute la production tourne en ESM
https://1024pix.github.io/areweesmyet/

![dashboard code](/assets/images/posts/migrer-de-commonjs-vers-esm-migration/are-we-esm-yet.png)

## Plus

### Le code
La [pull request principale](https://github.com/1024pix/pix/pull/5787) et ses 132 commits
Zoom sur les codemods

### Workflow canary
Voilà la stratégie de déploiement
![workflow canary](/assets/images/posts/migrer-de-commonjs-vers-esm-migration/workflow-canary.png)

### Coût de coordination et complexité

Un problème qui ne peut être résolu seul demande de la coordination, qui a un coût.

> In tasks that can be partitioned but which require communication among the subtasks, the effort of communication must be added to the amount of work to be done. The added burden of communication is made up of two parts, training and intercommunication. Each worker must be trained in the technology, the goals of the effort, the overall strategy, and the plan of work. This training cannot be partitioned, so this part of the added effort varies linearly with the number of workers. Intercommunication is worse. If each part of the task must be separately coordinated with each other part, the effort increases as n(n-1)/2. Three workers require three times as much pairwise intercommunication as two; four require six times as much as two.
> If, moreover, there need to be conferences among three, four, etc., workers to resolve things jointly, matters get worse yet. The added effort of communicating may fully counteract the division of the original task
in Fred Brooks, The mythical man-month, Chapter "The Man-month", page 18

### Estimation

L'informatique n'est plus si jeune, les développeurs non plus, et pourtant cette constatation reste la même qu'en 1975.

> All programmers are optimists. Perhaps this modern sorcery especially attracts those who believe in happy endings and fairy godmothers. Perhaps the hundreds of nitty frustrations drive away all but those who habitually focus on the end goal. Perhaps it is merely that computers are young, programmers are younger, and the young are always optimists. But however the selection process works, the result is indisputable: 'This time it will surely run,'' or "I just found the last bug."
> So the first false assumption that underlies the scheduling of systems programming is that all will go well, i.e., that each task will take only as long as it "ought" to take.
in Fred Brooks, The mythical man-month, Chapter "Optimism", page 15
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.

0 comments on commit ae4e136

Please sign in to comment.