Guide · L'IA dans le flux de travail du développeur
Refactorisation avec l'IA
La refactorisation modifie la structure du code tout en gardant son comportement observable identique. Un assistant peut renommer, extraire et remodeler en quelques secondes, et c'est précisément cette rapidité qui la rend risquée. Votre contrôle repose sur trois leviers : une suite de tests verte qui verrouille le comportement actuel avant que vous ne touchiez à quoi que ce soit, un plan qui avance par petites étapes, et le diff final que vous lisez ligne par ligne avant de le conserver.
Quand utiliser ceci
- Le code fonctionne mais est difficile à lire, tester ou étendre, et vous pouvez décrire la structure que vous souhaitez à la place.
- Vous avez des tests qui couvrent le comportement, ou vous pouvez les écrire avant de changer une seule ligne.
- Un renommage, une extraction ou un changement de signature doit se propager de manière cohérente à travers de nombreux fichiers et points d'appel.
- L'assistant propose une réécriture importante et bien ordonnée et vous ne pouvez pas dire d'un coup d'œil quel comportement a été modifié.
Idées clés
- Le comportement reste inchangé
- Le but d'une refactorisation est que rien d'observable ne change : mêmes valeurs de retour, mêmes erreurs lancées, mêmes effets secondaires, même interface publique. Vos tests sont la preuve de cela. Ils réussissent avant que vous ne commenciez, et ils réussissent encore après chaque étape. Un test échoué pendant une refactorisation signifie que le changement a cassé quelque chose, pas que vous devez modifier le test.
- Deux chapeaux, jamais les deux
- La restructuration et le changement de comportement sont des tâches distinctes, une distinction que Martin Fowler appelle les deux chapeaux. Portez un chapeau par commit. Soit vous refactorisez avec des tests verts tout au long, soit vous ajoutez une fonction et écrivez de nouveaux tests, jamais les deux en même temps, afin qu'un réviseur puisse voir d'un coup d'œil quel type de changement il lit.
- Verrouillez le comportement avec des tests de caractérisation
- Lorsque le code n'a pas de tests, écrivez d'abord des tests de caractérisation. Un test de caractérisation, un terme de Michael Feathers, enregistre ce que le code fait réellement aujourd'hui, pas ce qu'il devrait faire. Vous exécutez le code, capturez sa sortie actuelle et la fixez. Ce comportement capturé devient le filet de sécurité que chaque mouvement ultérieur doit garder vert.
- Petits mouvements plutôt que réécritures
- Les modèles ne réussissent qu'environ 40 % des tâches de refactorisation complexes dans les benchmarks, et les changements rédigés par l'IA présentent environ 1,7 fois le taux de problèmes et 1,4 fois le taux de défauts critiques du code écrit à la main. Ils gèrent les modifications de fichiers uniques mais échouent sur le raisonnement à l'échelle du dépôt. Une série de petits mouvements vérifiés garde chaque étape dans ce que le modèle et votre révision peuvent réellement vérifier.
- Lisez le diff, pas la description
- Un fichier refactorisé a souvent l'air plus ordonné que l'original, même lorsqu'il est défectueux. Les échecs dangereux sont silencieux : une branche de validation omise, un booléen inversé, un type d'erreur modifié. Lisez la différence par rapport à vos contraintes déclarées et rejetez tout ce qui modifie une valeur de retour, un chemin d'erreur ou un effet secondaire, peu importe à quel point cela semble propre.
Pourquoi c'est important
Le refactoring est le seul type de changement où l'utilisateur n'est censé rien remarquer. Vous améliorez la structure du code, et chaque sortie, erreur et effet secondaire reste exactement comme avant. C'est aussi ce qui rend un refactoring par IA dangereux. L'assistant prédit un code plausible, et un fichier refactorisé qui semble plus propre que l'original est perçu comme un succès même s'il a discrètement modifié le comportement.
Imaginez un développeur demandant à un assistant de nettoyer une fonction validateOrder tentaculaire. La réponse est vraiment plus agréable : plus courte, bien nommée, avec un emboîtement aplati. Le développeur la parcourt rapidement, ne voit aucun problème évident, et fusionne. Ce que le nettoyage a discrètement supprimé, c'est une branche, la garde qui rejetait les commandes avec une quantité négative, car le modèle a fusionné plusieurs conditions en une seule et a perdu un cas limite en cours de route. Il n'y avait pas de test échoué, car personne n'en avait écrit pour les quantités négatives. Des semaines plus tard, un flux de remboursement laisse passer un article de ligne négatif, et l'équipe débogue un bogue financier que le refactoring a introduit et que le diff a caché derrière un formatage plus propre.
La recherche décrit exactement cette situation. Deux études indépendantes en 2024 et 2026 ont révélé que les modèles à la fine pointe de la technologie ne réussissent qu'environ 40 % des tâches de refactoring complexes, et les échecs courants sont les silencieux : supprimer une branche qui contenait la validation des entrées, inverser un booléen pour qu'une condition soit lue à l'envers, mal gérer la liaison this de JavaScript lors de l'extraction d'une fonction. Un sondage SonarSource de 2026 a révélé que 88 % des développeurs rapportent des effets négatifs de l'IA sur la dette technique, et 53 % pointent du code qui semblait correct mais était peu fiable.
Le bénéfice de bien faire les choses est que vous conservez toute la vitesse et éliminez presque tous les risques. L'épine dorsale partagée de tout ce sujet est que l'assistant prédit à partir de son contexte, et votre contrôle provient de trois leviers : le contexte que vous fournissez, le plan que vous acceptez avant qu'il n'écrive, et le diff que vous examinez avant de le conserver. Un refactoring s'appuie fortement sur les trois, avec un ajout spécifique à ce type de changement. Parce que le comportement doit rester fixe, vous obtenez une quatrième vérification que le modèle ne peut pas simuler : une suite de tests qui était verte avant et doit l'être après. Le mécanisme qui transforme cela en un filet de sécurité fiable est ce que la section suivante décompose.
Comment ça fonctionne
Un refactoring sûr est une chaîne de transformations préservant le comportement. Chaque étape change la structure et laisse le comportement observable identique, ce qui signifie qu'un test réussi avant une étape devrait toujours réussir après. Mettez les pièces dans le bon ordre et le modèle peut avancer rapidement sans que vous perdiez le contrôle. Voici les pièces.
- Le filet de sécurité. Une suite de tests verte qui exerce le comportement que vous êtes sur le point de remodeler. C'est ce qui vous indique si une étape a préservé le comportement ou l'a brisé. Pas de filet, pas de refactoring sûr.
- Tests de caractérisation. Lorsque le code n'a pas de tests, vous écrivez des tests qui enregistrent ce qu'il fait réellement aujourd'hui, y compris ses particularités, avant de changer quoi que ce soit. Ils fixent le comportement actuel pour que le refactoring ait quelque chose à respecter.
- La contrainte. Une déclaration explicite de ce qui ne doit pas changer : les signatures, les formes de retour, les types d'erreurs lancées, les effets secondaires, l'interface publique. C'est la règle que le modèle ne doit pas enfreindre.
- Le petit mouvement. Un renommage, une extraction, une variable en ligne à la fois, chacun suivi d'un test complet. Les petits mouvements gardent chaque étape dans ce que votre examen et le modèle peuvent réellement vérifier.
- Le diff. Les lignes exactes qui ont changé, lues par rapport à la contrainte, et non par rapport au résumé en prose que le modèle a écrit sur lui-même.
La distinction qui décide du succès est le deux chapeaux de Martin Fowler. Lorsque vous portez le chapeau de refactoring, chaque changement préserve le comportement et les tests restent verts tout au long; un test rouge signifie que vous avez fait une erreur, pas que le test est faux. Lorsque vous portez le chapeau d'ajout de fonction, vous changez le comportement, donc vous écrivez de nouveaux tests et les tests existants peuvent légitimement changer. Les deux chapeaux ne partagent jamais un commit. Les mélanger est la façon dont un changement de comportement se cache dans le bruit de cent lignes déplacées, où aucun réviseur ne le trouvera.
Le deuxième fait décisif est l'endroit où les modèles échouent. Ils s'en sortent raisonnablement bien sur une édition localisée, à un seul fichier. Ils s'effondrent sur le raisonnement au niveau du dépôt : suivre chaque site d'appel d'une fonction renommée à travers les fichiers, mettre à jour une signature de manière cohérente partout où elle est utilisée, reconfigurer tous les appelants. La plupart des échecs de refactoring par IA sont des transformations composées incomplètes, l'extraction qui a eu lieu mais a laissé trois appelants pointant vers l'ancienne forme. La conséquence pratique est que vous demandez d'abord à l'assistant de cartographier le rayon d'explosion, afin que vous puissiez voir si le mouvement est une édition à un seul fichier qu'il peut gérer ou un changement inter-fichiers où vous devez vérifier chaque site d'appel vous-même. Avec l'ordre en place, la section suivante guide un refactoring de bout en bout.
Un scénario travaillé
Maya, une développeuse, hérite d'un module de paiement avec une fonction parseTotals dans cart.ts. Elle fait deux cents lignes, est profondément imbriquée et n'a pas de tests. Elle veut extraire la logique de validation dans un validateOrder(order) propre pour qu'elle puisse être réutilisée, et elle veut que le comportement reste identique au bit près. Voici comment elle procède.
- Construire d'abord le filet de sécurité. Parce que le code n'est pas testé, elle ne refactorise pas encore. Elle demande à l'assistant d'écrire des tests de caractérisation qui fixent le comportement actuel, y compris les cas délicats : panier vide, quantité négative, champ manquant. Le prompt est explicite, "ne changez pas le code, capturez ce qu'il fait aujourd'hui, et exécutez les tests pour que je puisse les voir réussir." Deux des comportements capturés ressemblent à des bogues, mais elle les garde pour l'instant; le seul travail du refactoring est de préserver le comportement, et corriger les bogues est l'autre chapeau.
- Énoncer la contrainte à l'avance. Elle l'écrit en haut du prompt de refactoring : garder la signature de la fonction, retourner la même forme, lancer le même
RangeErrorsur les totaux incorrects, préserver le comportement de panier vide et de quantité négative que les tests de caractérisation viennent de verrouiller. Ne pas modifier les tests. - Demander le rayon d'explosion. Avant toute modification, elle demande à l'assistant de lister chaque fichier et site d'appel que l'extraction touche. Il nomme
cart.tset trois appelants danscheckout.tsetrefund.ts. Maintenant, elle sait qu'il s'agit d'un mouvement inter-fichiers, pas d'une édition à un seul fichier, donc les sites d'appel doivent être vérifiés. - Un mouvement, puis exécuter. Elle lui fait effectuer uniquement l'extraction, sans autre nettoyage, et produire un seul diff. Elle exécute la suite complète. Dix-neuf des dix-neuf tests de caractérisation restent verts. Un appelant dans
refund.tsfait encore référence à l'ancienne forme en ligne, exactement le mode d'échec de refactoring composé incomplet. Elle demande à l'assistant de corriger cet appelant et exécute à nouveau la suite. - Lire le diff par rapport à la contrainte. Le diff fait quarante lignes. Elle vérifie l'extraction de
validateOrderpar rapport à l'original ligne par ligne : mêmes conditions, même type d'erreur, aucune branche supprimée. La garde de quantité négative est intacte. Elle ne rejette rien. - Commit le refactoring seul. Elle commit l'extraction comme un changement préservant le comportement, avec un message qui le dit. Les deux bogues suspects qu'elle a trouvés plus tôt vont sur un ticket séparé, pour être corrigés sous le chapeau d'ajout de fonction dans leur propre commit.
L'avant et l'après est la leçon. Sans les tests de caractérisation, la garde supprimée de la première section aurait été livrée invisiblement. Avec eux, le refactoring était prouvablement fidèle, l'appelant obsolète a été détecté en quelques minutes, et l'amélioration de la structure a été réalisée proprement. Maya et ce même changement validateOrder se poursuivent dans les pièges ci-dessous.
Pièges et cas limites
Chaque piège ici donne l'impression de progresser tout en transformant discrètement le refactoring en un changement de comportement que vous ne pouvez pas voir.
- Refactoring sans filet. Remodeler du code non testé semble efficace parce que rien ne devient rouge. Rien ne devient rouge parce que rien ne surveille. La solution est d'écrire d'abord des tests de caractérisation, capturant le comportement actuel avant le premier mouvement, pour qu'un comportement modifié ait quelque chose contre quoi échouer.
- Modifier le test pour le faire passer. Lorsqu'un test échoue en milieu de refactoring, le raccourci tentant est d'ajuster le test. Cela convertit votre filet de sécurité en un tampon en caoutchouc. En portant le chapeau de refactoring, un test rouge signifie que le mouvement a cassé quelque chose; annulez le mouvement, ne pas adoucir la vérification.
- Accepter la réécriture qui semble propre. Un grand diff qui semble plus propre que l'original gagne une confiance qu'il n'a pas prouvée. Un formatage plus propre cache des branches supprimées et des conditions inversées. La solution est de garder les mouvements suffisamment petits pour être lus entièrement, et de les examiner par rapport à la contrainte et aux tests plutôt que par rapport à leur apparence propre.
- Mélanger les deux chapeaux. Glisser une petite correction de comportement dans un gros commit structurel semble inoffensif et économise un commit. Cela enterre également la seule ligne qui compte sous une centaine qui ne le font pas. Gardez les chapeaux dans des commits séparés pour que le vrai changement soit visible.
Ensuite, les véritables cas limites. Le renommage inter-fichiers que le modèle laisse à moitié fait. Les changements à l'échelle du dépôt sont là où les modèles échouent le plus, en mettant à jour la définition et en manquant certains appelants. La gestion consiste à refuser de traiter un refactoring inter-fichiers comme une seule étape : demandez d'abord à l'assistant d'énumérer chaque site d'appel, appliquez le changement, puis vérifiez avec une compilation ou un test complet qu'aucun appelant ne fait encore référence à l'ancienne forme, exactement comme Maya a détecté l'appelant obsolète dans refund.ts.
Le comportement qui s'avère être un bogue. Les tests de caractérisation fixent ce que le code fait, y compris ses erreurs. Si votre refactoring "corrigerait" l'une de ces erreurs, c'est un changement de comportement déguisé en refactoring. La particularité de 2026 est qu'un assistant corrigera souvent discrètement un bogue qui semble évident lors de la restructuration, ce qui brise la préservation du comportement et tout appelant qui dépendait de l'ancienne particularité. Gardez le comportement de bogue suspect vert pendant le refactoring, et corrigez-le délibérément par la suite sous le chapeau d'ajout de fonction, avec son propre test et son propre commit. Maintenir cette discipline de manière cohérente lorsque plusieurs personnes refactorisent le même dépôt est là où l'échelle entre en jeu.
Le faire en équipe et à grande échelle
Un développeur peut garder la règle des deux chapeaux en tête. Dès qu'une deuxième personne, un deuxième outil ou un deuxième mois est impliqué, la discipline doit vivre dans des artefacts partagés, sinon l'historique se remplit de commits qui ont discrètement mélangé structure et comportement et personne ne peut faire de bissection.
Le premier artefact durable est la suite de tests elle-même, traitée comme le contrat. Une équipe qui refactorise avec l'IA garde les tests de préservation du comportement sous contrôle de version et les exécute en CI, de sorte qu'un refactoring qui brise le comportement échoue dans le pipeline plutôt que de compter sur un réviseur fatigué pour le repérer. Le refactoring gouverné, validé par des tests et CI, est ce qui sépare un refactoring IA sûr d'une suggestion qui semblait simplement correcte dans un éditeur. Les organisations avec des protocoles de test systématiques pour le code refactorisé rapportent beaucoup moins de problèmes après déploiement.
Le deuxième artefact est la petite demande de tirage. La capacité de révision, pas le volume de code, est le goulot d'étranglement en 2026, et un assistant peut produire un refactoring de mille lignes en quelques secondes qu'aucun humain ne peut examiner en profondeur. La barre largement citée est de traiter 200 lignes comme cible et 400 lignes comme plafond strict, car les révisions de diffs plus grands deviennent superficielles et les PR de plus de 400 lignes stagnent souvent pendant des jours. Les PR de refactoring plus petites et à but unique réduisent le temps de cycle de 30 à 40 % et permettent à un réviseur de vérifier réellement le diff par rapport à la contrainte de comportement. Une responsable, Priya, établit une limite de taille de PR en CI et ajoute deux lignes au modèle de PR : quel assistant a produit le changement, et le prompt ou la tâche qui l'a motivé, pour qu'un réviseur puisse poser la bonne question.
Le troisième est une déclaration partagée de la règle, dans un fichier versionné que les outils lisent, comme CLAUDE.md ou AGENTS.md. Une courte entrée, "les refactorings doivent préserver le comportement, garder les tests verts, ne jamais modifier un test pour le faire passer lors d'un refactoring, lister les sites d'appel avant un changement inter-fichiers," voyage avec le dépôt et atteint l'assistant de chaque contributeur. Les outils soutiennent directement le rythme des petits pas : le mode Plan de Cursor, activé avec Shift+Tab, écrit un plan Markdown révisable dans .cursor/plans que vous éditez avant que l'agent ne touche au code, et le mode plan de Claude Code (aussi Shift+Tab, ou claude --permission-mode plan) lit la base de code sans écrire, donc vous convenez de la séquence des mouvements avant qu'aucun diff n'existe.
Le principe durable à garder, quelle que soit la taille de l'équipe : un refactoring n'est sûr que lorsque le comportement est verrouillé avant de commencer et prouvablement inchangé après avoir terminé, et lorsque chaque mouvement est suffisamment petit pour qu'un humain puisse lire le diff. Commencez par une petite chose. La prochaine fois que vous envisagez un refactoring sur du code non testé, écrivez d'abord les tests de caractérisation et ne refactorisez rien tant qu'ils ne sont pas verts.
Flux de travail
- 01Confirmez que les tests couvrant ce code passent, et écrivez des tests de caractérisation pour tout comportement qu'ils laissent non couvert.
- 02Énoncez la structure cible et la contrainte stricte que le comportement ne doit pas changer, en nommant les signatures, les sorties et les types d'erreurs qui doivent rester identiques.
- 03Demandez à l'assistant de cartographier chaque fichier et site d'appel que le déplacement touche avant qu'il n'édite quoi que ce soit, afin que vous puissiez voir le rayon d'impact.
- 04Laissez-le appliquer un mouvement à la fois, un seul renommage ou une extraction, et exécutez la suite complète de tests après chaque mouvement.
- 05Lisez la différence de bout en bout et rejetez tout ce qui modifie une valeur de retour, un chemin d'erreur ou un effet secondaire.
- 06Validez chaque refactorisation réussie individuellement, séparément de tout changement de comportement ultérieur, afin que l'historique reste bisectable.
- 07Exécutez la suite une fois de plus sur le résultat combiné et confirmez que l'interface publique est identique octet par octet à ce qu'elle était avant de commencer.
Erreurs courantes
- Refactoriser du code qui n'a pas de tests, de sorte qu'un comportement discrètement modifié passe en production sans qu'aucun contrôle échoué ne le détecte.
- Regrouper un changement de structure et un changement de comportement dans un seul commit, ce qui cache le véritable changement dans le bruit du déplacement.
- Accepter une réécriture importante parce qu'elle semble plus propre, alors que l'assistant a omis une branche de cas limite ou inversé une condition que les tests ne couvrent pas.
- Laisser l'assistant renommer à travers les fichiers sans vérifier chaque site d'appel, de sorte qu'un appelant obsolète compile mais échoue à l'exécution.
- Modifier un test pour le faire passer lors d'un refactor, ce qui transforme le filet de sécurité en un tampon en caoutchouc.
Exemples
Notes
- Cette page couvre le changement structurel préservant le comportement : verrouiller le comportement, avancer par petites étapes et lire la différence. Elle ne couvre pas l'ajout de fonctionnalités ou la correction de bogues, qui sont le chapeau d'ajout de fonction et appartiennent à leurs propres commits.
- S'associe à Donner le bon contexte à l'IA, où la contrainte que le comportement ne doit pas changer fait partie du contexte, et à Réviser le code IA en toute sécurité, où vous vérifiez la différence produite par le refactor.