7 techniques pour reprendre le contrôle de ton legacy code

7 techniques pour reprendre le contrôle de ton legacy code

Aujourd’hui je suis fier de recevoir Nicolas pour ce nouvel article invité ! Merci à lui de continuer la danse avec ses techniques pour maîtriser le legacy code ! 😉




nicolas

Salut 👋

Moi c’est Nicolas, Tech Lead le jour à Busbud, organisateur de meetups et de conférences la nuit. Depuis tout petit déjà, je rêvais de travailler avec du code Legacy. Ce rêve est aujourd’hui une réalité !…

Plus sérieusement, je me suis rendu compte que le Legacy, c’est un gros sujet pour les développeurs. Souvent, c’est douloureux. Du coup, ça fait quelques années que je me penche sur la question: comment remettre un projet sur les rails avant la catastrophe ?

Chaque semaine je partage donc ce que j’ai appris, des astuces concrètes pour aider les devs à s’en sortir sur understandlegacycode.com. Grâce à Mehdi, je peux aujourd’hui t’en donner un aperçu ici. Merci Mehdi !




Aaaaah le code “Legacy”. C’est un vaste sujet qui concerne tout développeur et développeuse tôt au tard (plus souvent tôt que tard, d’ailleurs). 

Soyons réalistes : nous passons la plupart de notre temps à modifier du code existant. Généralement, nous ne l’avons même pas écrit. Souvent, il n’y a pas de tests. Parfois les auteurs du code ne sont même plus dans les parages ! Pourtant, nous devons comprendre et modifier ce code sans introduire de bug si possible, merci.

Tu rêverais de pouvoir modifier n’importe quelle partie du code en toute confiance… Mais tu n’as jamais le temps ! Ce changement a été estimé à 2 jours et il y en a plein d’autres à faire avant la fin du Sprint / démo client / livraison / <insère ta deadline ici>. L’enfer !

C’est pas faux.

Mais que dirais-tu si tu avais une botte secrète ? Des techniques pour aborder ce Legacy efficacement en gardant le cap sur ton objectif, sans te laisser distraire par les sirènes de cet océan de dette technique ? Tu pourrais reprendre en main ce projet et le rendre plus facile à maintenir, à chaque itération !

C’est vrai que travailler sur du Legacy c’est pas le fun… mais ça pourrait l’être.

Voici 7 techniques très concrètes qui t’aideront à reprendre le contrôle sur ton Legacy.



1. Le Brain Dump 🧠

Ton cerveau, il n’est pas optimisé pour mémoriser pleins de choses. Tu ne peux jongler qu’avec un nombre limitées de pensées.

Le problème, c’est que ton Legacy est une jungle. Elle regorge de variables mal nommées, de structures non standard, d’indirections inutiles, de mauvaises abstractions… Pour atteindre ton objectif, tu vas passer à travers plein de pièges que tu n’avais pas anticipés. Et quand tu bouges quelque chose, tu en découvres 3 autres qui étaient masqués derrière !

Si tu essaies de jongler avec toutes ces choses dans ta tête, tu vas te perdre.

C’est l’effet ”j’ai presque fini ce ticket” que tu prononces déjà depuis 3 jours au stand-up. Ça se termine souvent avec des Pull Requests trop longues qui contiennent bien plus de changements que prévu.

Pour ne pas se perdre, il faut sortir ces idées de ta tête. Et le plus simple pour ça, c’est une feuille de papier.

Prends une feuille et un crayon. Commence par noter tout ce que tu veux faire sur ce code. Dresse une TODO-list.

Puis choisis une première tâche et vas-y.
Lorsque tu vas avancer sur ta tâche, tu vas avoir d’autres idées. D’autres tâches que tu découvres. Des refactors que tu veux faire. Quand ça arrive, ne les fais pas : note-les !



legacy code


Le fait de les noter sur ta feuille a deux avantages majeurs :

  1. Tu calmes ton esprit. Il sait que l’information est sortie de ta tête et que tu ne l’oublieras pas. Donc tu vas arrêter de ressasser cette idée toutes les 5 minutes et tu peux te concentrer sur ta tâche en cours !
  2. Tu vas éviter l’effet tunnel. Tu vas finir ce que tu as commencé avant de commencer autre chose. Tu pourras rayer ta tâche terminée, faire un commit et prendre une pause ! Tu auras une vision plus claire de ta progression plutôt qu’un vague sentiment de “presque fini”.

Si tu es familier avec la méthode GTD, tout ceci te semblera d’ailleurs très familier.



2. La méthode Mikado 🥢

La méthode Mikado, c’est le même concept que le Brain Dump mais avec plus de structure. C’est idéal quand tu veux atteindre un objectif en particulier et que tu ne connais pas les embûches qui t’attendent.

Là encore, il te suffit d’un papier et d’un crayon.

Commence par noter ton objectif principal, la tâche que tu veux accomplir. Entoure-la. Puis essaye de la réaliser.

Si tu te rends compte qu’il te manque quelque chose pour pouvoir faire cette tâche, tu dois faire 2 choses très importantes :

  1. Annule tes changements en cours (git reset –hard)
  2. Note la tâche que tu dois faire et marque sa dépendance avec ta tâche principale

Puis, recommence en essayant de faire cette sous-tâche à présent. Itère le procédé si tu te rends compte qu’il te manque quelque chose pour atteindre ton but.



mikado


À un moment donné, la sous-tâche sera tellement petite que tu pourras la faire sans problème. Génial ! Commit ça, raye cette tâche et félicite-toi ! 

Puis choisis une autre sous-tâche et continue. Le secret c’est qu’en réalisant les sous-tâches, tu pourras tenter de réaliser la tâche à nouveau et ce sera un jeu d’enfant !

Tout comme le Brain Dump, tu auras moins de stress et une meilleure visibilité sur ton avancée. Tu pourras aussi soumettre des Pull Requests intermédiaires qui rendront progressivement le travail de la tâche principale plus facile.
Si tu veux en savoir plus, je te conseille de jeter un œil au livre officiel sur la méthode.



3. L’over-committing ➿

Quand on travaille sur du code Legacy, il est très facile de se retrouver dans une situation où rien ne marche et on ne sait pas trop comment s’en sortir.

Dans ce genre de contexte, je recommande de prendre une approche plus sécuritaire : avancer à tâtons !

Ce serait tellement pratique d’avoir des checkpoints à chaque petit pas que l’on fait dans la bonne direction. Comme ça, si on fait un ou deux faux pas, on n’a pas à recommencer du début. Il suffit de retourner au dernier checkpoint !

C’est exactement le rôle de notre système de contrôle de version. Marquer des checkpoints.

Mon conseil : quand tu travailles sur du code Legacy, commit très très très souvent. Probablement plus souvent que tu imagines. Je te propose 2 options :

  1. Commit toutes les 5 minutes. C’est facile à faire, il te suffit d’avoir un minuteur. À chaque fois qu’il sonne, fais un commit et relance-le.
  2. Si tu pratiques la méthode Mikado, commit à chaque tâche que tu achèves. La technique est optimisée pour te pousser à faire des petits changements, donc c’est propice aux commits fréquents.


legacy code


C’est pas grave si tes messages de commits sont un peu brouillons ou se répètent. Tu peux (dois) les éditer avant de pousser tes changements sur le repo de l’équipe. Il m’arrive fréquemment de faire des commits que je squash par la suite. Faire trop de commits t’aidera plus qu’en faire trop peu.

Pratique cette technique et tu verras la qualité de tes Pull Requests se bonifier au fil des semaines. Mais surtout, tu auras tes checkpoints !



4. Les ADRs 📝

Parfois, tu vas buter sur un obstacle très gênant pour atteindre ton objectif : le manque de contexte.

Le problème quand tu ne sais pas pourquoi ce code est écrit de cette façon, c’est que tu te retrouves à résoudre un dilemme : laisser le code comme il est et tenter de le contourner ou le modifier et prendre le risque de casser quelque chose. Au mieux, ce genre de dilemme va te prendre beaucoup de temps à résoudre. Remonter la trace des décisions à l’origine de ce code, c’est pas facile.

S’il n’y a pas de baguette magique pour générer la documentation qui n’existe pas dans ton projet, j’ai tout de même une technique qui va te permettre d’arrêter l’hémorragie. Quelque chose de plus pragmatique que “écrit la doc”.

Ce sont les Architecture Decisions Records (ADRs).

Le concept, c’est que tu vas écrire une petite note quand tu prends une décision non triviale. L’intérêt, c’est qu’il n’y a pas besoin de maintenir cette note. Elle est là pour capturer les raisons de ta décision à un moment précis. Ton futur toi te remerciera d’avoir pris 5 minutes pour l’avoir écrite !

Voilà à quoi ressemble un ADR :



adr


La structure est simple :

  1. Le titre qui récapitule la décision que tu documentes
  2. La date 
  3. Le contexte autour de cette décision. Explique pourquoi tu prends cette décision plutôt qu’une autre. Décris tes contraintes, tes connaissances, l’état de l’art actuel, etc.
  4. La décision en soi
  5. Les conséquences de cette décision, bonne et mauvaise. Il y a peut-être des compromis qui viennent avec cette décision, documente-les !

Versionne tes ADRs avec ta base de code. C’est simple, facile à trouver et ça facilite les recherches quand tu veux retrouver une décision en particulier.

Prendre l’habitude d’écrire des ADRs c’est un petit investissement qui paye rapidement. D’après mon expérience, ça facilite le travail de celui qui revoit le code ! 

Enfin, je te conseille d’utiliser le CLI adr-tools. Ça rend la tâche si simple que tu n’auras même plus d’excuse pour ne pas les écrire !



5. Le Approval Testing ✅

Cette technique est une sorte d’arme secrète.

C’est la manière la plus rapide que je connaisse pour poser des tests sur du code existant afin de pouvoir le refactor en toute sécurité.

Tu la connais peut-être sous un autre nom : Characterization Tests, Golden Master ou Snapshot Tests (coucou React). 

Voici les 3 étapes qui la composent :

  1. 📸 Génère un texte que tu peux capturer
  2. ✅ Utilise la couverture de tests pour trouver toutes les combinaisons à tester
  3. 👽 Introduit des mutations pour vérifier la qualité de test tests


📸 Génère un texte que tu peux capturer

La première étape est aussi la plus complexe, mais elle vaut le coup : génère un texte que tu peux capturer. Écris ce texte dans un fichier : c’est ton snapshot. 

Si le code que tu testes retourne une valeur, t’as déjà gagné. Sinon, il faut probablement que tu interceptes les appels fais dans ton code pour enregistrer les paramètres qui sont passés… Une autre approche consiste à introduire des logs dans ton code. Détailler chaque cas de figure pourrait remplir un article dédié, donc je vais te donner un lien pour que tu creuses plus loin cette étape à la fin de cette technique.

Voici un exemple de snapshot avec la librairie Jest, en JavaScript:

it("should update quality", () => {
  expect(updateQuality("foo", 0, 0)).toMatchSnapshot()
})

La première fois que le test se lance, il passe et écrit le résultat de l’appel de fonction dans un fichier. Les fois suivantes, il comparera les résultats avec ce qu’il avait enregistré. Si c’est différent, il plantera. L’idée, c’est de détecter si quelque chose a changé !



✅ Utilise la couverture de tests pour trouver toutes les combinaisons à tester

Une fois que tu as ton premier snapshot, tu as couvert 1 scénario. Il y en a probablement d’autres à trouver si tu veux pouvoir modifier ton code en toute sérénité.

C’est ici que tu la couverture de tests est un outil très utile. La couverture de tests te permet de savoir quel code n’est pas testé !

legacy code

Les lignes surlignées en rouge, ce sont les lignes qui ne sont pas couvertes par un test. Ton but, c’est de ne plus avoir de ligne rouge. Fais varier ce qu’il faut pour tester un maximum de scénario !



👽 Introduit des mutations pour vérifier la qualité de test tests

Une fois que tu as tout couvert avec des tests, il y a une dernière vérification à faire : que tu couvres véritablement le code.

D’ailleurs, c’est la limite de la couverture de tests : elle ne prouve pas que les tests sont de bonne qualité. Tu peux avoir 100% de coverage sans pour autant tester grand-chose. C’est grosso modo pour cela que je ne fixe jamais d’objectif en % de couverture de tests, car c’est un outil utile, mais pas un objectif en soi.

Comment vérifier rapidement que les tests sont de bonnes qualités ? En introduisant des “mutations”. Très concrètement, en introduisant des bugs dans le code source pour voir si un test plante.

Ma manière préférée, c’est de commenter du code. Commente une ligne de code et lance les tests que tu viens d’écrire :

  1. S’ils plantent, tu auras droit à ton moment d’autosatisfaction car tu auras la certitude d’avoir un filet de sécurité si tu introduis un bug ici. 
  2. S’ils passent, il faut que tu trouves la combinaison manquante qui va tester ce cas de figure en particulier.


Pourquoi ça marche ?

Une fois que c’est terminé, tu peux sereinement restructurer ton code. Si tu fais une erreur, tu le sauras immédiatement. Ça va te faire gagner énormément de temps !

Cette technique à un gros avantage : tu n’as pas besoin de comprendre tout ce que fait le code avant de pouvoir commencer à écrire des tests. Tu pars du principe que le code fonctionne d’une certaine façon aujourd’hui et que tu veux préserver ça, peu importe le détail.

Cela m’a permis de poser des tests en quelques heures là où j’aurai dû y passer des jours.

Néanmoins, il y a une mise en garde avec cette technique : tu ne dois pas garder ces tests ! Le problème des snapshot tests, c’est qu’ils vont planter à chaque fois que le comportement du code va changer. C’est très bien quand tu as besoin de refactor le code. Mais ça va générer énormément de faux positifs quand tu vas modifier le comportement du code.

Si tu gardes les snapshot tests, ton équipe va prendre l’habitude que les tests plantent après un changement. Ils vont prendre le réflexe de simplement mettre à jour le snapshot, sans plus vraiment regarder ce qui plante. Si t’en es rendu là, je t’invite à te demander à quoi servent ces tests, à part vous faire perdre du temps ?

Aussi tentant que cela puisse être, les snapshot tests ne sont pas une bonne idée dans la majorité des cas. Le seul cas d’usage véritablement utile des snapshot tests, c’est le Approval Testing. 

Le Approval Testing te permet de refactor du code en un temps record grâce aux snapshot tests, qui eux sont temporaires.

Au fait, je t’avais promis un lien pour creuser cette technique plus en profondeur. Le voici : https://understandlegacycode.com/approval-tests/



6. L’analyse de Hotspots 🎯

Le meilleur moyen pour reprendre le contrôle sur du code Legacy, c’est de l’améliorer progressivement. Ajouter des tests et refactor un peu de code à chaque Pull Request fait du temps, ton allié.

Mais par où commencer ?

Je veux dire, si tu lances une analyse de la qualité de cette base de code, il y a de fortes chances pour que tu aies accumulé ÉNORMÉMENT de dettes techniques. D’après Code Climate, React.js aurait 8 années de dette technique :

hotspot

C’est-à-dire que ça prendrait 8 ans à un développeur de corriger tous les problèmes. C’est absurde. Il faut se focaliser sur ce qui est important. Mais comment faire ?

Généralement, les gens se focalisent sur la gravité des problèmes. Ils vont donc se concentrer sur les problèmes “critiques” en se disant que ce sera déjà un bon début. C’est une erreur.

En fait, la complexité du code n’est pas suffisante pour pouvoir focaliser le refactoring. Pour être efficace, il faut la combiner avec une 2e métrique : la fréquence de changement (aka le churn).

Le raisonnement est assez intuitif : si le code est pourri, mais qu’on y touche jamais, qu’est ce que ça peut faire ? En gros, c’est l’idée. Focalise-toi sur le code qui est complexe et qui est fréquemment modifié. Ce sont les Hotspots.

legacy code

Pleins d’outils te donneront une valeur de complexité pour chaque fichier de ton projet. Souvent, chaque langage dispose de ses propres solutions.

Pour le churn, les informations sont déjà à ta disposition… dans ton système de contrôle de version. Si tu utilises git, cette commande te listera les 50 fichiers les plus modifiés depuis 1 an :

git log --format=format: --name-only --since=12.month \
 | egrep -v '^$' \
 | sort \
 | uniq -c \
 | sort -nr \
 | head -50

Ce genre d’analyse va te permettre de frapper efficacement et d’avoir des résultats rapides.

Grâce à Code Climate, je sais donc par où commencer si je veux vraiment améliorer la base de code de React :

react


7. Les katas 🥋

Enfin, voici une technique qui est plutôt un conseil : il faut pratiquer.

Travailler avec du code Legacy, ça s’apprend. Savoir lire et comprendre du code qui manque de tests et de documentation, c’est un muscle qui se travaille.

Cependant, ta base de code Legacy, ce n’est pas l’idéal pour pratiquer. Le fait est la complexité maximale et les contraintes de temps vont t’obliger à rester dans ta zone de confort pour pouvoir livrer sans trop de retard.

Idéalement, il te faut un espace de jeu où la complexité est suffisante, mais maîtrisée et où tu peux prendre des risques. Il existe plein d’exercices de code pour pratiquer. On appelle ça des katas, car l’idée est de les refaire encore et encore, jusqu’à ce que les mouvements deviennent un réflexe pour toi. Mais la plupart commencent de 0. Tu dois coder le jeu de la vie, ou les règles de jeu du bowling, etc.

C’est pourquoi je suis allé chercher 5 exercices qui sont parfaits pour pratiquer tes compétences de refactoring. Je les ai classés par ordre de complexité croissante :

  1. Le Gilded Rose kata est le meilleur kata pour commencer. Je m’en sers souvent pour illustrer des techniques. D’ailleurs, je m’en suis servi pour te présenter le Approval Testing ! Il n’y a pas de base de données ou d’appel HTTP, juste du code pas très joli à comprendre et modifier. Idéal pour débuter !
  2. Le Tennis Refactoring kata est dans le même esprit. La contrainte est un peu différente : il te reste 1,5h de budget pour améliorer ce code qui a été écrit par un collègue. Que peux-tu faire ? Je l’aime bien, car il va t’obliger à focaliser tes efforts.
  3. Le Trip Service kata introduit la notion de “dépendance gênante”. Il va simuler des appels à une base de données ou un serveur HTTP, ce qui va t’obliger à trouver des astuces pour poser des tests et refactor le code.
  4. Le Trivia kata est le plus complet. Le code est moche, il y a des dépendances gênantes, il n’y a pas de tests… C’est le genre d’exercice complet qu’on pratique dans les Legacy Coderetreat (des événements dédiés à l’apprentissage de ces pratiques). Je ne te conseille pas de commencer par celui-ci.
  5. Le Baby Steps Timer kata est similaire au Trivia kata, mais focalisé sur le front-end. C’est un très bon exercice quand tu travailles sur une Single Page Application et que tu réalises que React / Angular / Vue.js n’a pas résolu tous tes problèmes.

Avec ces 5 terrains de jeu, tu as de quoi pratiquer les différentes techniques présentées ici.

Quand pratiquer ? Et bien, tu peux évidemment prendre sur ton temps libre si tu peux te le permettre et que c’est ton truc. Seul chez toi ou en groupe avec des amis, voire des inconnus. Moi-même, j’étais très investi dans les meetups et les dojos de code (où on pratique les katas, logique). Mais maintenant, j’ai une fille donc d’autres priorités avec lesquelles jongler.

Donc, je privilégie une autre approche : la formation professionnelle. Ces exercices, ils sont là pour te rendre plus efficace, plus professionnel. Ton entreprise doit certainement investir un certain budget dans la formation chaque année. Vois s’il n’y a pas moyen de connecter les deux. Savoir reprendre en main un code Legacy est un investissement plus rentable pour ton évolution que de connaître X ou Y framework. Les entreprises en ont désespérément besoin.



Conclusion

Voilà. Tu connais désormais 7 techniques qui vont te permettre de reprendre le contrôle de ton Legacy. 

Mon dernier conseil, c’est d’en choisir une et de l’essayer dès que tu retournes au boulot !

Travailler sur du Legacy c’est pas le fun… si tu n’as pas les clés pour renverser la vapeur. En maîtrisant certaines techniques, comme celles que je t’ai présentées ici, ta vision du code Legacy change. Ce n’est plus un fardeau imposé, mais un challenge que tu sais résoudre. C’est un investissement sur ton épanouissement personnel, quotidien !

J’espère avoir pu t’aider. Si tu as des questions, n’hésite pas à me contacter sur Twitter (@nicoespeon).

Enfin, si le sujet t’intéresse vraiment, sache que je publie chaque semaine sur mon blog dédié au Legacy Code: https://understandlegacycode.com 

Tu peux même me laisser ton e-mail pour recevoir mes conseils chaque mercredi, directement dans ta boite mail !

Merci à Mehdi de nous avoir connectés,

Prends soin de toi 👋

Qui me parle ?

Nicolas
Moi c’est Nicolas, Tech Lead le jour à Busbud, organisateur de meetups et de conférences la nuit. Chaque semaine je partage donc ce que j’ai appris, des astuces concrètes pour aider les devs à s’en sortir sur understandlegacycode.com.

3 commentaires sur “7 techniques pour reprendre le contrôle de ton legacy code”

  1. Bonjour. En tant que dev’ amateur cet article me fait repenser à la problématique des tests : quelqu’un ici pourrait-il me donner un lien vers un bon article/tutoriel sur la manière (concrète) de créer des tests pour mon code (pour nodejs de préférence). D’avance je vous remercie.

T'en penses quoi ?

Your email address will not be published. Required fields are marked *