Tout ce que vous avez toujours voulu savoir sur le refactoring (sans jamais oser le demander)

Tout ce que vous avez toujours voulu savoir sur le refactoring (sans jamais oser le demander)

La définition du refactoring ne souffre aucune ambiguïté : le refactoring consiste à modifier une implémentation sans modifier le comportement associé. Aussi, quand une nouvelle fonctionnalité mène à un refactoring préalable, on gagne à distinguer le temps du refactoring, qui procède à iso-fonctionnalités, du temps de l'implémentation de la fonctionnalité elle-même. Et donc à faire 2 commits, pour plus de clarté.

Nous venons de le voir, le refactoring est souvent "tiré" par la fonctionnalité qui vient juste après. En d'autres termes, la nécessité du refactoring naît de l'écart entre le modèle qui sous-tend la codebase actuelle et celui qui sous-tend la fonctionnalité. Par exemple, une application pourrait associer 1 cours à 1 enseignant et 1 classe. Cela fonctionne très bien jusqu'au jour où l'on souhaite permettre aux élèves de travailler en petits groupes, pour un suivi plus personnalisé par le professeur. À cet instant précis, le modèle devient obsolète et le code inadapté. On pourrait être tenté d'anticiper ces changements, mais mieux vaut éviter.

Autre cause de refactoring : la dette technique. Elle doit être remboursée sous peine de freiner la capacité de la codebase à évoluer à moyen terme. Rembourser une dette technique, c'est justement procéder à des refactorings. La dette peut être contractée de manière involontaire, par méconnaissance des meilleures pratiques de développement, ou bien volontairement pour tenir une échéance. Au-delà, il faut comprendre que la dette est inhérente à la programmation, parce que l'architecture et les conventions de code émergent pour partie, malgré tous nos efforts pour anticiper. Dès qu'on touche le clavier, on crée de la dette et la nécessité du refactoring s'impose.

Mais assez parlé… refactorons 🧰 ⚙️ 🔧 Plus encore que le développement en général, le refactoring demande de la méthode. En voici 3, auxquelles vous pourrez toujours vous accrocher, comme autant de bouées de sauvetage.

Une préoccupation majeure doit être de ne pas créer de régression. Il vous faut donc un filet de sécurité, c'est-à-dire des tests qui détecteront rapidement les effets de bord malheureux de vos refactorings. Le problème, c'est que les tests unitaires, s'il y en a, ne vous seront d'aucune utilité puisque l'implémentation va changer du tout au tout. Vous pourrez vous appuyer sur des tests de plus haut niveau (intégration, end-to-end), mais il faudra en ajouter afin d'explorer à travers eux tous les chemins possibles, chose d'ordinaire dévolue aux tests unitaires.

Bon, mais ne nous voilons pas la face : le plus probable est encore qu'il n'y ait aucun test 🤣 En pareille situation, une approche consiste à créer une piste de logs fonctionnels, désignée sous le terme de Golden Master 1️⃣ parce qu'elle doit rester stable malgré les refactorings successifs. On comprend donc que ces logs ne doivent comporter aucune information relative à l'implémentation.

Vient ensuite une autre difficulté : souvent, un 1er refactoring dépend d'un 2ème, qui dépend lui-même d'un 3ème et ainsi de suite. Si l'on n'y prend pas garde, on est vite prisonnier d'un vortex dont il sera très difficile de s'extraire : la compilation n'est plus qu'un lointain souvenir et les régressions s'accumulent. La Méthode Mikado 2️⃣ pallie ce problème en vous proposant de cartographier au préalable les dépendances entre refactorings, puis de parcourir l'arbre ainsi établi à l'envers.

Forcément, tout ce travail prend du temps, beaucoup de temps. Généralement des semaines ou des mois, dans le pire des cas des années. Travailler en parallèle de la production vous expose à un fort effet tunnel et met votre travail en péril : du code qui n'est pas en production est du code en sursis. Pour y remédier, Martin Fowler a rapporté de ses vacances en Australie le Strangler Fig pattern 3️⃣, qui permet la substitution progressive en production du code legacy par le code refactoré.

D'autres considérations entrent en jeu, qui ne se révèlent qu'au fil des heures de travail. Rien ne remplacera jamais la pratique, alors… happy refactoring !

Subscribe to Mathieu Eveillard

Don’t miss out on the latest issues. Sign up now to get access to the library of members-only issues.
jamie@example.com
Subscribe