Refactoring assisté
Refactorer, c'est changer la structure du code sans changer son comportement. Un agent est une paire de mains idéale pour le travail mécanique et répétitif, à condition de garder les tests comme oracle et de ne jamais mélanger refactoring et changement de comportement.
Ce qu’est un refactoring (et ce qu’il n’est pas)
Refactorer, c’est modifier la structure interne du code sans changer son comportement observable. Les entrées produisent les mêmes sorties, les effets de bord publics restent identiques. Seule la forme évolue : noms plus clairs, méthode extraite, classe déplacée, duplication supprimée.
Point clé : Si le comportement change, ce n’est pas un refactoring. Ajouter une fonctionnalité ou corriger un bug modifie le comportement — ce sont des opérations distinctes, à ne pas mélanger avec le refactoring.
Un agent ne change pas cette définition. Il en accélère l’exécution : ce qui est fastidieux et risqué à la main (propager un renommage dans 40 fichiers) devient rapide et fiable, si le filet de sécurité est en place.
Le filet de sécurité : les tests comme oracle
Le refactoring promet de préserver le comportement. Le seul moyen objectif de le vérifier est une suite de tests verte avant et après. Sans tests, « refactorer » revient à modifier du code à l’aveugle.
Point clé : Les tests sont l’oracle du refactoring : ils définissent le comportement à préserver. Tant qu’ils restent verts, la transformation est sûre.
Attention — corrompre l’oracle. Si un test casse pendant le refactoring et que l’agent modifie le test pour le faire repasser au vert, il déplace la cible et masque une régression. Pendant un refactoring, le code de test ne bouge pas (hors renommage purement mécanique). Un test rouge = c’est le code de prod qu’on corrige.
Mécanique pour l’agent, jugement pour l’humain
L’agent excelle sur le refactoring mécanique et répétitif : renommer un concept partout, extraire une méthode, déplacer une classe, changer une signature dans tous les appelants. C’est précisément ce qui fatigue un humain et génère des erreurs.
Les décisions architecturales relèvent du jugement : découper un monolithe en bounded contexts, arbitrer entre deux designs, prioriser quoi refactorer. L’agent propose, le dev décide. Déléguer ce jugement mène au drift architectural.
Point clé : En hexagonal/DDD, l’agent est excellent pour aligner le code sur l’ubiquitous language (renommages) ou extraire un port. Le choix de où placer la frontière reste une décision de conception.
Cadrer l’agent : trois leviers
Un refactoring assisté sûr repose sur trois consignes explicites données à l’agent :
| Levier | Consigne concrète |
|---|---|
| Contrat invariant | « La signature publique et le comportement de X doivent rester identiques. » |
| Oracle | « Les tests existants doivent rester verts. Ne modifie aucune assertion de test. » |
| Petits pas | « Procède par étapes committées séparément, relisables et annulables. » |
Attention : « Refactore tout et committe à la fin » est un anti-pattern. Un gros commit unique est ingérable en review, impossible à bisecter, et noie un éventuel changement de comportement dans le bruit.
Mélanger refactoring et nouvelle feature dans la même étape est l’autre piège classique : si un test casse, impossible de savoir qui est responsable. Refactoring d’abord (tests verts inchangés), feature ensuite.
Le cas du legacy : tests de caractérisation
Sur du code legacy sans tests, refactorer directement est l’erreur classique. La parade est le test de caractérisation : un test qui capture le comportement actuel tel qu’il est — bizarreries comprises — pour figer la cible avant de toucher la structure.
Point clé : Caractérisation = ce que le code fait. Spécification = ce qu’il devrait faire. Sur du legacy, on fige d’abord l’existant, on corrige ensuite — jamais les deux en même temps.
Une fois ces tests verts, on refactore en exigeant qu’ils restent verts : l’oracle manquant est recréé. Isoler le code derrière un port hexagonal aide à écrire ces tests (meilleure testabilité), mais ne les remplace pas — un port vide ne vérifie aucun comportement.