1 points par GN⁺ 2 시간 전 | 1 commentaires | Partager sur WhatsApp
  • 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
  • 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 grep et sed ont é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_watches avec les champs itemId, userId et createdAt
  • 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 de FirestoreStore devait 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 FirestoreStore et d’ajouter environ 120 lignes au client
  • Étape 2 — extraction des fonctions extract_doc_id et new_link

    • Mutualiser l’extraction d’ID dans 20 parseurs de documents et la création de Link répétée 62 fois
    • Économie attendue d’environ 500 lignes
  • É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
  • É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
  • É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 LinkQuery et les types associés vers un module séparé
    • Réduire mod.rs d’environ 800 lignes sans modifier les sites d’appel existants
  • É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.rs d’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.rs et system.rs
    • Limiter la taille de chaque fichier à environ 300 à 650 lignes sans changer les définitions ni les sites d’appel
  • Étape 10 — séparation de codec.rs

    • Déplacer les encodeurs/décodeurs de documents, les parseurs, FieldsBuilder et les fonctions de création de valeurs
    • Après l’étape 6, obtenir un module d’environ 400 à 500 lignes et réduire mod.rs d’environ 500 lignes
  • Étape 11 — séparation de fake_store.rs

    • Déplacer FakeStore, FakeStoreInner et 18 implémentations de traits
    • Réduire mod.rs d’environ 4 700 lignes
  • Étape 12 — séparation de l’implémentation de FirestoreStore

    • Conserver dans store/mod.rs la structure, le constructeur, FirestoreClient et MetadataAuth, 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.rs un fichier de réexportation d’environ 100 lignes
  • É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.rs d’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

 
GN⁺ 2 시간 전
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êt

    • Il est bien plus facile d’amener des agents IA à exécuter la même tâche de façon cohérente que des collègues humains
      Les 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
    • La personne liée à cet article est Martin Fowler, qui a écrit il y a plus de vingt ans le livre Refactoring et popularisé ce terme
      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
    • La grande différence entre avant et après l’IA, c’est que les humains ont une assez bonne capacité à gérer le contexte sur le long terme
      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
    • Grâce à la vague IA, il est enfin possible d’obtenir un budget pour les améliorations de l’expérience développeur que l’on voulait faire, mais le fait que la raison soit mauvaise laisse un goût amer
      Cela dit, pouvoir lancer la CLI 100 fois en une heure pour tester l’ergonomie d’un nouveau flag reste appréciable
    • Les humains arrivent d’une manière ou d’une autre à produire un résultat, même avec de vieux documents sur SharePoint, un contexte global saisi au vol en réunion et une faible priorité donnée au refactoring, même si la qualité et les délais en pâtissent
      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 lu Refactoring de Fowler en doutant que cela puisse servir pour du code scientifique ou de recherche, mais après l’avoir appliqué à titre expérimental à une structure de code qui ne me plaisait pas, mon point de vue a complètement changé
      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
    • C’est peut-être parce que cela procure une récompense dopaminergique, un peu comme regarder l’écran de défragmentation de Windows 98
    • Ce sentiment, c’est la fierté de l’artisan. Pour ceux qui comprennent, il n’y a rien à expliquer ; pour ceux qui ne comprennent pas, aucune explication ne suffira
    • Je me demande dans quelle mesure une suite de tests a été mise en place comme garde-fou pour éviter les régressions pendant le refactoring
    • J’aime le processus consistant à étudier divers patterns de refactoring et des cas réels d’application
  • 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.

    • Les LLM actuels exécutent pourtant assez bien des refactorings précis quand on leur donne des consignes concrètes sur une portion de code. Par exemple, ils peuvent gérer une demande complexe comme implémenter le pattern Command avec functools.partial au 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.
    • Avec un humain à côté pour expliquer la direction, un refactoring qui aurait pris plusieurs mois a été mené en grande partie en environ une semaine.
      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
    • Dire que les agents ne savent pas faire de refactoring est une opinion dépassée ; aujourd’hui, ils sont très performants.
      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.

    • Partout dans le monde et dans l’univers, une réduction d’entropie peut être vue comme le fait de construire quelque chose.
    • Si l’on abandonne la lisibilité humaine comme objectif et qu’on ne garde que la réduction de consommation de tokens comme fonction objectif, il est difficile de savoir où l’on aboutira.
      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.

    • Je budgétise séparément du temps de suppression de code bancal et je suis justement en train de faire ce travail dans la fenêtre d’à côté.
      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
    • J’observais le même résultat par défaut, mais en donnant une direction de refactoring plus précise, on pouvait produire un code mieux séparé.
      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/

    • L’article a été publié sur martinfowler.com, mais n’a pas été écrit par Martin ; l’auteur indiqué est Giles Edwards-Alexander, CTO de Thoughtworks.
    • Le vrai point essentiel est que l’économie n’est que de quelques dizaines de centimes.
      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.

    • Dire qu’un code d’agent ne peut être compris que par des agents n’est fondamentalement pas vrai ; si c’est l’impression que l’on a, c’est qu’on utilise les LLM de la mauvaise manière.
    • Le mauvais code a toujours existé, mais l’IA pose un nouveau problème en multipliant par 1 000 l’ampleur des dégâts d’un mauvais recrutement.
      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é.
    • Même avec une base de code écrite à 100 % par un LLM, je n’ai eu aucun problème à la lire ni à trouver l’endroit voulu ; ce n’était pas plus difficile que lorsqu’elle était écrite par moi-même.
    • Je n’ai jamais vu du code produit par un agent être pire que le pire code produit par des humains.
      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.