# Refactoriser du code legacy avec l’IA sans casser la prod

URL: https://agentvera.dev/fr/blog/refactor-legacy-code-with-ai/ · Publié: 2026-10-25

Refactoriser du code legacy avec des agents IA en sécurité : tests de caractérisation d’abord, petites étapes réversibles, passage à TypeScript, revue et retour arrière.

**En bref:**

- Avant qu’un agent touche à du code legacy, faites-lui figer le comportement actuel avec des tests de caractérisation ; sans ce filet, impossible de distinguer un refactoring d’une réécriture.
- Avancez par petites étapes, chacune dans son commit et avec des tests verts, et gardez les changements de comportement hors des commits de refactoring pour pouvoir annuler chaque étape seule.
- Les migrations comme JavaScript vers TypeScript ou une montée de version de framework se passent mieux module par module, en laissant le compilateur, les tests et un codemod faire le plus de travail possible.
- Dans AgentVera, chaque étape peut tourner dans son propre worktree, être relue et vérifiée à la fin du tour de l’agent, puis arriver sur le dernier main via la file de fusion.

Refactoriser du code legacy avec l’IA, c’est confier à un travailleur très rapide et très sûr de lui la partie de votre base de code que personne ne comprend entièrement. Cela peut bien se passer. Les agents sont patients face aux fichiers de 3 000 lignes, renommer une fonction à deux cents endroits ne les gêne pas, et ils lisent du vieux code sans soupirer. Cela peut aussi mal tourner : un « nettoyage » qui change une règle d’arrondi, supprime un effet de bord que personne n’avait documenté, ou se transforme en réécriture impossible à relire.

Ce guide vise la première issue. Il explique comment poser un filet de sécurité avant le premier changement, comment garder chaque étape petite et réversible, comment mener des migrations comme JavaScript vers TypeScript ou une montée de version de framework, et comment relire et annuler ce que l’agent a fait.

## Pourquoi le code legacy est difficile aussi pour les agents

Le code legacy, c’est du code que l’on a peur de modifier, en général parce qu’il a peu de tests et beaucoup de règles non écrites. Ce qui le rend difficile pour les humains le rend difficile pour un agent :

- **Le comportement se cache dans des endroits bizarres.** Un format de date dans un helper, un retry dans un décorateur, une variable globale lue ailleurs.
- **Certains bugs sont des fonctionnalités.** Un système en aval peut dépendre d’une valeur fausse. La « corriger » casse une intégration que vous n’avez jamais vue.
- **Le code mort a l’air vivant et le code vivant a l’air mort.** La réflexion, le dispatch par chaîne de caractères, les tâches cron et les templates appellent des fonctions qu’aucune recherche ne trouve.
- **La fenêtre de contexte est finie.** Un agent voit les fichiers qu’il lit. Il ne connaît pas le job batch d’un autre dépôt qui importe ce module.

Un agent a aussi une habitude dangereuse ici : il améliore. Demandez-lui d’extraire une fonction et il risque aussi de corriger le cas limite qu’il a remarqué, de renommer des variables et de moderniser la syntaxe. Chaque changement peut être correct. Ensemble, ils donnent un diff où l’on ne sait plus ce qui devait changer.

## Étape 1 : poser d’abord le filet de sécurité

Ne laissez pas l’agent modifier une seule ligne de code de production tant que le comportement qui vous importe n’est pas figé par des tests. Pour du code legacy, cela veut dire des tests de caractérisation : des tests qui enregistrent ce que fait le code maintenant, pas ce qu’il devrait faire.

Un prompt qui fonctionne :

> Ne modifie aucun code sous `src/`. Écris des tests de caractérisation pour `src/orders/pricing.js` qui enregistrent son comportement actuel, y compris ce qui semble faux. Couvre chaque branche que tu trouves, chemins d’erreur compris. Quand un comportement ressemble à un bug, garde le test qui affirme la sortie actuelle et ajoute un commentaire qui commence par `SUSPICIOUS:`. Lance les tests et montre-moi qu’ils passent.

Quelques conseils :

- **Testez par la surface publique.** Des tests qui appellent le module comme le fait le reste de l’application survivent au refactoring. Des tests qui fouillent dans les helpers privés cassent dès qu’on les déplace.
- **Utilisez des entrées réelles.** Des exemples de payloads tirés des logs (nettoyés des données personnelles), des fichiers de fixtures ou une copie d’une base de staging couvrent bien mieux les cas bizarres que des entrées inventées.
- **Les fichiers de référence conviennent ici.** Pour un générateur de rapports ou un export, enregistrer toute la sortie et la comparer est un test de caractérisation rapide et honnête, tant que la sortie est déterministe.
- **Vérifiez que les tests peuvent échouer.** Cassez le code à la main à deux ou trois endroits, ou lancez un outil de tests de mutation sur le module. Si les tests restent verts, le filet a des trous.

Le guide [écrire des tests unitaires avec l’IA](/fr/blog/write-unit-tests-with-ai/) approfondit les tests de caractérisation, la couverture et les tests de mutation.

Les notes `SUSPICIOUS:` ont de la valeur. Ce sont les bugs que vous corrigerez plus tard, volontairement, dans leurs propres commits, une fois que quelqu’un aura décidé que le nouveau comportement est le bon.

## Étape 2 : refactoriser par petites étapes réversibles

Une fois le filet en place, gardez chaque étape assez petite pour être relue en quelques minutes et annulée sans toucher au reste.

### Séparer structure et comportement

La règle la plus utile : un commit de refactoring ne change que la structure, et un changement de comportement a son propre commit. Dites-le clairement à l’agent :

> C’est un refactoring pur. Ne change pas le comportement, ne corrige pas de bugs, ne change pas les signatures publiques. Si tu vois quelque chose qui devrait changer, liste-le à la fin à la place.

Quand les tests de caractérisation changent dans un commit de refactoring, quelque chose ne va pas. Cela vous donne une vérification facile : `git diff --stat main -- tests/` ne doit montrer aucune modification de tests existants.

### Un seul type de changement par étape

De bonnes tailles d’étape :

- Extraire une fonction ou une classe.
- Déplacer un module et mettre à jour ses imports.
- Remplacer une API dépréciée dans toute la base de code.
- Introduire une interface à une frontière pour que l’ancien et le nouveau code puissent cohabiter.

Demandez à l’agent de lancer les tests après chaque étape et de commiter avec un message clair avant de continuer. Un plan aide : « Propose le refactoring sous forme de liste numérotée d’étapes, chacune laissant les tests verts. Attends mon accord avant de commencer. » La plupart des agents de code ont un mode de planification pour cela ; le plan mode de Claude Code, par exemple, explore et propose sans rien modifier.

### Étrangler, pas réécrire

Pour une partie qu’il faut vraiment remplacer, placez la nouvelle implémentation à côté de l’ancienne derrière une interface ou un flag, basculez les appelants un par un, et supprimez l’ancien code quand plus rien ne l’utilise. C’est le pattern du figuier étrangleur (strangler fig). Il transforme une bascule risquée en beaucoup de petites bascules ennuyeuses, et les agents sont doués pour l’ennuyeux.

## Étape 3 : les migrations avec des agents

C’est sur les migrations que les agents font gagner le plus de temps, car le travail est large et répétitif. C’est aussi là que les diffs deviennent énormes. L’astuce : laisser les outils faire la partie mécanique et l’agent trancher les cas qui demandent du jugement.

### JavaScript vers TypeScript

Un chemin qui garde l’application fonctionnelle tout du long :

1. **Ajoutez TypeScript à côté de JavaScript.** Dans `tsconfig.json`, mettez `allowJs: true` pour que les fichiers `.js` et `.ts` cohabitent, et lancez `npx tsc --noEmit` en CI comme vérification de types.
2. **Commencez souple.** Partez avec `strict: false`. En option, activez `checkJs` ou ajoutez `// @ts-check` à certains fichiers JS pour trouver les problèmes avant de les renommer.
3. **Convertissez d’abord les modules feuilles.** Les fichiers sans import interne, comme les utilitaires et les constantes, sont les plus faciles. Remontez ensuite vers les points d’entrée.
4. **Un dossier par étape.** Demandez à l’agent de convertir `src/utils/` en `.ts`, d’ajouter les types, de garder les tests verts et de faire passer `tsc --noEmit`. Puis le dossier suivant.
5. **Durcissez progressivement.** Une fois tout en `.ts`, activez `noImplicitAny`, puis `strictNullChecks`, puis `strict` complet, en corrigeant les erreurs entre chaque.

Deux règles à donner à l’agent : pas de `any` sans commentaire qui explique pourquoi, et pas de `@ts-ignore` pour faire disparaître les erreurs. Sinon, le chemin le plus court vers un compilateur vert consiste à l’éteindre ligne par ligne.

### Montées de version de frameworks et de bibliothèques

Pour une version majeure, l’ordre compte :

1. **Lisez d’abord le guide de migration.** Faites résumer par l’agent le guide de mise à jour officiel et lister les changements cassants qui concernent votre code, avec les chemins de fichiers. C’est une étape en lecture seule.
2. **Lancez le codemod officiel s’il existe.** Beaucoup de projets en fournissent, par exemple `npx @next/codemod` pour Next.js ; côté Java, les recettes OpenRewrite couvrent de nombreuses montées de version. Un codemod est déterministe, un agent ne l’est pas. Laissez le codemod faire ce qu’il peut.
3. **Laissez l’agent gérer le reste.** Les cas que le codemod n’a pas su traiter, les wrappers maison, les tests qui reposaient sur l’ancien comportement.
4. **Une version majeure à la fois.** Passer de 3 à 6 d’un seul coup empile tous les changements cassants dans un seul diff.

Fixez le résultat attendu dans votre prompt : « le build passe, la suite de tests passe, aucun nouvel avertissement dans la console ». Un vague « mets à jour vers la dernière version » invite l’agent à monter cinq autres paquets au passage.

## Étape 4 : isoler le travail avec des worktrees

Un long refactoring ne devrait pas traîner dans votre dossier de travail principal, et des étapes parallèles ne devraient pas en partager un. Un [git worktree](/fr/glossary/git-worktree/) donne à chaque étape sa propre branche et son propre dossier :

```bash
git worktree add ../app-ts-utils -b refactor/ts-utils
git worktree add ../app-ts-api -b refactor/ts-api
```

Un agent convertit alors `utils`, un autre `api`, et vous continuez à travailler dans le dossier principal. Quand une étape est terminée et relue, fusionnez-la ; quand elle ne mène nulle part, supprimez le worktree et la branche. Plus de détails dans [git worktrees pour agents parallèles](/fr/blog/git-worktree-parallel-agents/).

Attention aux étapes parallèles qui touchent les mêmes fichiers. Deux agents qui renomment des choses dans le même module produiront des conflits, et c’est dans la résolution de conflits d’un refactoring que le comportement se glisse. Découpez le travail par dossier ou par module, pas par type de changement.

## Étape 5 : relire chaque étape

Un diff de refactoring s’approuve facilement parce qu’il a l’air de ne rien faire. C’est justement pour cela qu’il faut le lire. À surveiller :

- **Des tests ont-ils changé ?** Dans un refactoring pur, les tests existants ne devraient pas bouger.
- **Des signatures publiques ont-elles changé ?** Fonctions exportées, réponses d’API, colonnes de base de données, noms d’événements.
- **Quelque chose a-t-il été supprimé ?** Demandez à l’agent pourquoi chaque fonction retirée était inutilisée. « Aucune référence trouvée » n’est pas une preuve quand il y a de la réflexion ou du dispatch par chaîne.
- **La gestion des erreurs a-t-elle changé ?** Une exception avalée qui se propage désormais, ou l’inverse, est un changement de comportement.
- **Le diff dépasse-t-il l’étape ?** Une étape « déplacer ce module » ne devrait pas aussi reformater vingt autres fichiers. Demandez le formatage dans son propre commit, ou pas du tout.

Un second modèle qui relit chaque tour en attrape une bonne partie. Voir [revue de code par IA](/fr/blog/ai-code-review/) pour le fonctionnement.

## Étape 6 : prévoir le retour arrière avant d’en avoir besoin

Revenir en arrière ne coûte pas cher quand on s’y prépare :

- **De petits commits.** `git revert <sha>` retire proprement une étape. Un commit de 4 000 lignes ne peut être annulé qu’en bloc.
- **Revert plutôt que réécrire.** Une fois sur main, faites un revert du commit ou du merge au lieu d’un force-push sur un historique partagé.
- **Bisect quand quelque chose passe entre les mailles.** Avec de petits commits verts, `git bisect` trouve en quelques essais l’étape qui a cassé le comportement.
- **Des flags pour les bascules risquées.** Quand ancien et nouveau code cohabitent, un flag désactive le nouveau chemin sans déploiement.
- **Annuler au sein d’une session.** Avant tout commit, vous pouvez annuler le dernier tour d’un agent ; voir [comment annuler les changements de Claude Code](/fr/blog/undo-claude-code-changes/).

## Erreurs courantes

- **« Refactorise ce module » sans aucun test en place.** Vous obtenez une réécriture et aucun moyen de la vérifier.
- **Mélanger refactoring et corrections de bugs.** Quand le comportement change, impossible de savoir si c’était voulu.
- **Une seule branche de migration géante.** Elle s’éloigne de main, les conflits s’accumulent et personne ne peut la relire.
- **Faire confiance à « inutilisé ».** La recherche ne voit ni les appels dynamiques, ni les autres dépôts, ni les tâches planifiées.
- **Laisser l’agent faire taire le compilateur.** `any`, `@ts-ignore` et les règles de lint désactivées cachent le travail au lieu de le faire.
- **Fusionner des étapes parallèles sans les tester ensemble.** Deux branches vertes peuvent devenir rouges une fois fusionnées, et c’est à cela que sert une [file de fusion](/fr/blog/merge-queue-for-ai-agents/).

## Le faire dans AgentVera

AgentVera fait tourner des CLI d’agents de code côte à côte par projet, avec git intégré, ce qui colle bien au style pas à pas d’un refactoring de code legacy.

- **Un worktree par étape.** Depuis le panneau des worktrees, ouvrez une branche et un dossier pour chaque étape et lancez un agent directement dedans, Claude Code sur l’un, Codex ou Gemini CLI sur un autre. Votre dossier principal reste tel quel.
- **Des checkpoints à chaque tour.** Au début de chaque tour, le dossier de travail est enregistré dans une ref git cachée, et les 60 derniers tours sont conservés par agent. Voyez quels fichiers un tour a modifiés et annulez uniquement ce tour si l’agent est allé trop loin.
- **Une revue à la fin de chaque tour.** La revue de code automatique lit le code écrit par l’agent avec le modèle Claude de votre choix et liste ses constats avec une sévérité et un lien fichier:ligne ; en option, les constats retournent à l’agent, jusqu’à deux tours d’affilée.
- **Verify selon vos critères.** Écrivez « refactoring pur, tous les tests passent, aucun fichier de test existant modifié » dans votre message. Verify en tire des critères et, à la fin du tour, un vérificateur distinct qui ne peut pas modifier de fichiers lance les tests et marque chaque critère avec une preuve.
- **La file de fusion pour les étapes parallèles.** Les branches sont fusionnées une à une sur la dernière version de la cible, et la commande de vérification tourne sur le résultat fusionné. Par défaut, une branche verte attend votre approbation.
- **Parallel team pour les grosses migrations.** Pour une migration qui se découpe en parties indépendantes, une équipe parallèle fait tourner chaque partie dans son propre worktree, fusionne les parties terminées dans une branche d’intégration et lance la vérification finale : vous relisez une seule pull request.
- **Git sans quitter l’application.** Le gestionnaire de commits, les diffs et l’historique en graphe sont dans le panneau de droite, donc relire chaque étape et en annuler une va vite.

## Pour conclure

L’IA ne rend pas le code legacy sûr à modifier ; ce sont les tests et les petites étapes qui le font. Ce que l’IA change, c’est le coût de ces étapes. Écrire des tests de caractérisation, convertir un dossier en TypeScript, lancer un codemod et nettoyer derrière : c’était le travail pour lequel personne n’avait le temps. Avec des agents, il coûte peu, vous pouvez donc vous permettre de le faire correctement : le filet d’abord, un changement à la fois, chaque étape relue, chaque étape réversible.

Pour aller plus loin :

- [Git et GitHub](/fr/features/git-and-github/)
- [Checkpoints et replay](/fr/features/checkpoints-and-replay/)
- [Revue de code](/fr/features/code-review/)
- [Verify](/fr/features/verify/)
- [File de fusion](/fr/features/merge-queue/)
- [Parallel team](/fr/features/parallel-team/)

Pour essayer AgentVera, commencez par la [page d’accueil](/fr/).

## Questions fréquentes

**L’IA peut-elle refactoriser du code legacy en toute sécurité ?** Oui, si vous lui donnez un filet de sécurité et de petites étapes. Faites d’abord écrire des tests de caractérisation à l’agent, puis un seul changement structurel à la fois, avec les tests lancés et un commit après chaque étape. Les grandes demandes du type « nettoie ce module » sont celles où les agents changent le comportement sans le dire.

**Que sont les tests de caractérisation ?** Des tests qui enregistrent ce que fait le code aujourd’hui, y compris les comportements étranges ou bogués, plutôt que ce qu’il devrait faire. Ils permettent de changer la structure et de voir immédiatement si le comportement a bougé.

**Faut-il laisser un agent migrer toute une base de code vers TypeScript d’un coup ?** Non. Activez allowJs, convertissez un module ou un dossier à la fois, gardez le build et les tests verts entre les étapes, et durcissez les options du compilateur progressivement. Un seul changement géant est très difficile à relire.

**Comment revenir en arrière sur un refactoring IA qui a cassé quelque chose ?** Si chaque étape a son propre commit, git revert retire uniquement cette étape. Avant la fusion, les checkpoints d’AgentVera peuvent aussi annuler un seul tour d’agent. Après la fusion, faites un revert du commit ou du merge sur main plutôt que de réécrire l’historique.

**Quel agent est le meilleur pour refactoriser ?** Claude Code, Codex et Gemini CLI savent tous le faire. Le processus compte plus que le modèle : les tests d’abord, de petites étapes, chaque diff relu. Dans AgentVera, vous pouvez les faire tourner côte à côte sur des étapes distinctes.

---

**À propos d’AgentVera.** AgentVera est une app de bureau pour macOS, Windows et Linux, développée par Solviera Teknoloji. Elle exécute 18 agents de code IA (Claude Code, Codex, Gemini CLI, Copilot, Cursor, Antigravity, opencode, Hermes, Qwen Code, Kimi Code, Kiro, Amp, Droid, Goose, Vibe, Crush, Aider, Cline) côte à côte, par projet, dans de vrais terminaux avec les installations et connexions CLI de l’utilisateur. L’offre gratuite inclut des agents illimités. Télécharger: https://agentvera.dev/fr/download/ · Tarifs: https://agentvera.dev/fr/pricing/
