D'où vient le mot, et pourquoi l'origine compte
Ward Cunningham a inventé la métaphore pour expliquer à des gens de la finance pourquoi son équipe passait du temps à réécrire du code qui fonctionnait déjà. Son argument n'était pas que le mauvais code est une dette. Son argument était qu'expédier une première version imparfaite permet d'apprendre vite, et que ce qu'on apprend doit ensuite être remis dans le code. Si on ne le remet pas, on paie des intérêts sur tout ce qu'on construit par-dessus.
C'est une métaphore financière, et elle a été pensée comme telle. Elle décrit un emprunt consenti. Elle ne décrit pas un accident.
Aujourd'hui le mot sert à désigner à peu près n'importe quoi qui déplaît dans une base de code. C'est dommage, parce que la version d'origine servait à quelque chose de précis.
Je précise tout de suite que nous vendons du refactoring et de la reprise de legacy. Donc quand j'écris plus bas qu'une bonne partie de ce qu'on appelle dette technique ne mérite pas qu'on y touche, lisez-le en sachant que cela va contre notre intérêt commercial immédiat.
Dette consentie, et simple désordre
Deux choses très différentes portent le même nom.
La première. Une équipe sait comment il faudrait faire, décide de ne pas le faire, et note pourquoi. On code en dur trois cas particuliers au lieu d'écrire le moteur de règles, parce que la démo est dans six semaines et qu'un moteur générique n'apporte rien à cette démo. C'est un arbitrage. Il a une contrepartie, une échéance, et un coût de remboursement qu'on peut estimer. C'est une décision de financement, au même titre qu'un crédit de trésorerie, et elle peut être excellente.
La seconde. Personne n'a rien décidé. La logique métier s'est répandue dans quatre couches parce que trois développeurs se sont succédé sans jamais se parler. Ce n'est pas de la dette. C'est du désordre. Il n'y a pas eu d'emprunt, donc il n'y a rien qui a été acheté avec.
Confondre les deux, c'est la raison pour laquelle la discussion avec la direction financière tourne mal. Vous arrivez en disant « nous avons de la dette technique », ce qui sonne comme une décision assumée. Votre interlocuteur entend « nous avons emprunté pour financer quelque chose », et demande légitimement ce que cet emprunt a payé. Si la réponse honnête est « rien, c'est arrivé tout seul », vous venez de perdre la conversation, et vous la reperdrez au trimestre suivant.
Séparez donc les deux dans votre discours. Il y a ce que nous avons choisi d'emprunter pour sortir en novembre. Et il y a ce qui s'est dégradé faute d'attention. Les deux coûtent de l'argent. Un seul des deux a acheté quelque chose.
Pourquoi ça compose
Une dette financière normale a un échéancier. Vous savez quand vous payez et combien. La dette technique n'a pas d'échéancier. Elle prélève sur chaque modification suivante, et le prélèvement grandit.
Le mécanisme est simple. Le raccourci pris en janvier devient un support sur lequel deux fonctionnalités s'appuient en mars. En juin, il y en a six, et le contourner proprement demande de toucher les six. Le coût du remboursement a triplé sans que personne n'ait rien fait de mal entre-temps. Vous n'avez pas non plus payé moins cher les six fonctionnalités. Chacune a coûté un peu plus que la précédente, parce que chacune a dû composer avec le raccourci.
Voilà l'intérêt composé de la métaphore, et il est très réel.
La partie perverse, c'est la forme du paiement. Aucun intérêt n'apparaît sur un compte de résultat. Il se paie en lenteur : des estimations qui gonflent sans raison apparente, des développeurs qui deviennent prudents, des changements simples qui passent en revue trois fois, un test manuel de plus avant chaque mise en production parce que la dernière fois ça a cassé ailleurs.
Rien de tout cela n'a de ligne comptable. C'est exactement pour ça que ça reste invisible jusqu'au jour où c'est cher. À ce moment-là, ce qu'on entend en comité de direction n'est pas « nous avons un problème de dette », c'est « l'équipe technique n'avance plus », ce qui est le même fait raconté par quelqu'un qui n'a pas les mots.
Rendre la chose lisible à quelqu'un qui ne lit pas de code
La plupart des développeurs plaident leur cause avec des adjectifs. Le code est sale, fragile, illisible, mal fichu. Un directeur financier n'a aucun moyen d'agir sur un adjectif. Il ne sait pas si « sale » coûte dix mille euros ou trois cent mille, et comme il ne sait pas, il reporte.
Ce qui fonctionne, c'est de parler en délai et en risque.
En délai : prenez une catégorie de changement que vous faites régulièrement, ajouter un champ à un formulaire, brancher un nouveau moyen de paiement, sortir un rapport. Regardez combien de temps cela prenait il y a dix-huit mois et combien cela prend aujourd'hui. L'historique Git et le board vous donnent les deux chiffres sans avoir à les inventer. Si l'écart existe, vous n'avez plus besoin d'adjectifs : la même demande coûte plus cher qu'avant, et voici de combien.
En risque : combien de personnes dans l'entreprise peuvent modifier ce module sans surveillance. Si la réponse est une seule, vous n'avez pas un problème de code, vous avez un problème de continuité, et ça, tout dirigeant le comprend immédiatement. Ajoutez la part des incidents de production des six derniers mois qui viennent de la même zone. La concentration parle d'elle-même.
Ensuite, chiffrez sur la durée de vie réelle du logiciel et pas sur l'exercice en cours, parce que c'est là que la dette se voit. Nous avons détaillé cette mécanique dans notre article sur le coût total d'un logiciel sur cinq ans. Le raccourci qui a fait gagner trois semaines en année un se rembourse en année trois, souvent avec un multiple.
Et donnez une option chiffrée, pas une alerte. « Six semaines de travail sur ce module, après quoi les changements de cette famille reviennent à leur coût d'avant » est une proposition d'investissement. « Il faut refactoriser » n'en est pas une.
Réécrire ou réparer
C'est la décision la plus chère du sujet, et celle où les équipes techniques se trompent le plus souvent, nous compris. Nous avons déjà plaidé pour des réécritures que nous n'aurions pas dû plaider.
La réécriture complète est presque toujours plus longue, plus chère et plus risquée qu'elle n'en a l'air. Trois raisons.
L'ancien système contient des années de cas particuliers que personne n'a documentés. Ils ne sont pas dans les specs, ils sont dans le code, et vous ne les découvrez qu'en production, un par un, sous forme de plaintes clients. Ensuite, pendant la réécriture, vous devez faire vivre les deux systèmes, donc corriger deux fois et arbitrer en permanence entre alimenter l'ancien ou avancer sur le nouveau. Enfin, vous estimez la réécriture contre l'idée propre que vous avez du système, pas contre son comportement réel, qui est le seul périmètre à atteindre. C'est l'erreur d'estimation la plus fiable du métier.
Ajoutez que pendant ce temps, la feuille de route produit est gelée. Ce gel est un coût commercial, et il n'apparaît nulle part dans le budget du projet.
La réparation gagne quand le système rend le bon service, que sa plateforme est encore supportée, et qu'il existe assez de tests, ou assez de gens qui le connaissent, pour modifier sans casser. Dans ce cas, on isole la zone qui fait mal, on met une interface stable autour, et on remplace par l'intérieur. C'est lent et peu spectaculaire, mais ça se livre par petits morceaux, chacun vérifiable, et vous pouvez arrêter à tout moment sans perdre ce qui est déjà fait.
La réécriture gagne dans des cas identifiables. Quand le socle n'est plus supporté et ne reçoit plus de correctifs de sécurité, la décision est prise par quelqu'un d'autre que vous. Quand plus personne ne comprend le système, qu'il n'y a pas de tests et que la documentation est fausse, il n'y a rien sur quoi s'appuyer pour réparer. Quand le métier a réellement changé, si bien que la parité fonctionnelle n'est plus l'objectif et que la moitié de ce que fait l'ancien système ne doit pas être reconstruite. Et quand le système est assez petit pour être refait en moins de temps que votre cycle normal de décision, auquel cas le risque est faible parce que la fenêtre est courte.
Un signal pratique : si vous ne savez pas décrire, en une page, ce que fait l'ancien système, vous n'êtes pas prêt à le réécrire. Vous êtes prêt à en réécrire l'idée que vous en avez, ce qui est autre chose.
Toute la dette ne mérite pas d'être remboursée
C'est la partie que les gens de mon métier disent trop peu.
De la dette dans un module que personne ne touche ne coûte rien. Le module de facturation écrit il y a six ans, que deux personnes ont ouvert depuis, qui tourne sans incident et que la feuille de route n'approche pas, peut rester exactement comme il est. Il est laid. Il fonctionne. Le remettre au propre consommerait des semaines pour un gain nul, parce que l'intérêt ne se paie qu'au moment où l'on modifie.
La bonne priorisation croise deux informations que vous avez déjà. Où la douleur est réelle, et où le travail va se produire dans les douze mois qui viennent. L'historique Git vous donne la première moitié presque gratuitement : les fichiers qui concentrent les commits et les corrections de bugs sont vos points chauds. La feuille de route produit vous donne la seconde. L'intersection des deux, c'est la seule dette à rembourser cette année.
Tout ce qui est douloureux mais stable, vous le laissez. Tout ce qui est propre et actif, tant mieux. Et si un point chaud se trouve dans une zone que vous prévoyez de retirer l'année prochaine, ne le touchez pas non plus.
C'est un arbitrage d'investissement, pas un jugement esthétique, et c'est typiquement le genre de décision pour laquelle nos clients prennent un CTO à la demande plutôt qu'un recrutement. Il faut quelqu'un capable de dire non à une réécriture demandée par l'équipe, et de le justifier devant la direction.
Ce qu'un refactoring ne réparera pas
Une partie de ce qu'on appelle dette technique n'en est pas.
Parfois, le problème est produit. La fonctionnalité est lourde à maintenir parce qu'elle essaie de couvrir quatre usages différents qui n'auraient jamais dû vivre ensemble, et elle essaie de les couvrir parce que personne n'a tranché sur le client visé. Le code n'est pas compliqué par accident, il est compliqué fidèlement. Si vous le nettoyez sans trancher, vous obtiendrez une implémentation propre d'une mauvaise idée, et vous recommencerez dix-huit mois plus tard.
Parfois, le problème est organisationnel. Quatre équipes modifient le même module sans propriétaire clair. Chaque mise en production demande trois validations qui prennent une semaine chacune. Personne n'ose supprimer du code parce que personne ne sait qui s'en sert. Aucune de ces situations ne se corrige dans un éditeur de texte. Ce sont des problèmes de propriété, de mandat et de décision, et un refactoring les rendra simplement plus visibles.
La règle que j'applique est courte. Un refactoring ne répare ni un produit qui répond à la mauvaise question, ni une organisation qui ne sait pas décider. Il rend seulement l'exécution moins chère une fois que la question et la décision sont réglées.
Ce que nous faisons concrètement
Quand un client nous appelle sur ce sujet, nous commençons rarement par du code. Nous regardons l'historique, nous mesurons où les changements ralentissent, et nous demandons où va la feuille de route. La sortie de ce travail est une liste courte, chiffrée, avec ce que nous proposons de ne pas toucher, ce qui est en général la moitié de la liste d'origine.
Ensuite, soit votre équipe exécute et nous encadrons, soit nous prenons le module en charge et nous le rendons dans un état où vos développeurs peuvent y revenir. Cette seconde forme relève de notre offre d'externalisation informatique, et elle n'a d'intérêt que si vous récupérez la main derrière.
Un dernier point d'honnêteté. Si votre équipe vous dit depuis deux ans que le système ralentit et que rien n'a bougé, le problème n'est probablement pas technique. Il est dans le fait que personne n'a jamais traduit cette alerte en une décision d'investissement chiffrée, avec une option à accepter ou à refuser. Commencez par là. C'est gratuit, et c'est presque toujours l'étape manquante.
