Profiter de chaque occasion pour améliorer le code legacy

Vivre avec une grande codebase legacy n’est pas agréable. Les changements sont longs, les bugs se cumulent, la compréhension se perd. Cependant, rien ne nous oblige à subir ces inconvénients éternellement. On peut agir, à tout moment, et dès maintenant. Il n’y a pas besoin de se lancer dans un grand chantier pour cela, ni de prévoir un plan pour aller sur la Lune. On peut faire du refactoring par petites étapes et le faire régulièrement. Profiter de chaque occasion (une évolution, une tâche, une correction) pour améliorer le code qui entoure les modifications. Ce concept, tout simple, permet d’améliorer la qualité du code dans le temps.

Cet été, j’ai eu un bug à corriger sur une partie de l’application que je n’avais pas encore touché. Après une brève balade dans le code, je tombe sur le RoadMapBlock. Le fameux RoadMapBlock. Ça ne vous parle certainement pas, mais en interne, ce nom possède une grande renommée. Ce nom-là, je l’ai entendu lors de mes premiers jours. Son évocation suscitait rires nerveux et désespoir. Il est même connu des non-tech, c’est dire. Mais de quoi bon s’agit-il ?

Le RoadMapBlock est à la fois une brique centrale pour l’un des écrans les plus importants de l’application et l’un des gros points de douleurs du projet. Cette brique a été créée des années auparavant et a depuis été modifiée par des dizaines de développeurs. Pour donner un ordre d’idée, la classe possède une centaine de fonctions. La méthode qui contenait le bug faisait avoisinait le millier de lignes et possédait une grande complexité (une centaine de ifs, plusieurs niveaux d’imbrications, des boucles, …).

Une horreur à première vue, mais également une énorme opportunité d’amélioration.


Faire du refactoring progressivement

J’ai commencé ma session de travail par la localisation de l’erreur dans le code. Je sentais qu’il se passait quelque chose dans une partie de cette fonction, mais la zone était difficilement intelligible. Je me suis donc mis à faire du rapide refactoring pour gagner en compréhension. J’ai effectué plusieurs opérations de refactoring pour améliorer le code, me l’approprier, et y voir plus clair. C’est un moyen rapide de comprendre du code legacy que j’aime bien utiliser (j’en parle plus en détails dans mon précédent article). Peu de temps après, la cause du bug me sautait aux yeux et j’ai pu le corriger facilement. La correction tenait en une seule ligne. Mais était-ce fini ? Non !

J’étais là, au milieu de tout ce code legacy. J’avais pris du temps pour en comprendre une partie, pour l’analyser, pour charger tout ce contexte dans ma tête. J’avais même effectué des modifications ici. Alors autant en profiter pour améliorer le code, pendant que j’étais encore plongé dans ce contexte. Il ne faut pas sous-estimer ce moment. La compréhension du code legacy est souvent difficile et longue. Ce n’est pas non plus quelque chose qui motive, ou qui donne envie, pour la plupart des développeurs. Il faut sauter sur l’occasion pour l’améliorer. Il y a peu de chances qu’on se réveille un matin en se disant « tiens, je vais refaire cette partie pour le plaisir ». Si on ne le fait pas là, maintenant, on ne le fera probablement jamais. Ce code qui nous fait si mal restera une épine dans notre pied.

J’ai donc recommencé mon refactoring proprement. Mon gain de compréhension me permettait de mieux le faire. J’ai renommé des variables, des noms de méthodes. J’ai extrait des méthodes pour commencer à découper et à structurer. J’ai diminué les niveaux d’imbrications des ifs, switch, et for. Des actions simples qui aident énormément pour le futur. Oui, pour le futur. On lit beaucoup plus de code que l’on en écrit. Faire du refactoring maintenant permettra de mieux comprendre ce code toutes les autres fois.

C’est également une fondation pour un refactoring plus large. La succession des petites améliorations facilitent un refactoring plus conséquent. Un jour, il sera aisé de tout reprendre. Le refactoring d’une fonction complexe de mille lignes demande un gros effort. Mais cette même fonction, découpée en plusieurs petites fonctions simples, mieux nommée, mieux structurée, est bien plus facilement modifiable. Peut-être même que ce ne sera plus nécessaire, la structure du code sera peut-être suffisamment bonne pour être comprise et pour évoluer.

L’amélioration du code qui entoure nos modifications peut aller très vite. Je n’ai pas dû prendre plus d’une heure. Une heure sur la vie d’un projet, ce n’est rien. Pourtant, ça a une immense importance. C’est un gros gain. On agit maintenant, on passe à l’action. C’est facile de se plaindre du code legacy, c’est aussi facile de faire des améliorations par petits pas. Cependant, se plaindre ne fera pas avancer les choses.

Savoir s’arrêter

On est enfin lancé dans ce refactoring, on veut bien faire. On peut avoir envie de faire quelque chose de parfait. Ou de tout refaire. Mais l’important, c’est de commencer à améliorer, par petits bouts, et de le faire régulièrement. Il est plus facile d’être régulier en faisant des petits refactoring. Avec le temps, ce deviendra un automatisme. Je fais une modification ici, je vais en profiter pour améliorer là. La qualité globale du projet augmentera progressivement.

L’objectif n’est pas de faire quelque chose de parfait. Ce serait trop long. Dans certains cas, le legacy est tellement grand qu’il faut effectuer de nombreux changements. Malheureusement, certains changements sont longs et complexes. Casser des dépendances. Changer la structure du code. Et puis, qu’est-ce que le code parfait ? On peut toujours améliorer et faire différemment. Le design du code peut faire grincer des dents, mais ce n’est pas grave, c’est mieux qu’avant.

L’objectif n’est pas de tout refaire. Ce serait risqué et également long. Si on veut tout réécrire d’un coup, le travail sera énorme et probablement risqué. On peut faire de grosses erreurs, rater le refactoring. On peut découvrir de nombreux problèmes en cours de route et prendre beaucoup plus de temps que prévu. Pire, on peut abandonner avant même d’avoir terminé. Tout le travail serait alors jeté. L’équipe ou le management pourrait accorder plus difficilement sa confiance pour d’autres sujets. Il est préférable de bien cibler la partie que l’on veut améliorer à cet instant.

Il faut donc savoir s’arrêter à un moment. Se concentrer sur des petites améliorations. C’est déjà mieux qu’avant. Si on y revient plus tard, on pourra à nouveau l’améliorer. Voire améliorer de manière plus macro. J’ai espoir que mon refactoring d’une petite zone du RoadMapBlock servira de première étape à l’amélioration de l’ensemble. La première pierre à l’édifice. Ce travail continuera et inspirera les autres développeurs.


Lancez-vous, maintenant

Toutes les améliorations sont intéressantes. Du simple renaming ou suppression de code mort à l’extraction de méthodes ou restructuration. Les améliorations peuvent être simples et effectuées rapidement. Il n’y a pas d’excuse à rester sans rien faire devant du code legacy. Il n’y a pas besoin de tout refaire, ni d’y passer des journées entières.

Faire de petites améliorations et être régulier. C’est une des clés pour sortir du legacy progressivement. Profitez d’une correction de bug ou d’une évolution pour améliorer le code environnant. Passez à l’action dès maintenant.

Et vous, que faites-vous pour améliorer du code legacy ? Quelles sont vos stratégies ?