Reprendre un projet délaissé, comment on s’y prend ?
Reprendre un vieux projet, ce n’est pas foncer dans le code : c’est d’abord comprendre pourquoi on y va, ce qu’il fait vraiment, et comment agir sans tout casser.
Introduction
Il arrive, dans un cadre perso ou pro, que l’on doive travailler sur un vieux projet toujours en fonctionnement mais qui n’est plus vraiment maintenu pour diverses raisons : manque de temps, manque de besoin, manque d’envie, etc.
Ainsi, sans historique ni connaissance, il n’est pas toujours facile de savoir par où attaquer. Ce guide, s’il en est un, permet d’évoquer les grandes étapes clés à mettre en place.
Afin d’illustrer au mieux, je vais prendre un exemple concret : notre serveur principal est consommateur d’un service de catégorisation de transaction. Malheureusement, ce service renvoyait de temps en temps des erreurs empêchant 10% des transactions d’être catégorisées. Ce service faisait à la fois appel à une API d’un autre projet interne mais contenait aussi une logique métier assez lourde non testée empêchant de comprendre précisément d’où vient le bug.
Le balisage
Le but
Première étape primordiale, qui est souvent mise de côté : “Définir un but”. Pour cela, on peut répondre aux questions : Qu’est-ce qu’on fait là exactement ? Réparer un bug ? Ingérer de la connaissance ? Migration ? Maintenance ? Ajouter une feature ?
Bref, les “pourquoi on est là” peuvent être nombreux, et cela aura un impact très différent sur les étapes à mettre en place par la suite.
Le but était clair dès le début : comprendre pourquoi le service de catégorisation renvoyait des erreurs, avec potentiellement un refactoring si besoin.
Le temps
On n'a jamais un temps infini et le but est souvent lié au temps. Si on est là pour un bug, c’est réaliste d’y passer quelques jours, mais peut-être pas 1 mois.
Par exemple, si on est là pour acquérir de la connaissance et faire évoluer le module, 3 à 4 jours de tests et d’analyse afin de comprendre le module semblent acceptables.
Le code appelant était assez vieux, écrit en JS et trop complexe pour ce qu’il faisait. Au vu de notre but, nous nous étions donné environ 1 semaine de compréhension et refacto JS vers TS, et 1 semaine d’amélioration pour corriger le bug. C’était une estimation assez haute, ne connaissant pas du tout le projet, ni ce qu’on allait y découvrir.
Chercher, demander, monitorer et plus
Ici, il n’y a pas d’ordre précis sur les étapes. Souvent, on fait toutes les étapes en même temps sans vraiment s’en rendre compte.
Chercher
On met les mains dedans, on essaie de comprendre les différents fichiers, les points d’entrée, les appels API entrants/sortants, on dépile la montagne de code progressivement.
On jette un coup d’œil par-ci par-là. Le but est de prendre un bout et d'essayer de tirer la pelote de code jusqu'à la base de données, en passant par les différentes couches de service.
S’il y a un ReadMe à la racine, on le lit. Il n’est pas toujours à jour, donc on prend ses infos avec des pincettes.
Dès qu’on voit une ligne ou un algo qu’on ne comprend pas, il ne faut pas hésiter à aller chercher plus d’infos et cela par plusieurs moyens :
- le message de commit (avec un peu de chances, on aura une petite ligne explicative)
- En relisant la PR/MR liée s’il y en a une (avec un peu plus de chances, elle existera avec une belle description !)
- En essayant de retrouver le ticket Jira (ou autre) lié à ce commit ou cette PR/MR (uniquement si on a beaucoup de chances, ça n’arrive pas toujours …)
Pas de ReadMe disponible pour ce service, juste le code à lire, comprendre et exécuter. Les messages de commits datant d’il y a 6 ans sont très simplistes et encore plus les descriptions de PR, donc impossible de se baser dessus.
Demander
On récolte le plus d’infos venant d’une personne ayant travaillé de près ou de loin sur le sujet, elle pourra facilement nous aider que ça soit durant une conversation rapide ou plus longue. Toutes les infos ne seront peut-être pas utiles, ou des données seront peut-être dépassées, mais souvent c’est par ce biais qu’on apprend le plus de choses.
Par exemple, savoir que le projet a été fait par un seul développeur pendant 6 mois ne sera pas la même chose que s’il a été fait par une équipe de 4 avec code review.
Nous avons échangé avec les développeurs ayant créé ce service il y a quelques années, ce qui nous a permis de récupérer des infos sur l’utilisation et son fonctionnement. Nous avons aussi appris que le code n’a pas vraiment évolué depuis sa création, et donc correspond aux standards d’il y a quelques années.
Monitorer
Pour s’assurer de l’impact réel de ce que l’on va faire (négatif ou positif) et donc savoir si on est en train d’insérer un bug, ou si on en répare un autre.
On met des logs en entrée et sortie du service, que ça soit pour comprendre l’utilisation du service ou connaître la volumétrie.
C’est toujours intéressant d’avoir la volumétrie d’utilisation d’une route ou d’un service, cela permet de s’assurer que tout reste fonctionnel durant nos changements par la suite.
Jusqu'à ce moment-là, nous étions absolument aveugles car nous n'avions aucune métrique sur le fonctionnement du service. Nous avons donc rajouté des logs à l'entrée et à la sortie du service, ainsi qu'avant et après l'appel à l'API interne. Le but est d'analyser la donnée en entrée et celle en sortie et de s’assurer que durant le refactoring prévu par la suite, tout reste fonctionnel.
Prendre des notes
Et oui, les paroles idées s’envolent, mais les écrits restent. Il est primordial de prendre des
notes quand on explore quelque chose, que ça soit sur un cahier, sur Notion ou dans un fichier
markdown. Le but est de garder une trace de ce qu’on a fait/vu/exploré, mais aussi de mettre au
clair toutes nos pistes d’exploration ; de schématiser l’architecture du projet ou encore de mettre
à plat le but du service.
Ces notes permettent juste de s’y retrouver et de mettre à plat nos recherches et nos idées. Le but est juste d’avoir un cahier de brouillon privé.
Mettre du propre
À partir de là, on devrait avoir engrangé pas mal de connaissances pour mettre au propre et en faire profiter tout le monde.
Il peut être très intéressant de compléter le ReadMe du projet avec les notes prises en amont. Permettant ainsi de rajouter de l’information fraiche grâce à nos découvertes, voire de rajouter des diagrammes d’architectures, etc. Le but est cette fois de mettre au propre toutes ses informations et de les partager publiquement avec le reste de l’équipe.
Une autre façon de mettre au propre est de pouvoir en sortir des tâches à faire : si on était là pour améliorer une feature, on se dit qu’un refacto avant sera nécessaire par exemple et mettre ça dans un Jira permet d’y voir plus clair par exemple.
Grâce aux notes prises tout au long de notre exploration du projet, nous avons pu créer un Notion permettant d’expliquer le cycle de vie du service que nous avons partagé au sein de l’équipe. Nous ne voulions pas mettre un ReadMe au milieu du code que personne ne lira réellement.
Pour le moment, on a surtout balisé la zone, en analysant le code, mais aussi en comprenant comment il est appelé, par qui, combien de fois, etc.
Le temps passé pour chaque étape est complexe à déterminer : selon la complexité du code et de l’architecture, mais aussi nos connaissances sur le métier ou sur le langage. On peut aussi bien passer 1 journée à rajouter du monitoring qu’une heure. Toute situation est différente, donc chacun doit définir le temps à investir selon le bénéfice escompté.
L’action
Maintenant qu’on a balisé, on peut commencer à faire des changements. Cependant, il n’est pas rare que des changements aient déjà été faits en amont sans qu’on s’en rende vraiment compte.
Dans l’étape “Chercher”, des petits tests unitaires du type “boîte noire” ont sûrement été ajoutés.
Durant l’étape “Monitorer”, des logs ont certainement été ajoutés.
On attend et on analyse
Maintenant qu’on a du monitoring en place, on va … monitorer ! On sort nos plus beaux dashboards Datadog ou autre, et on attend que les logs remontent.
Encore une fois, ça peut aller très vite comme être très lent. Selon la fréquence d’appel du service.
Le service de catégorisation de transactions est appelé uniquement le matin entre 4h et 9h, car les banques mettent à jour les transactions vers ces heures-là. Le reste du temps, le service n’est pas appelé, donc on doit attendre le lendemain matin pour avoir des infos exploitables.
En attendant, notre connaissance sur le sujet a commencé à évoluer. Et on fait le lien avec ce qu’on a pu lire dans un vieux ReadMe incompréhensible ou encore le collègue qu’on a interviewé et qui nous a baragouiné un truc sans qu’on le comprenne. En fait, tout commence à s’éclairer et on se dit “ok je ne comprends pas tout, mais je sais ce que ça fait à peu près.”
Migration ? Bug ? Maintenance ? Pourquoi on est là ?
Très bizarrement, une fois à cette étape, on a une forte envie de tout brûler et de tout recommencer.
Même si cela peut sembler légitime, il faut prendre un pas de recul et se poser la question : “Pourquoi on est là ?”. Exemple : Est-ce que tout passer en ESM au lieu de CommonJS a un réel impact fort ? Si mon but est de réparer un bug obscur, je ne pense pas. Si mon but est d’améliorer ce service et de le maintenir réellement, passer 2 jours sur cette tâche peut être une bonne idée.
On peut enfin faire ce pourquoi on est là : refactoring et correction du bug. Pour la petite histoire, nous avons réussi à améliorer le code métier complexe récursif qui catégorisait plusieurs fois de suite les mêmes transactions, atteignant le rate limit de l’API de temps en temps.
À garder en tête tout du long
- Il est normal de ne pas tout comprendre immédiatement, ça peut demander du temps et peut être décourageant. Mais il faut continuer de progresser, demander de l’aide, réfléchir, se tromper.
- Un bon moyen de comprendre est de changer le code et de voir ce qu’il se passe. Passer une heure à
écrire une méthode pour la supprimer à la fin avec
git resetpeut être rageant, mais l’heure passée est en fait plus bénéfique qu’une seule méthode écrite. Cela a permis d’engranger de la connaissance, d’explorer une piste inutile, de comprendre un langage ou un pattern. Bref, le nombre de lignes de code final a très peu d’importance. - Le temps est crucial, tout peut se faire en moins d’une demi-journée comme en 2 semaines ; ainsi il est important de souvent se poser la question : “Est-ce que cela a une réelle valeur ajoutée pour la suite ?”.
Conclusion
Il n’est pas aisé d’arriver sur ce genre de projet. Cela peut être fastidieux mais très gratifiant quand on commence à maîtriser le scope.
Ces étapes ne sont pas toujours utilisables dans toutes les situations, ce sont plus des idées à creuser si besoin. Il est possible que le code soit totalement clair et testé, donc pas besoin de perdre du temps à interviewer un collègue par exemple.
Il n’est pas rare qu’une piste en engendre une autre et que toutes ses étapes se mélangent petit à petit :
- Une interview nous emmène sur un bout de code incompréhensible qui est le cœur du projet,
- On écrit des tests pour mieux comprendre tout en prenant des notes à côté,
- Finalement, on rajoute un log en prod pour comprendre l’entrée et la sortie de cette méthode,
- Le temps que les logs apparaissent, on se concentre sur un appel API qui semble étrange,
Tout cela nous aura pris peut-être 2 heures et on aura exécuté plein d’étapes en même temps sans s’en rendre compte.
Aparté IA
À l’heure de l’IA, on pourrait se dire “on le passe à Claude et on pose des questions dessus”. Cela peut être une solution, mais ce n’est pas toujours suffisant. Selon les personnes, il est préférable de creuser un problème pour mieux le comprendre et se l’accaparer que d’avoir l’explication directement. Mettre au propre un ReadMe à la main selon ses connaissances permet aussi de faire le vide dans sa tête et éventuellement de se poser plus de questions entraînant de nouvelles recherches ; le but étant d’éliminer toutes les zones d’ombre et d'incompréhension. Alors que lire un ReadMe qui vient d’être généré peut contenir des zones d’ombre que personne ne verra directement et ne remettra en question.
Aussi, l’IA n’a pas plus de contexte que nous. Elle saura répondre au comment (le code) mais pas au pourquoi (le métier) s’il n’est pas documenté.