Des micro-refactorings pour s'orienter dans une codebase difficile
Ce guide s’adresse aux développeurs confrontés à une codebase qui semble bonne à jeter et qui ne savent pas par où commencer.
Introduction
Quand une codebase paraît irrécupérable, la tentation est de tout réécrire de zéro. Avant d’en arriver là, mieux vaut effectuer quelques petits refactorings pour s’orienter dans les vrais.
❌ Ne commettez pas l’erreur de lancer un refactoring architectural dans du code que vous n’arrivez même pas encore à lire.
Ces micro-refactorings pourraient aussi être décrits comme un simple « rangement ». Dans ce post, nous verrons la méthode que Kent Beck utilise dans son livre Tidy First? — que nous ne traiterons pas dans son intégralité et que nous recommandons donc absolument !
Guard Clauses
Essayez d’utiliser des gardes plutôt que d’enfermer le code dans mille conditions imbriquées, tout en restant sous les 8 gardes.
⚠️ Si l’on commence à en mettre trop, le code reste difficile à digérer : il vaut alors mieux décomposer cette fonction en plusieurs parties.
Dead Code
Supprimez toujours le code qui n’est plus nécessaire. Inutile même de le garder en commentaire : il est versionné, ou au pire il sera réécrit en mieux au fil des évolutions futures.
Le code inatteignable ne fait que rendre l’ensemble plus cryptique et, à cause de la réflexion, il n’est parfois pas si évident à repérer !
Normalize Symmetries
Choisissez la manière la plus simple d’obtenir un résultat et convertissez tous les algorithmes pour qu’ils utilisent précisément cette manière-là.
Plus on s’impose de standards, plus le code devient lisible sans avoir à y réfléchir.
Reading Order & Cohesion Order
En tenant compte des limitations du langage (parfois une fonction ne peut pas être appelée si elle est définie plus bas, etc.), il est très utile d’organiser les fichiers pour livrer l’information dans l’ordre : imaginez devoir les expliquer à une personne extérieure et facilitez la recherche.
Il est également important de placer tout ce qui est couplé (quand le découplage n’est pas immédiat et trivial) le plus près possible du reste : fonctions dans le même fichier, fichiers dans le même dossier, et ainsi de suite !
Il n’existe pas de standard gravé dans le marbre, mais il existe le bon sens.
Move Declaration and Initialization Together
Les variables doivent être initialisées le plus tôt possible une fois déclarées. Une bonne pratique consiste souvent à les mettre tout en haut, mais les placer à des étapes intermédiaires peut aussi avoir du sens.
L’essentiel est de les mettre là où elles servent, juste avant leur utilisation et non à des endroits aléatoires.
Explaining Variables & Constants
Si une fonction est trop élaborée et pleine d’expressions longues, c’est une excellente occasion d’introduire des variables parlantes, pour simplifier la lecture et aider les autres devs en même temps.
Le même raisonnement s’applique aux magic numbers : s’ils ont un sens précis au sein de la logique, en faire des constantes facilite les refactorings et en clarifie la signification.
Chunk Statements
Si la fonction ou le fichier sont très volumineux, les diviser en sections est naturellement moins confus.
C’est le correctif le plus simple de tous, mais il peut apporter d’énormes satisfactions pour s’orienter, surtout dans les widgets Flutter !
Explicit Parameters
Dans la mesure du possible, mieux vaut écrire des fonctions pures, c’est-à-dire qui ne modifient l’extérieur que par leur sortie. Il vaut également mieux que les données d’entrée soient explicitement déclarées dans les paramètres.
Exemple à ne pas suivre : utiliser les variables d’environnement en les appelant dans le corps au lieu de les demander en paramètres.
Extract Helper
Créez des méthodes, mixins ou fichiers helper pour résoudre les problèmes courants.
En conclusion : avant de refactorer, il faut comprendre, et pour comprendre, il faut ranger. Les micro-refactorings coûtent peu, ne changent pas le comportement du code et vous rendent la carte dont vous avez besoin pour affronter les vrais changements.
