Le geste de base du métier enfin nommé : ~60 transformations sûres, à petits pas, tests à chaque pas.
Pourquoi ce livre
La première édition (1999) a donné un nom au geste le plus quotidien du métier. Avant, « améliorer le code » était une intention vague ; après, il existait une soixantaine de gestes nommés, chacun avec sa mécanique sûre, pas à pas. Si votre éditeur a un menu Refactor, c'est à cause de ce livre.
Cette deuxième édition (2018) réécrit tout en JavaScript et change l'exemple fil rouge : le magasin de location de vidéos de 1999 devient le programme de facturation d'une troupe de théâtre, parce que, dit Fowler, il faudrait aujourd'hui commencer par expliquer ce qu'était un vidéo-club.
Les idées qui restent
Quatre chapitres de leçons, puis un catalogue d'une soixantaine de refactorings. Voilà ce qui reste vraiment.
1Refactorer a une définition stricte
Le mot sert à tout ; le livre est précis. La définition : « un changement de la structure interne du logiciel pour le rendre plus facile à comprendre et moins cher à modifier, sans changer son comportement observable » (ch. 2). Comportement inchangé : c'est tout le contrat. Le diagnostic instantané : « si quelqu'un dit que son code a été cassé deux jours pendant qu'il refactorait, vous pouvez être à peu près sûr qu'il ne refactorait pas ».
La discipline vient avec la métaphore des deux chapeaux de Kent Beck : on ajoute une fonctionnalité OU on refactore, jamais les deux à la fois. On change de chapeau souvent, parfois toutes les quelques minutes, mais toujours en le sachant. Les mélanger, c'est comme ça qu'un « petit nettoyage » devient un marécage d'une semaine.
« Sans changer le comportement observable » est le mot-clé. Refactorer ne touche jamais à ce que le code rend, seulement à sa forme :
// avant : ça marche, mais c'est illisible
function p(d) { return d.q * d.u * (d.q > 10 ? 0.9 : 1) }
// après : EXACTEMENT le même résultat, structure clarifiée
function prixTotal(commande) {
const remise = commande.quantite > 10 ? 0.9 : 1
return commande.quantite * commande.prixUnitaire * remise
}
Les deux fonctions renvoient le même nombre pour les mêmes entrées. C'est ça, le contrat : un test qui passait avant passe encore après. Si quelque chose dans le résultat change, ce n'est plus un refactoring, c'est une modification.
🎨 Illustration à générer : copier ce prompt dans ChatGPT :
Flat illustration, warm ivory background (#faf7f2), muted green and terracotta palette, no text, minimalist editorial style, a developer at a desk mid-swap between two hats, one muted green and one terracotta, one hat on the head and the other held in hand, a code editor glowing softly in front, deadpan humor, 3:2 aspect ratio
Légende prévue : « Ajouter une fonctionnalité, ou refactorer. Un chapeau à la fois. »
2Tout est dans le rythme : des pas minuscules, jamais cassé
Le chapitre 1 est une démonstration en direct de soixante-dix pages. En partant d'une seule fonction statement() de 44 lignes qui facture une troupe de théâtre, Fowler enchaîne dix refactorings nommés, et après chaque geste : compiler, tester, committer. Pas une seule fois le code ne cesse de fonctionner.
Il désigne lui-même ce rythme comme la leçon la plus importante du livre : « la clé du refactoring efficace, c'est de reconnaître qu'on va plus vite en faisant des pas minuscules, le code n'est jamais cassé, et on peut composer ces petits pas en changements substantiels » (ch. 1). Il l'a appris de Kent Beck « dans une chambre d'hôtel à Détroit, il y a deux décennies ». Et il avoue : « je ne fais pas toujours des pas aussi courts, mais dès que les choses deviennent difficiles, mon premier réflexe est de raccourcir les pas ».
3C'est purement économique, pas moral
Fowler tue l'argument de la bonne conscience : « l'objectif du refactoring n'est pas de montrer comme la base de code est étincelante : il est purement économique » (ch. 2). On refactore pour livrer plus vite. Son argument central, la Design Stamina Hypothesis, dit qu'un bon design interne soutient la vitesse de l'équipe dans la durée, et il a l'honnêteté de l'étiqueter : « je ne peux pas le prouver, c'est pourquoi j'en parle comme d'une hypothèse ».
La forme la plus rentable est le refactoring préparatoire : « le meilleur moment pour refactorer, c'est juste avant d'ajouter une nouvelle fonctionnalité ». Kent Beck l'a compressé dans un tweet que le livre cite : « pour chaque changement souhaité, rendez d'abord le changement facile (attention : ça peut être difficile), puis faites le changement facile ». L'image de Jessica Kerr : faire 30 km au nord pour rejoindre l'autoroute, puis filer 150 km à l'est trois fois plus vite.
Concrètement : on vous demande d'ajouter le transporteur « express ». Le code actuel rend ce changement pénible.
// le code tel quel : ajouter un cas = rallonger le if/else, fragile
function frais(transporteur) {
if (transporteur === 'standard') return 4.99
if (transporteur === 'retrait') return 0
}
// 1) on rend le changement FACILE (le pré-refactoring) : une table
const TARIFS = { standard: 4.99, retrait: 0 }
function frais(transporteur) { return TARIFS[transporteur] ?? 4.99 }
// 2) on fait le changement facile : une ligne, zéro logique touchée
TARIFS.express = 9.99
Sans le pré-refactoring, ajouter « express » voulait dire entrer dans le if/else et risquer de casser les cas existants. Après, c'est une ligne de données. C'est tout le sens du tweet de Beck : on a payé un petit nettoyage d'abord pour que la vraie demande devienne triviale.
Et la contrepartie : du code moche qu'on n'a jamais besoin de modifier se laisse tranquille. « Si je tombe sur un code en désordre, mais que je n'ai pas besoin de le modifier, alors je n'ai pas besoin de le refactorer. »
4Les odeurs remplacent les métriques
Quand refactorer ? Le chapitre 3, coécrit avec Kent Beck, s'ouvre sur la règle de sa grand-mère : « si ça pue, change-le ». Le livre refuse explicitement les seuils chiffrés : « aucun ensemble de métriques ne rivalise avec l'intuition humaine informée ». Pour les fonctions longues, le vrai critère n'est « pas la longueur, mais la distance sémantique entre ce que la méthode fait et comment elle le fait ».
Vingt-quatre odeurs sont cataloguées. Celles que je croise toutes les semaines :
- Feature Envy : une fonction passe son temps chez les données d'un autre module ;
- Shotgun Surgery : un changement logique = dix fichiers à toucher ;
- Data Clumps : les mêmes 3-4 valeurs voyagent toujours ensemble, un objet attend de naître ;
- Primitive Obsession : des strings et des ints à la place des concepts métier ;
- Mutable Data : « une des plus grosses sources de problèmes du logiciel » ;
- Comments : le commentaire-déodorant ; l'envie de commenter un bloc = extraire une fonction à la place.
Une odeur en chair et en os, le Data Clumps (le « paquet de données ») : dès que les mêmes valeurs voyagent collées partout, c'est un objet qui demande à naître.
// odeur : ville + cp + rue se baladent toujours ensemble, dans chaque signature
function livrer(ville, cp, rue) { ... }
function facturer(ville, cp, rue) { ... }
// après : ces 3 valeurs ÉTAIENT un concept, on lui donne un nom
class Adresse { ville; cp; rue }
function livrer(adresse) { ... }
function facturer(adresse) { ... }
Le seuil personnel de Fowler, pour mémoire : « toute fonction de plus d'une demi-douzaine de lignes commence à sentir ».
🎨 Illustration à générer : copier ce prompt dans ChatGPT :
Flat illustration, warm ivory background (#faf7f2), muted green and terracotta palette, no text, minimalist editorial style, a kind elderly grandmother with glasses holding a sheet of source code at arm's length like a smelly dirty diaper, clothespin on her nose, small stink wavy lines rising from the paper, deadpan humor, 3:2 aspect ratio
Légende prévue : « La règle de la grand-mère de Beck : si ça pue, change-le. »
5Pas de refactoring sans filet
La condition de tout ce qui précède : « le refactoring exige des tests. Si vous voulez refactorer, vous devez écrire des tests » (ch. 4). Fowler l'a découvert empiriquement en 1992 : rendre ses tests auto-vérifiants a quasi supprimé son temps de débogage. La nuance est concrète :
// ✗ non auto-vérifiant : la machine affiche, c'est VOUS qui jugez
console.log(prixTotal(commande)) // "53.91" … est-ce juste ? à vous de relire
// ✓ auto-vérifiant : le test dit lui-même PASS ou FAIL
expect(prixTotal(commande)).toBe(53.91)
Avec la première version, refactorer 200 fonctions voudrait dire relire 200 sorties console à l'œil. Avec la seconde, on lance la suite et le rouge saute aux yeux. C'est ce qui rend les « pas minuscules » de l'idée 2 possibles : sans filet auto-vérifiant, on n'ose pas. « Une suite de tests est un puissant détecteur de bugs qui décapite le temps nécessaire pour les trouver. »
Les règles pratiques ont remarquablement bien vieilli : une fixture neuve pour chaque test (jamais d'état partagé entre tests), injecter temporairement une faute pour vérifier qu'un test sait échouer, et mesurer la suffisance à la confiance, pas au coverage : si quelqu'un cassait le code, est-ce qu'un test le verrait ?
6Conditions : gardes, flags, polymorphisme
Le chapitre du catalogue qui rapporte tous les jours est celui des conditions. Premier geste : les guard clauses. Quand une branche est le cas normal et les autres des exceptions, les exceptions sortent tôt et le chemin normal se lit à plat :
// avant : le cas normal est enterré trois niveaux plus bas
if (!estDecede) {
if (!estSepare) {
if (!estRetraite) { resultat = paieNormale(); }
}
}
// après : clauses de garde, le cas normal se lit à plat
if (estDecede) return montantDeces();
if (estSepare) return montantSeparation();
if (estRetraite) return montantRetraite();
return paieNormale();
Au passage, Fowler démonte la règle du point de sortie unique : « un seul point de sortie n'est vraiment pas une règle utile. La clarté est le principe clé. » Deuxième geste : tuer les flag arguments, parce que « dans un appel de fonction, je ne peux pas deviner ce que true veut dire » ; deux fonctions bien nommées battent un booléen. Troisième : Replace Conditional with Polymorphism, réservé aux switch répétés sur le même type. Avec la nuance anti-dogme : « la plupart de ma logique conditionnelle utilise des instructions basiques : if/else et switch/case ».
7Chaque refactoring a un inverse
La méta-leçon discrète du catalogue : les gestes vont par paires, et le chemin retour existe toujours. La paire reine, Extract Function ↔ Inline Function, c'est le même code lu dans les deux sens :
// Extract Function → : on sort un bout nommé (clarifie une grosse fonction)
function total(c) { return sousTotal(c) + tva(c) }
function tva(c) { return sousTotal(c) * 0.2 }
// ← Inline Function : on réabsorbe (si le nom n'apporte plus rien)
function total(c) { return sousTotal(c) * 1.2 }
Aucune des deux directions n'est « la bonne » : extraire clarifie quand le bout a un sens métier, réabsorber simplifie quand le nom est un détour inutile. La bonne direction dépend du contexte de la semaine. Les autres paires suivent la même logique : Hide Delegate et Remove Middle Man, Replace Parameter with Query et son inverse, Pull Up et Push Down.
C'est ce qui libère du dogme. Sur le bon niveau d'encapsulation : « c'est difficile à déterminer ; heureusement, avec Hide Delegate et Remove Middle Man, ça n'a pas tant d'importance : je peux ajuster mon code au fil du temps ». Même la Loi de Déméter y passe : Fowler l'aimerait beaucoup plus « si elle s'appelait la Suggestion occasionnellement utile de Déméter ».
8L'héritage est une carte qui ne se joue qu'une fois
Là où The Pragmatic Programmer dit « stop », Fowler explique comment vivre avec. Sa position (ch. 12) : « j'utilise l'héritage fréquemment, en partie parce que je sais que je peux toujours appliquer Replace Subclass with Delegate si je dois en changer plus tard ». Il réécrit le slogan célèbre à sa façon : « préférez un mélange judicieux de composition et d'héritage à l'un des deux seuls, mais je crains que ce soit moins accrocheur ».
Le mécanisme derrière le jugement : l'héritage ne gère qu'un seul axe de variation. Tant qu'il n'y en a qu'un, il est parfait ; le jour où un deuxième apparaît, l'arbre explose en combinatoire.
// 1 axe (le type) : l'héritage va très bien
class Reservation {}
class ReservationPremium extends Reservation {}
// 2e axe (remboursable ou non) : il faut UNE classe par combinaison
class ReservationPremiumRemboursable extends ... ? // et ainsi de suite : 2×2, puis 2×3…
// délégation : la réservation COMPOSE deux axes indépendants
class Reservation {
constructor(tarif, politiqueRemboursement) { ... } // 2 pièces, plus d'arbre
}
C'est le moment exact où Fowler applique Replace Subclass with Delegate, et le catalogue donne le chemin pas à pas. Le contre-exemple historique qu'il cite : faire de Stack une sous-classe de List, dont on hérite des méthodes qu'on doit ensuite refuser. La délégation, c'est le « préférez la composition » de la fiche Design Patterns, vu côté refactoring : on n'y arrive pas d'un coup, on y migre quand le 2ᵉ axe pointe.
Trois choses que je ne savais pas
- Quand le bon nom est encore pris par l'ancienne fonction, Fowler nomme temporairement la nouvelle
appleSauce(compote de pommes), le temps de libérer le nom (ch. 1). - Fowler a croisé le refactoring à OOPSLA 1992, via la thèse de doctorat de Bill Opdyke, et a pensé : « Intéressant, mais pas si important que ça. Qu'est-ce que je me trompais ! » (ch. 2)
- Sur Remove Dead Code, la phrase la plus joyeuse du livre : « rien n'est aussi satisfaisant que de passer le lance-flammes numérique sur les instructions superflues ». (ch. 8)
Mon avis, honnêtement
Le chapitre 1 est la meilleure leçon de code que j'aie lue : soixante-dix pages où on regarde quelqu'un travailler, chaque geste expliqué, le code jamais cassé. Et Fowler a une honnêteté rare : son argument central est étiqueté « hypothèse non prouvée », et ses conseils sont pleins de « je ne suis pas pur à 100 % là-dessus ».
La limite : la moitié du livre est un dictionnaire. Personne ne lit les chapitres 7 à 12 d'une traite ; on les consulte. Les exemples JavaScript étaient le bon choix en 2018 et datent déjà côté outillage (Babel, Mocha). Et le conseil « ne dites pas à votre manager que vous refactorez » est signalé comme controversé par Fowler lui-même : il l'est.
Mais ce dictionnaire a changé le métier : le menu Refactor de votre éditeur existe à cause de ce livre. Lisez les chapitres 1 à 4 comme un roman, gardez le reste à portée de main en revue de code. Neuf développeurs sur dix devraient lire les cent premières pages ; le catalogue les attendra sur l'étagère.
Odilon
Toujours valable en 2026 ?
Plus qu'en 2018. Les assistants IA produisent à grande vitesse du code qui marche mais sent fort, et ce livre est la grille pour le juger : le catalogue des odeurs se lit comme une checklist de revue de code généré, et « d'abord rendre le changement facile, ensuite faire le changement facile » est exactement le bon workflow avec un assistant. Les outils et les LLM automatisent la mécanique de chaque refactoring ; savoir quand et quoi reste du jugement, et c'est précisément ce que le livre enseigne. Ce qui a vieilli : l'outillage JavaScript de 2018, et la charge contre les feature branches (les PR courtes ont gagné sans tuer le refactoring).
Pour qui ?
Lisez-le si
- Vous maintenez du legacy et « refactorer » signifie pour vous un chantier d'une semaine qui fait peur
- Vous voulez nommer les gestes en revue de code au lieu de dire « nettoie un peu ça »
- Vous avez lu Clean Code et cherchez le mode d'emploi qui va avec le pourquoi
- Vous relisez du code généré par IA : les odeurs sont votre checklist
Passez votre chemin si
- Vous attendez une lecture de bout en bout : la moitié du livre est une référence à consulter
- Vous n'écrivez pas encore de tests : commencez par là, refactorer sans filet est un pari
- Vous cherchez de l'architecture macro : ici c'est du micro-design, fonction par fonction
Pour aller plus loin
Le filet de sécurité se construit dans mon cours sur les tests, et héritage contre composition se travaille dans le cours POO. Côté bibliothèque, Clean Code est le pourquoi de ce comment, The Pragmatic Programmer partage le combat contre l'impôt sur l'héritage, et TDD by Example est l'origine du rythme à petits pas.
Commentaires (0)