Be Software Architecture Wise
Be Wise Apps

Read in English · Leer en español · Auf Deutsch lesen

Section 1.7 sur 1.8 · Intermédiaire · 20 min de lecture

Dette technique, érosion et dérive de l’architecture

Leçon vidéo

4 min · narré en anglais, avec sous-titres
Écouter seulement (audio)
Lire la transcription

Toute équipe prend des raccourcis, et toute conception vieillit à mesure que vous en apprenez davantage. Cette leçon explique la dette technique : ce qu’elle signifie vraiment, comment la voir, et comment décider de ce qui mérite d’être remboursé.

Imaginez que vous déménagez dans l’urgence et que vous jetez tout dans des cartons sans étiquettes. Vous avez déménagé à temps, et c’était le but. Mais désormais, chaque fois que vous cherchez quelque chose, vous perdez dix minutes à fouiller. Ces minutes perdues, ce sont les intérêts. Déballer et étiqueter correctement, c’est rembourser la dette. Un peu de dette, c’est acceptable, et parfois sage. Le danger est de la laisser s’accumuler.

Ward Cunningham a forgé le terme en 1992. Livrer du code écrit pour la première fois revient à s’endetter : un peu de dette vous fait aller plus vite, à condition de la rembourser rapidement. Il a expliqué plus tard que ce n’était en rien un permis d’écrire du code bâclé. Son propos portait sur la compréhension. Vous livrez du code qui reflète ce que vous savez aujourd’hui, et à mesure que vous en apprenez davantage, vous le refactorisez pour qu’il corresponde. Cela ne fonctionne que si le code est assez propre pour être refactorisé.

Le vocabulaire financier aide. Le principal est l’effort nécessaire pour corriger le problème. Les intérêts sont l’effort supplémentaire que vous payez à chaque changement qui le touche. Si une fonctionnalité prendrait quatre jours dans du code propre mais en prend six, les deux jours supplémentaires sont des intérêts. Une dette dans du code qui ne change jamais ne coûte donc rien. Rembourser est une décision d’investissement : cela vaut la peine quand les intérêts que vous économiserez dépassent le principal.

Martin Fowler classe la dette selon deux axes : a-t-elle été contractée délibérément ou involontairement, et était-ce imprudent ou prudent ? Prudente et délibérée : il faut livrer maintenant et gérer les conséquences. Elle est assumée et planifiée, avec un plan de remboursement, et cela peut être une bonne décision commerciale. Imprudente et délibérée : nous n’avons pas le temps de concevoir. L’équipe sait faire mieux mais prend quand même des raccourcis, et se ralentit généralement elle-même en quelques semaines. Imprudente et involontaire : l’organisation en couches, c’est quoi ? L’équipe ne voit pas la dette qu’elle crée. Le remède passe par les compétences, les revues et le mentorat, pas par la seule refactorisation. Prudente et involontaire : maintenant, nous savons comment nous aurions dû faire. Toute équipe qui apprend finit par arriver ici, et c’est pourquoi la refactorisation continue est du travail normal, pas un signe d’échec.

La dette de code vit à l’intérieur d’un module, et peut souvent être remboursée en quelques heures ou quelques jours. La dette architecturale vit dans la structure, par exemple dans des services qui partagent une base de données. La rembourser touche de nombreuses équipes, et souvent les données, c’est donc la plus coûteuse. Perry et Wolf ont nommé deux façons dont une structure se dégrade. L’érosion vient des violations, comme un contrôleur qui interroge directement la base de données en contournant la couche de services. La dérive vient de l’insensibilité : des changements qui n’enfreignent aucune règle mais ignorent les concepts prévus, si bien que le système perd peu à peu sa forme.

Comment trouver la dette qui compte ? Une technique place chaque fichier selon la fréquence à laquelle il change et sa complexité. Les fichiers complexes qui changent rarement coûtent peu d’intérêts. Laissez-les de côté pour l’instant. Les fichiers simples qui changent souvent ne posent généralement pas de problème. Mais là où la complexité et les changements fréquents coïncident, vous payez des intérêts à chaque commit. Ces hotspots sont les endroits où le remboursement est rentable en premier.

Pour défendre son dossier, une boutique en ligne mesure la dette dans un module que partagent les commandes et les paiements. Il a changé quarante-huit fois en six mois : c’est le premier hotspot. L’effort supplémentaire sur chaque changement, plus les incidents, représente environ quatorze jours-développeur par mois. Cela fait environ huit mille quatre cents livres. Séparer les commandes des paiements, par petites étapes, coûterait environ quarante-cinq jours-développeur, soit environ vingt-sept mille livres. Avec environ onze jours économisés chaque mois, l’investissement est remboursé en quatre mois environ. Même en doublant le coût, il est remboursé en huit mois environ. C’est un argumentaire dans les termes du commanditaire : jours, argent et délai de retour, pas qualité du code.

Voilà ce qu’est la dette technique. La section complète présente d’autres façons de la détecter, et explique comment la gérer avec un registre de la dette, une capacité protégée et une refactorisation au fil de l’eau. Ensuite, dans la section un point huit, nous examinons l’architecture tout au long du cycle de vie. À très vite.

Ce qu’il faut savoir

Ce que Ward Cunningham voulait vraiment dire

Le terme dette technique vient du retour d’expérience de Ward Cunningham sur le système de gestion de portefeuille WyCash, présenté à la conférence OOPSLA en 1992. Il y écrivait que livrer du code écrit pour la première fois revient à s’endetter : un peu de dette accélère le développement, à condition d’être remboursée rapidement par une réécriture, et le danger survient quand elle ne l’est pas : Chaque minute passée sur du code pas tout à fait juste compte comme des intérêts sur cette dette. Des organisations d’ingénierie entières, avertissait-il, peuvent être paralysées sous le poids de la dette.

On interprète souvent la métaphore comme une permission d’écrire du code bâclé. Cunningham a expliqué plus tard (dans une courte vidéo de 2009) que ce n’avait jamais été son intention. Son propos portait sur la compréhension. Une équipe livre du code qui reflète sa compréhension actuelle, partielle, d’un problème, parce que c’est le moyen le plus rapide d’apprendre de l’usage réel. À mesure que la compréhension s’améliore, le code ne correspond plus à ce que l’équipe sait désormais, et chaque changement doit contourner ce décalage. Rembourser la dette signifie refactoriser le code pour qu’il reflète ce qui a été appris. Cela ne fonctionne que si le code a été écrit assez proprement pour pouvoir être refactorisé au départ. Selon cette lecture, la dette est un sous-produit de l’apprentissage, et non de la négligence.

Depuis, l’usage s’est élargi. Aujourd’hui, « dette technique » couvre toute insuffisance de qualité interne qui rend les changements futurs plus lents ou plus risqués, qu’elle provienne de l’apprentissage, de raccourcis délibérés, de l’ignorance ou d’une simple négligence. Ce sens élargi est utile tant que vous gardez à l’esprit que les différents types de dette appellent des réponses différentes.

Le principal et les intérêts

C’est le vocabulaire financier qui rend la métaphore puissante dans les conversations avec des personnes qui ne sont pas ingénieurs. Le principal est l’effort nécessaire pour corriger le problème : restructurer le module, séparer la base de données, supprimer le cycle. Les intérêts sont l’effort supplémentaire payé sur chaque travail qui touche le problème tant qu’il subsiste. L’illustration de Martin Fowler : si une fonctionnalité prendrait quatre jours dans du code propre mais en prend six à cause du code encombré (cruft), les deux jours supplémentaires sont des intérêts.

Trois conséquences en découlent. Premièrement, une dette à laquelle on ne touche jamais ne coûte rien : un module désordonné que personne ne modifie n’accumule pas d’intérêts, si bien que le rembourser peut être un effort perdu. Deuxièmement, les intérêts se composent : les contournements deviennent les fondations de nouveaux contournements, les nouveaux développeurs copient les façons de faire qu’ils voient, et le coût de la réparation finale augmente. Troisièmement, le remboursement est une décision d’investissement : il vaut la peine de payer le principal quand les intérêts que vous économiserez sur un horizon raisonnable le dépassent. Cela transforme un argument émotionnel (« le code est un fouillis ») en argument économique (« ce module nous coûte onze jours par trimestre »).

Le quadrant de la dette technique de Fowler

Toutes les dettes ne se valent pas. En 2009, Martin Fowler a proposé de classer la dette selon deux axes : a-t-elle été contractée délibérément ou involontairement, et la décision était-elle prudente ou imprudente ? Les quatre combinaisons appellent des réponses différentes.

Prudente et délibérée : l’équipe connaît la meilleure conception, juge que livrer maintenant vaut le coût, et prévoit de rembourser. C’est le sens originel de Cunningham, et cela peut être une bonne décision commerciale : une start-up qui prouve la demande avant d’investir dans le passage à l’échelle. Imprudente et délibérée : l’équipe sait faire mieux mais saute la conception parce qu’elle croit ne pas avoir le temps, et se ralentit généralement elle-même en quelques semaines. Imprudente et involontaire : l’équipe n’en sait pas assez pour voir qu’elle crée de la dette ; le remède passe par les compétences, les revues et le mentorat plutôt que par la seule refactorisation. Prudente et involontaire : une équipe compétente fait du bon travail et ne comprend que plus tard comment elle aurait dû structurer le système. Fowler soutient que c’est inévitable pour toute équipe qui apprend, et c’est pourquoi la refactorisation continue fait partie du travail normal au lieu d’être un signe d’échec.

Le quadrant de la dette technique

Quadrant de la dette technique de Martin Fowler : imprudente ou prudente, délibérée ou involontaireImprudentePrudenteDélibéréeInvolontaire« Pas le temps deconcevoir. »Avertie, maisprend des raccourcis« Livrons maintenant etgérons les conséquences. »Assumée, planifiée,remboursement prévu« Des couches ? »Ignore qu’ellecrée de la dette« Maintenant, on saitcomment on aurait dû. »Apprendre révèleun meilleur plan
D’après Martin Fowler (2009) : les deux quadrants imprudents relèvent d’un problème de discipline ou de compétence ; les deux quadrants prudents sont des conséquences normales de la livraison en situation d’incertitude.

Dette architecturale ou dette de code

La dette existe à tous les niveaux, mais son profil de coût change avec l’échelle. La dette de code vit à l’intérieur d’un module : logique dupliquée, fonction qui fait cinq choses, tests manquants, noms mal choisis. Elle est réelle, mais locale ; un développeur peut généralement la rembourser en quelques heures ou quelques jours, souvent en travaillant sur une fonctionnalité voisine. La dette architecturale vit dans la structure : des services qui partagent une base de données, si bien qu’aucun ne peut modifier son schéma seul ; un domaine découpé selon les mauvaises lignes, si bien que chaque fonctionnalité touche quatre équipes ; une chaîne d’appels synchrones qui permet à un seul service lent de faire tomber l’étape de paiement ; un framework soudé à chaque couche. La rembourser touche de nombreux modules, souvent de nombreuses équipes, et parfois les données.

La recherche confirme l’intuition selon laquelle la dette structurelle est la plus coûteuse. Une enquête de 2015 menée auprès de 1831 ingénieurs et architectes par Neil Ernst et ses collègues du Software Engineering Institute a montré que les décisions d’architecture étaient la principale source de dette technique signalée, devant les problèmes au niveau du code. Les outils qui signalent les défauts de code (code smells) sont bons pour trouver la dette de code et mauvais pour trouver la dette architecturale, car le problème se situe dans les relations entre les parties plutôt que dans un fichier en particulier.

La dette architecturale compte pour la même raison que l’architecture compte tout court : comme l’a montré Pourquoi l’architecture compte, les décisions structurelles sont celles dont le coût de changement est le plus élevé.

Érosion et dérive

La dette d’architecture s’accumule souvent non pas à cause d’une seule mauvaise décision, mais au fil de milliers de petits changements. Dewayne Perry et Alexander Wolf, dans leur article de 1992 « Foundations for the Study of Software Architecture », ont nommé deux façons dont cela se produit. L’érosion de l’architecture est causée par des violations de l’architecture : un contrôleur qui interroge directement la base de données en contournant la couche de services ; un module qui va puiser dans les tables internes d’un autre. Chaque violation rend le système plus fragile, comme lorsqu’on retire un mur porteur. La dérive de l’architecture est causée par une insensibilité à l’architecture : des changements qui n’enfreignent aucune règle explicite mais ignorent les concepts prévus, si bien que le système perd peu à peu sa cohérence et la clarté de sa forme. La dérive est moins immédiatement dangereuse que l’érosion, mais elle obscurcit l’architecture, ce qui à son tour facilite les violations.

Les chercheurs ultérieurs emploient souvent « érosion » pour désigner l’écart plus large entre l’architecture prévue (ce que disent les documents et la tête de l’architecte) et l’architecture implémentée (ce que fait réellement le code). Quels que soient les termes, les causes sont familières :

La pression des délais, qui récompense le chemin le plus court plutôt que le bon chemin. La perte de connaissances, quand les personnes qui comprenaient la conception partent et que les nouveaux arrivants copient ce qu’ils trouvent. Une architecture invisible : des règles qui ne vivent que dans un wiki que personne ne lit, sans rien dans le build pour les faire respecter. Des exigences qui ont changé, et qui laissent une structure autrefois bonne mal adaptée au problème. Les changements d’organisation : selon la loi de Conway, une réorganisation pousse le système à se remodeler selon les nouvelles frontières des équipes. Le vieillissement des technologies : les frameworks et les plateformes qui ne sont plus pris en charge se transforment en dette sans que personne touche au code.

Détecter la dette

Une dette que vous ne voyez pas ne peut pas être gérée, et l’intuition n’est pas fiable : les développeurs ont tendance à se plaindre le plus fort du code qu’ils touchent le plus, ce qui est utile, mais ils savent rarement combien coûte chaque problème. Plusieurs techniques rendent la dette visible.

Hotspots (points chauds). Your Code as a Crime Scene d’Adam Tornhill (2015 ; deuxième édition 2024) applique des idées de criminalistique à l’historique de la gestion de versions. Un hotspot est du code à la fois complexe et souvent modifié. La complexité seule ne suffit pas : un fichier complexe auquel personne ne touche ne coûte aucun intérêt. La fréquence de changement seule ne suffit pas non plus : un simple fichier de configuration peut changer chaque jour sans dommage. Là où les deux coïncident, la dette se paie à chaque commit, et c’est là que le remboursement est rentable en premier. Dans la plupart des bases de code, une petite fraction des fichiers concentre l’essentiel de l’activité de changement.

Couplage de changement. Des fichiers ou des services qui changent sans cesse dans les mêmes commits sont couplés, que le code montre ou non une dépendance. Si chaque changement du service de tarification s’accompagne d’un changement du service de facturation, il s’agit d’une seule chose qui fait semblant d’en être deux. Un couplage de changement qui traverse les frontières d’équipes ou de services est un signe fort de dette architecturale.

Cycles de dépendances et violations de règles. L’analyse statique peut tracer le graphe de dépendances réel et le comparer au graphe prévu. Les cycles (A utilise B, B utilise C, C utilise A) signifient qu’aucun des trois ne peut être compris, testé ou mis en production seul. Les règles d’architecture (« la couche domaine ne doit pas dépendre de la couche web ») peuvent être vérifiées automatiquement à chaque build ; ce sont des fonctions d’aptitude (fitness functions), traitées au chapitre 11.

Tendances de livraison. L’allongement du délai de mise en œuvre des changements, davantage de défauts qui passent entre les mailles à chaque version, une intégration plus longue des nouveaux arrivants, davantage de réunions de coordination par fonctionnalité et une réticence croissante à toucher certaines zones sont des indicateurs retardés des intérêts accumulés. Les métriques de livraison DORA (comme le délai de mise en œuvre des changements et le taux d’échec des changements) offrent un moyen cohérent de suivre certains d’entre eux dans le temps.

Repérer les hotspots

Nuage de points des fichiers selon la fréquence de changement et la complexité, hotspots en haut à droiteFréquence de changement (commits des 12 derniers mois)ÉlevéBasComplexitéHotspots : débuter iciComplexe et stable :pas pour l’instantSimple et actif :souvent anodin
Placer chaque fichier selon la fréquence à laquelle il change et sa complexité montre où la dette se paie le plus souvent : les quelques fichiers du coin supérieur droit.

Gérer la dette

Aucune base de code saine n’a une dette nulle, et chercher à atteindre zéro est en soi un gaspillage. Le but est de garder la dette visible, délibérée et abordable. Les équipes qui y parviennent combinent plusieurs pratiques.

Un registre de la dette. Consignez les éléments de dette importants là où l’équipe planifie son travail : quel est le problème, où il se trouve, comment il est apparu, le principal estimé, les intérêts estimés (avec des éléments probants comme les données de hotspots ou des tickets récents), et le déclencheur de son remboursement. Un registre transforme des plaintes vagues en une liste qui peut être priorisée au même titre que les fonctionnalités.

Une part fixe de la capacité. Beaucoup d’équipes réservent une proportion stable de chaque itération, couramment entre 10 et 20 %, au remboursement de la dette et à d’autres travaux d’amélioration. Aucune donnée ne justifie un chiffre magique ; ce qui compte, c’est que cette part soit protégée et ne disparaisse pas dès qu’une échéance approche.

Refactoriser en même temps que les fonctionnalités. Le moment le moins coûteux pour rembourser la dette est celui où vous travaillez déjà dans la zone, parce que vous avez le contexte en tête et les tests qui tournent. Fowler appelle cela la refactorisation opportuniste. Sa forme quotidienne est la règle du boy-scout, popularisée par Robert C. Martin : laissez le code un peu plus propre que vous ne l’avez trouvé. Comme les hotspots sont par définition les endroits où arrivent les fonctionnalités, cela concentre naturellement l’effort là où les intérêts sont les plus élevés.

Un remboursement structurel planifié. La dette architecturale cède rarement à de petites étapes seules. Elle exige un chantier explicite et financé, avec un objectif, un plan de migration par incréments et le soutien des parties prenantes. Des techniques comme le patron strangler fig (figuier étrangleur) (chapitre 11, Moderniser les systèmes hérités) permettent à une équipe de remplacer une structure morceau par morceau sans réécriture big bang.

La prévention. Des vérifications automatisées de l’architecture dans le build, une revue de code qui examine la structure autant que le style, et des enregistrements de décision à jour ralentissent l’érosion et la dérive à la source.

Expliquer la dette aux parties prenantes non techniques

Les commanditaires et les product owners n’ont pas besoin d’entendre parler de dépendances cycliques ; ils ont besoin de comprendre l’effet sur ce qui leur importe : la vitesse, le coût, le risque et l’expérience client. La métaphore financière est ici un cadeau, à condition de l’utiliser avec des chiffres.

Parlez en temps et en argent : « Chaque changement de l’étape de paiement nous coûte environ trois jours-développeur de plus, à cause de la façon dont le paiement et les commandes sont enchevêtrés. » Parlez en risques : « Deux de nos quatre derniers incidents ont commencé dans ce module. » Parlez en options : « Tant que nous n’aurons pas séparé ces deux parties, nous ne pourrons pas proposer les nouveaux moyens de paiement que l’équipe commerciale a demandés. » Et présentez le remboursement comme un investissement avec un délai de retour, et non comme une supplique pour obtenir du temps d’ingénierie. Évitez deux pièges : présenter la dette comme une faute morale de ceux qui vous ont précédés (elle est généralement prudente ou involontaire), et demander un « sprint de refactorisation » sans limite ni résultat mesurable.

Exemple commenté

Exemple commenté : estimer les intérêts d’une dette

La logique de commande et de paiement d’une boutique en ligne partage un seul gros module et les mêmes tables de base de données. L’équipe soupçonne que cela lui coûte cher. Elle rassemble des éléments tirés des six derniers mois de tickets et de l’historique de la gestion de versions, puis fait une estimation.

Changements touchant le module48 changements en six mois, soit environ 8 par mois (c’est le premier hotspot).
Effort supplémentaire par changementEn comparant avec des changements similaires ailleurs, les développeurs estiment environ 1,5 jour de plus pour chacun, pour comprendre, contourner les tables partagées et faire des tests de régression supplémentaires.
Intérêts en effort8 changements × 1,5 jour = 12 jours-développeur par mois.
Intérêts en défauts3 incidents de production en six mois attribués à ce module, chacun coûtant environ 4 jours-développeur d’investigation et de correction : 12 jours ÷ 6 = 2 jours par mois.
Intérêts totauxEnviron 14 jours-développeur par mois. À un coût complet de £600 par jour-développeur, environ £8 400 par mois, soit environ £100 000 par an.
PrincipalSéparer les commandes des paiements derrière une interface et scinder les tables, de façon incrémentale : estimé à 45 jours-développeur, soit environ £27 000.
Intérêts résiduels après remboursementLes développeurs s’attendent à ce qu’un certain surcoût subsiste : estimé à 3 jours-développeur par mois.
Délai de retourÉconomie mensuelle d’environ 11 jours-développeur. 45 ÷ 11 donne environ 4 mois pour récupérer le principal.
RecommandationRembourser, par incréments d’environ deux semaines chacun, en commençant par les tables le plus souvent impliquées dans des incidents. Suivre le délai de mise en œuvre des changements de l’étape de paiement pour confirmer l’économie.

Chaque chiffre est une estimation avec de larges marges d’erreur. Même en doublant le principal pour le porter à 90 jours, l’investissement est encore remboursé en environ huit mois : la conclusion est donc robuste ; c’est une vérification qui mérite d’être montrée aux parties prenantes.

La même méthode peut montrer que certaines dettes ne valent pas la peine d’être remboursées : un module désordonné modifié deux fois par an peut avoir un délai de retour de plusieurs années.

L’argumentaire est construit dans les termes du commanditaire (jours, argent, incidents, délai de retour), et non en termes de qualité du code.

Vérifiez votre compréhension

Pourquoi un module très désordonné peut-il avoir une faible priorité de remboursement ?

Parce que les intérêts ne se paient que lorsque le code est modifié ou provoque des défaillances. Si personne n’y touche et qu’il est stable, la dette ne coûte presque rien.

Pourquoi la dette imprudente et involontaire ne se guérit-elle pas par la seule refactorisation ?

Parce que l’équipe ne savait pas qu’elle créait de la dette ; tant que ses compétences et ses pratiques de revue ne s’améliorent pas, elle continuera à créer le même type de dette aussi vite qu’elle la rembourse.

Quelle est la différence entre l’érosion et la dérive selon Perry et Wolf ?

L’érosion résulte de la violation des règles de l’architecture ; la dérive résulte de changements faits sans égard pour l’architecture, qui n’enfreignent aucune règle explicite mais brouillent ses concepts.

Pourquoi les analyses de hotspots combinent-elles la fréquence de changement et la complexité plutôt que d’utiliser l’une ou l’autre seule ?

Un code complexe qui ne change jamais accumule peu d’intérêts, et un code simple qui change souvent est peu coûteux à modifier ; seule la combinaison des deux montre où la dette coûte de l’effort de façon répétée.

Suivant · 1.8L’architecture dans le cycle de vieLa conception complète en amont (big design up front) face à la conception émergente, ce que dit réellement le Manifeste agile, le modèle piloté par les risques de Fairbanks, l’architecture intentionnelle et la piste architecturale, l’architecture continue, les squelettes ambulants, les spikes et l’architecture dans le DevOps.Continuer →

Sources et lectures complémentaires

Une question sur cette section ? ArchitectBot, l’assistant d’étude IA du cours, répond d’abord à partir du cours.

Demander : « Comment convaincre mon product owner de consacrer du temps à rembourser la dette architecturale alors que le backlog de fonctionnalités est long ? »