- En refactorisant progressivement une couche d’accès aux données en Rust de 17 155 lignes écrite par un agent, le nombre de tokens d’entrée nécessaires pour une même modification fonctionnelle est passé de 159 564 à 27 360, soit une baisse de 83 %
- Le volume total de code est resté presque inchangé, mais la séparation du code concerné dans des fichiers à forte cohésion a permis à l’agent de ne lire que l’ensemble minimal de fichiers nécessaire à la modification
- Les tokens d’entrée n’ont pas fortement diminué tant que le plus gros fichier n’était pas devenu suffisamment petit ; au final, la couche de données a été divisée en 19 fichiers Rust et la taille maximale de fichier est passée de 17 155 à 3 695 lignes
- Les tokens de sortie et le volume d’implémentation fonctionnelle ont peu changé, et Claude n’a pas su choisir ni effectuer de manière fiable le refactoring approprié par lui-même : il a fallu des directives humaines actives pour la planification et l’exécution
- Au prix d’entrée de Sonnet 5, soit 3 $/MTok, l’économie par modification n’est que d’environ 0,397 $, mais l’expérience montre que le coût pourrait diminuer de façon répétée à chaque modification ultérieure de la couche d’accès aux données
Un fichier de 17 155 lignes créé par un agent
- L’application de support métier comprend une interface web avec mises à jour et consultations dynamiques, des modales et une sauvegarde automatique, des intégrations avec des systèmes externes, du machine learning et de l’analyse de texte, des tâches en arrière-plan et un environnement de déploiement automatisé
- Sur environ 150 000 lignes au total, Rust représente environ 120 000 lignes, le reste étant en TypeScript et Terraform ; la majeure partie a été écrite par des agents à l’aide de Claude Code et, dans une moindre mesure, de Cursor
- Le développeur n’a pas lu ni relu le code, sauf quelques coups d’œil occasionnels par curiosité
- La couche d’accès aux données a dépassé les 6 000 lignes en répétant les mêmes configurations de requêtes HTTP et le même encodage/décodage JSON dans toutes les requêtes de lecture et d’écriture, jusqu’à ce qu’un unique fichier Rust atteigne 17 155 lignes
- Ce module ne comportait ni déduplication ni langage interne, avec une extraction de fonctions limitée et presque aucune extraction de classes, mais il disposait d’interfaces à préserver et de frontières claires, ce qui en faisait un bon candidat pour une expérience de refactoring
Méthode de mesure en répétant la même modification
- L’objectif était de vérifier si investir des tokens dans le refactoring actuel pouvait réduire la consommation de tokens des futures modifications fonctionnelles
- Comme l’agent n’apprend pas des tâches précédentes, la même modification exacte a été demandée à un nouveau sous-agent à chaque étape, afin d’éviter tout effet d’apprentissage
- L’expérience s’est déroulée dans l’ordre suivant
- Rédiger un plan complet selon des principes stricts de refactoring
- Définir une modification représentative avec un seul prompt
- Faire réaliser la modification par un sous-agent et lui faire rapporter la consommation de tokens afin de mesurer la valeur de référence
- Jeter le résultat de la modification, puis appliquer une étape de refactoring
- Répéter la même modification, puis jeter à nouveau le résultat
- Enregistrer, étape par étape, le coût en tokens, le temps d’exécution et le nombre de lignes de code
- Comme Claude ne fournissait pas de manière fiable le nombre de tokens en temps réel, il a dû rapporter le nombre de caractères envoyés et reçus ; celui-ci a ensuite été divisé par 4 avec tiktoken pour approximer le nombre de tokens
Résultats de mesure par étape
- À l’état de référence, la couche d’accès aux données et le plus gros fichier comptaient tous deux 17 155 lignes, le code Rust total comptait 50 359 lignes, et la modification représentative nécessitait 159 564 tokens d’entrée, 1 705 tokens de sortie et 342 secondes
- Après 15 étapes, la couche d’accès aux données comptait 16 608 lignes, le plus gros fichier 3 695 lignes, le code Rust total 49 812 lignes, avec 27 360 tokens d’entrée, 2 113 tokens de sortie et un temps d’exécution de 454 secondes
- Aux étapes intermédiaires, les tokens d’entrée diminuaient à mesure que le plus gros fichier devenait plus petit
- Après l’étape 7, extraction de
queries.rs, le plus gros fichier est tombé à 15 670 lignes et l’entrée à 151 850 tokens - Après l’étape 8, extraction de
traits.rs, le plus gros fichier est passé à 13 845 lignes et l’entrée à 132 558 tokens - Après l’étape 12, séparation de
store/, le plus gros fichier est passé à 9 269 lignes et l’entrée a diminué jusqu’à 104 080 tokens - Après la dernière séparation de
store/, le plus gros fichier est tombé à 3 695 lignes et l’entrée a chuté à 27 360 tokens
- Après l’étape 7, extraction de
- La couche d’accès aux données finale se composait de 19 fichiers Rust, et le plus gros fichier était devenu la bibliothèque de tests
- Le même procédé pourrait être appliqué à ce fichier de tests lors de refactorings supplémentaires
Pourquoi les tokens d’entrée ont diminué de 83 %
- Pour la même tâche, les tokens d’entrée sont passés de 159 564 à 27 360, soit une économie de 132 204 tokens
- Comme le volume total de code de la couche d’accès aux données a très peu changé, ce résultat ne vient pas d’une réduction du code à lire en lui-même
- L’agent a identifié l’ensemble minimal de fichiers nécessaires à la tâche et n’a lu que des zones de code de plus en plus petites, ce qui se voyait aussi dans le raisonnement produit par Claude Code et dans les résumés de lecture de fichiers
- Découper arbitrairement les fichiers en petits morceaux ne produirait pas forcément le même effet, car il faudrait alors lire plusieurs fichiers pour retrouver le code pertinent
- La plus forte baisse s’est produite lors de la dernière séparation, mais celle-ci n’a été possible que parce que les étapes précédentes avaient extrait les doublons et fait émerger une structure centrale répétée
- Cette séquence n’avait pas été conçue à l’avance pour réduire les coûts : elle est issue d’un processus de refactoring classique consistant à supprimer d’abord les duplications locales, puis à faire apparaître un noyau commun avant de le décomposer en petits fichiers
Tokens de sortie et effet financier
- Les tokens de sortie générés pour écrire la modification représentative ont peu changé, si bien que le refactoring n’a pas réduit la taille réelle de la modification
- Le prix des tokens de sortie était 5 fois supérieur à celui des tokens d’entrée, mais leur volume absolu était bien plus faible
- Avec un prix d’entrée de Sonnet 5 à 3 $/MTok, l’économie par modification est d’environ 39,7 cents
- On ne sait pas encore si les économies s’accumulent aussi lors du débogage, de fonctionnalités plus complexes ou d’un refactoring à l’échelle de toute la base de code, ni combien coûte le refactoring lui-même
- Il reste aussi incertain qu’un refactoring puisse réduire les tokens de sortie ; dans cette modification représentative simple, le bruit de la génération de code non déterministe a masqué les différences dues aux changements de structure
Refactoring mené avec Claude
- Claude n’a pas su choisir par lui-même les refactorings à appliquer en observant le code ; les résultats correspondaient en pratique aux tâches explicitement indiquées dans le prompt
- Le harnais de développement comportait une étape explicite de refactoring, mais Claude ne l’a pas utilisée pour améliorer le fichier de 17 155 lignes
- Lors de la planification, Claude Code a identifié l’extraction de fonctions comme première étape, tandis que Claude.ai a repéré jusqu’à l’extraction complète d’une classe client
- Pour les changements mécaniques, des scripts Python utilisant
grepetsedont été employés, mais ces scripts se sont souvent emmêlés à cause de l’indentation - La séparation des fichiers du store, qui s’est avérée la plus précieuse, a été omise lors de la première tentative et réappliquée dans une étape ultérieure ; c’est pourquoi le nombre d’étapes mesuré ne correspond pas aux étapes du plan en annexe
- L’ensemble de l’expérience a pris environ 8 heures et s’est déroulé pour l’essentiel sans supervision
- Une intervention a eu lieu après 6 h 40 pour corriger l’étape manquante
- Le fort ralentissement des tests venait davantage d’un cache temporaire de build Cargo devenu trop volumineux que du Wi-Fi lent de l’hôtel
Prompt de modification représentative
- Chaque sous-agent ne recevait que la base de code et la documentation d’architecture, et implémentait le même trait public asynchrone
ItemWatchStore - Le trait comprenait les trois méthodes suivantes
watch_item(&self, item_id: &str, user_id: &str) -> Result<()>unwatch_item(&self, item_id: &str, user_id: &str) -> Result<()>watched_items_for_user(&self, user_id: &str) -> Result<Vec<String>>
- Les informations de watch étaient stockées dans la collection Firestore
item_watchesavec les champsitemId,userIdetcreatedAt - Le code devait renvoyer un
Vec<String>d’ID d’items sans structure d’enregistrement Rust séparée - Un champ en mémoire
Vec<(String, String)>devait être ajouté àFakeStore, et l’implémentation deFirestoreStoredevait réutiliser le motif HTTP existant - À la fin de la réponse, il devait produire en JSON les fichiers lus, le nombre de caractères lus et le nombre de caractères de la réponse, avec consigne de ne pas committer le code
Plan de refactoring appliqué
-
Étape 1 — extraction de la classe
FirestoreClient- Séparer les responsabilités d’orchestration des requêtes de domaine et de transport HTTP vers Firestore
- Déplacer
reqwest::Client,project_id,MetadataAuth, ainsi que la gestion des URL et des en-têtes d’authentification vers une nouvelle structure - Le plan prévoyait de retirer environ 1 200 lignes de l’implémentation de
FirestoreStoreet d’ajouter environ 120 lignes au client
-
Étape 2 — extraction des fonctions
extract_doc_idetnew_link- Mutualiser l’extraction d’ID dans 20 parseurs de documents et la création de
Linkrépétée 62 fois - Économie attendue d’environ 500 lignes
- Mutualiser l’extraction d’ID dans 20 parseurs de documents et la création de
-
Étape 3 — extraction de fonctions pour le pipeline de requêtes de liens
- Mutualiser les motifs de collecte de résultats de requêtes présents à environ 15 endroits et de recherche d’un ID cible unique présents à environ 8 endroits
- Économie attendue d’environ 200 lignes
-
Étape 4 — extraction de fonctions de conditions de liens dans
FakeStoreInner- Séparer en deux méthodes les variantes répétées de
inner.links.iter()présentes dans environ 15 méthodes - Économie attendue d’environ 120 lignes
- Séparer en deux méthodes les variantes répétées de
-
Étape 5 — introduction de fonctions de création de valeurs Firestore
- Remplacer les expressions
json!répétées plus de 128 fois pour les chaînes, timestamps, etc., par quatre appels de fonctions - Transformer des macros multilignes en appels sur une ligne, avec une économie attendue d’environ 80 lignes
- Remplacer les expressions
-
Étape 6 — extraction de
FieldsBuilder- Unifier dans un builder les motifs de création de maps de champs utilisés par environ 20 encodeurs
- Réduire des encodeurs d’environ 40 lignes à environ 12 lignes, pour une économie totale attendue de 500 à 600 lignes
-
Étape 7 — séparation de
queries.rs- Déplacer 32 constantes
LinkQueryet les types associés vers un module séparé - Réduire
mod.rsd’environ 800 lignes sans modifier les sites d’appel existants
- Déplacer 32 constantes
-
Étape 8 — séparation de
traits.rs- Déplacer 17 traits publics et les types d’erreurs associés, puis les réexporter
- Réduire
mod.rsd’environ 1 900 lignes, même si le nouveau fichier atteint aussi environ 1 900 lignes
-
Étape 9 — séparation de
traits/par domaine- Diviser les traits entre
planning.rs,content.rs,people.rsetsystem.rs - Limiter la taille de chaque fichier à environ 300 à 650 lignes sans changer les définitions ni les sites d’appel
- Diviser les traits entre
-
Étape 10 — séparation de
codec.rs- Déplacer les encodeurs/décodeurs de documents, les parseurs,
FieldsBuilderet les fonctions de création de valeurs - Après l’étape 6, obtenir un module d’environ 400 à 500 lignes et réduire
mod.rsd’environ 500 lignes
- Déplacer les encodeurs/décodeurs de documents, les parseurs,
-
Étape 11 — séparation de
fake_store.rs- Déplacer
FakeStore,FakeStoreInneret 18 implémentations de traits - Réduire
mod.rsd’environ 4 700 lignes
- Déplacer
-
Étape 12 — séparation de l’implémentation de
FirestoreStore- Conserver dans
store/mod.rsla structure, le constructeur,FirestoreClientetMetadataAuth, et répartir les implémentations de traits dans des fichiers par domaine - Transformer un fichier d’environ 10 000 lignes en 10 fichiers de 120 à 650 lignes chacun, et faire de
mod.rsun fichier de réexportation d’environ 100 lignes
- Conserver dans
-
Étape 13 — colocalisation des tests avec les modules ciblés
- Déplacer le code de test sous chaque fichier d’implémentation sans le modifier
- Réduire
mod.rsd’environ 2 000 lignes, en ajoutant à chaque fichier les tests associés, soit 200 à 700 lignes
Limites et expériences ultérieures
- Les tokens consacrés à l’élaboration et à l’exécution du plan de refactoring n’ont pas été comptés séparément, ce qui empêche de calculer précisément le coût d’investissement du refactoring
- La borne supérieure basée sur l’utilisation totale pendant cette période est de 5 millions de tokens, mais elle inclut deux élaborations de plan, la conception de l’expérience et de la modification représentative, ainsi que d’autres travaux
- Le sujet de l’expérience est encore en phase greenfield et correspond à une unique grande application construite et maintenue par un seul développeur ; les résultats ne sont donc pas généralisables
- Les travaux suivants devraient mesurer précisément les tokens de refactoring, tester des modifications plus complexes, des refactorings plus larges, un refactoring continu et la valeur relative de différentes approches
- Cette expérience constitue un point de départ pour mesurer à la fois la valeur temporelle et financière du refactoring et son propre coût
1 commentaires
Réactions sur Hacker News
Il est amusant de voir les bonnes pratiques de développement que la plupart des entreprises IT ignoraient être réinventées en bonnes pratiques pour l’IA
Avant, quand on disait de garder la documentation dans le code, de ne pas simplement jeter des tickets Jira mais de fournir le contexte global du projet, et de refactoriser pour la productivité à long terme, on trouvait ça ennuyeux
Maintenant, si on dit de mettre cette même information dans le code et dans
CLAUDE.md, de ne pas tout contrôler dans le détail via des prompts, et de refactoriser pour la productivité de l’IA, cela suscite de l’intérêtLes humains peuvent connaître la bonne méthode mais être occupés ou distraits, alors que les agents ne se lassent pas des tâches répétitives ; des procédures dont l’efficacité a été prouvée chez les humains mais qui étaient difficiles à appliquer régulièrement deviennent donc réalistes
À partir d’une spécification commune, des agents distincts rédigent l’implémentation et les tests, puis un agent d’audit les vérifie afin qu’ils ne soient pas contaminés par les résultats des uns et des autres ; c’est une application large et cohérente à l’IA de la méthode Cleanroom qu’IBM avait développée pour les humains dans les années 1980
Il ne s’agit pas d’emballer de vieilles pratiques pour les faire passer pour neuves à l’ère de l’IA, mais de montrer, preuves à l’appui, que des bonnes pratiques vieilles de plus de vingt ans restent valables
Les agents doivent réapprendre le contexte à chaque session, ce qui augmente fortement la valeur des bonnes pratiques et en rend les effets immédiatement visibles
Cela dit, pouvoir lancer la CLI 100 fois en une heure pour tester l’ergonomie d’un nouveau flag reste appréciable
L’IA, en revanche, fonctionne très mal voire pas du tout sans ces bases, si bien que des pratiques d’ingénierie saines deviennent non plus une amélioration à long terme mais une condition préalable indispensable
Même si l’effet net réel est nul, introduire l’IA dans le flux de travail reste utile parce que cela donne un prétexte pour adopter de vraies bonnes pratiques de développement
J’apprécie que cet article critique l’IA de façon concrète et quantitative, à partir de la manière dont les outils sont réellement utilisés
C’est bien plus utile que les textes qui parlent vaguement des risques sociétaux sans cas d’usage réels : ici, on montre par des mesures ce que l’IA ne sait pas faire
Pour la même raison, le rapport qui a interrogé des membres de Boko Haram pour étudier comment l’IA avait été utilisée dans le terrorisme m’a aussi marqué
J’aime vraiment le refactoring fait directement, sans IA
Il n’y a pas de changement visible, mais il y a quelque chose de satisfaisant à rendre un site web, dont les résultats ne se verront pas tout de suite, beaucoup plus facile à faire évoluer à l’avenir
Repérer qu’un problème déjà résolu par des patterns établis est à nouveau traité par un ancien contournement étrange, puis le ramener vers les bonnes pratiques sans créer de nouvelle dette technique, a quelque chose de plaisant, comme un puzzle
J’ai même bricolé moi-même tout un tas de choses, jusqu’à l’authentification, pour apprendre les mécanismes internes à la dure, et cela m’a aussi laissé de quoi me divertir en refactoring pour les dix prochaines années
J’ai compris concrètement ce que signifie l’idée que la base de code forme un système, et j’ai commencé à la voir à un niveau plus élevé, comme une organisation continue ou un réseau que l’on peut tirer et pousser
Le fait que l’IA puisse court-circuiter cet apprentissage met en lumière le problème des développeurs juniors. Pour acquérir cette intuition, il n’y a pas d’autre choix que de creuser soi-même en profondeur, et même si Naur l’avait déjà averti il y a quarante ans, cette leçon continue d’être oubliée
J’estime que l’intervention humaine est indispensable quand un agent fait du refactoring.
Un modèle génératif peut se concentrer sur le travail initial et un modèle de revue peut repérer ce qui lui a échappé, mais il est permis de douter qu’il comprenne réellement l’objectif global du projet et la manière dont le code s’articule pour juger des redondances ou d’une structure plus élégante.
Confier le refactoring à un agent de code, c’est un peu comme demander à un chirurgien traumatologue d’améliorer des performances sportives ; pour bien le faire, il faut une vision holistique.
Diviser un gros fichier en plusieurs fichiers ne reste qu’un refactoring superficiel. Sans théorie sur ce qui doit rester ensemble et ce qu’il faut extraire en fonctions utilitaires, on est plus proche d’une décomposition artificielle que d’une vraie factorisation.
Les agents construisent parfois des systèmes qui réenregistrent et recalculent des valeurs déjà récupérées via l’API, alors qu’un humain peut parcourir l’ensemble du projet et repérer précisément que les données nécessaires existent déjà dans une clé donnée du JSON.
functools.partialau lieu de classes de données.L’idée que les frontières entre fichiers représentent celles de sous-systèmes logiques, facilitent le raisonnement, et que le contenu des autres fichiers est traité par défaut comme opaque, est également très présente dans les données d’entraînement.
Je pense que les avantages de cette structure ne relèvent pas seulement de traits accidentels de la cognition humaine, mais ont aussi une dimension objective.
L’expérience en refactoring, la manière d’aborder le code d’autrui, et le fait de pouvoir expliquer les intentions passées et présentes en tant que concepteur d’origine ont aidé.
Le langage utilisé était peu courant, avec peu de vulnérabilités de dépendances et facile à manipuler pour les LLM ; une fois le biais JavaScript et Python éliminé, la vitesse d’exécution a fortement augmenté.
C’était un projet JSR-223 où l’on écrivait des scripts dans plusieurs langages populaires, tout en les exécutant tous sur la JVM selon les exigences de l’environnement : https://en.wikipedia.org/wiki/Scripting_for_the_Java_Platform
Sur ce marché de l’emploi, il faut utiliser des agents de code fondés sur les modèles de pointe les plus récents et connaître précisément leurs capacités et leurs limites ; donner l’avis contraire en entretien peut devenir un motif d’élimination.
Un contexte concis ne réduit pas seulement la consommation de tokens, il améliore aussi le raisonnement et permet de traiter intelligemment davantage de couches dans un même contexte.
Le refactoring vers de bonnes abstractions produit un logiciel qui généralise mieux, avec plus de chances d’être correct non seulement sur les cas testés, mais aussi sur des cas interpolés et extrapolés.
Il existe des fondements en théorie de l’information et en mathématiques bayésiennes à l’appui, et le fait qu’un logiciel plus efficace économiquement et énergétiquement devienne aussi plus exact ressemble à une heureuse coïncidence.
L’essentiel est de réduire l’entropie du code.
Les LLM infèrent déjà assez bien le sens avec peu de contexte.
Il est intéressant de voir des données présentées, et cela correspond à mon ressenti : les LLM tirent un grand bénéfice d’un code bien séparé, mais ne sont pas très doués pour en produire eux-mêmes.
La plupart des développeurs humains sont probablement dans le même cas.
Globalement, le gain apporté par l’IA est important, mais il faut aussi du temps de nettoyage, et je pense toujours qu’il faut lire chaque ligne.
J’ai reporté une partie des revues pour ne pas bloquer l’avancement d’autres équipes, et je rembourse maintenant une dette technique plus lourde que d’habitude, mais débloquer le goulet d’étranglement en premier valait le coup.
L’IA a rendu la dette technique plus facile à contracter dans tous les sens du terme et, si elle est bien guidée, elle se débrouille aussi plutôt bien pour la résorber. Les résultats varient cependant selon les personnes : https://news.ycombinator.com/item?id=49035455
Montrer, à travers des exemples de code bien structuré ou des dépôts open source, ce qu’il faut faire et ne pas faire aide énormément.
La majeure partie des bénéfices économiques du refactoring vient moins de l’économie de tokens que d’une meilleure compréhension humaine.
Cela permet de résoudre plus vite les alertes de production à 3 heures du matin, de réduire les bugs qui atteignent l’environnement de production, et de livrer plus vite que les concurrents.
Surtout, comprendre le système rend les gens plus enclins à assumer responsabilités et ownership, ce qui les pousse à corriger les problèmes plus rapidement et à s’investir davantage dans les améliorations.
Le point clé est que le refactoring réduit la consommation de tokens, et il est appréciable que l’effet soit quantifié plutôt que discuté de façon abstraite.
Mais Fowler dit dans Refactoring que la condition préalable essentielle au refactoring, ce sont des tests solides, et je pense que c’est là le vrai bénéfice, indépendamment de l’IA.
De bons tests empêchent les régressions produites par des humains comme par des robots, et laissent dans le code une spécification lisible par les deux : https://www.oreilly.com/library/view/refactoring-improving-the/9780134757681/
Si l’on calcule le prix de Sonnet 5 à 3 dollars par MTok, le montant économisé sur les changements futurs touchant la couche d’accès aux données est de 39,7 centimes.
Si l’on tient compte des baisses de prix d’OpenAI, des modèles ouverts et de la baisse tendancielle du prix des tokens à long terme, cela pourrait ne pas compenser le coût d’un développeur senior à environ 100 dollars de l’heure pour guider le refactoring.
Le code produit par des agents est devenu un énorme bloc que seuls les agents peuvent lire et comprendre ; dans ce contexte, la réalité compte plus que de savoir s’il s’agit d’une fonctionnalité, d’un bug ou d’une propriété émergente.
Pour gérer le code généré par des outils d’IA, on devient de nouveau dépendant des outils d’IA.
Cela dit, les humains ont eux aussi déjà produit des fichiers atrocement volumineux et des monorepos, et grâce aux LLM, les éditer et les refactorer devient enfin gérable.
Quand une base de code est devenue trop grande et trop désordonnée pour être comprise par des humains, les LLM peuvent aussi nous sauver ; personnellement, je déteste les fichiers géants, mais il est amer de se dire que les principes de rangement à la Fowler ne sont peut-être plus si importants.
Même un employé moyen, ou parfois compétent, peut soudain exécuter à toute vitesse des choses qu’il ne pouvait pas faire auparavant à cause des procédures de l’entreprise, et ainsi devenir au contraire un mauvais employé.
Si un agent crée un fichier ou une fonction gigantesque, il suffit de lui dire de ne pas le faire, et il obéit.
Je pense que le refactoring est l’un des meilleurs signes d’une équipe de développement en bonne santé.
Le refactoring a ses propres bénéfices, mais sa valeur se voit mal du point de vue du responsable produit ou d’un tableau de suivi des fonctionnalités.
Si une équipe refactore pour la santé globale du logiciel, cela signifie que les développeurs peuvent proposer sereinement des idées en faveur d’un bon logiciel, et que ces propositions sont prises au sérieux.
La dégradation du logiciel est à son pire quand l’équipe n’a ni la motivation ni l’autorité nécessaires pour concrétiser une vision de logiciel de haute qualité ; à l’inverse, lorsqu’une équipe peut suivre son jugement sur ce qu’est l’excellence, c’est généralement un bon signe.
Bien sûr, il existe aussi des excès, comme tout réécrire entièrement en passant de Ruby à Node, puis à Rust, avant de revenir à une technologie plus compatible avec les agents, mais dans l’environnement des entreprises, il est bien plus courant de voir des équipes qui ont le sentiment de ne pas avoir l’autorisation d’améliorer les choses.