Jardiner son codebase.
Les agents écrivent désormais une grande partie de mon code. Que me reste-t-il à faire ? Entretenir le jardin où il pousse, et arracher les mauvaises herbes.
Par Nizar Oukhchi, Architecte solution
Publié le · 8 min de lecture
Pendant la plus grande partie de ma carrière, mon travail consistait à écrire du code.
Ce n’est plus vraiment le cas. Dans les dépôts sur lesquels je travaille aujourd’hui, une grande partie du code est écrite par des agents. Je le relis, je l’oriente, je le réécris parfois. Mais je tape beaucoup moins de lignes qu’avant.
Alors, en quoi consiste mon travail maintenant ?
J’y ai beaucoup réfléchi, et la meilleure réponse que j’ai trouvée est un peu inattendue. Je crois que mon travail, c’est le jardinage.
Le code pousse. Le jardinier entretient.
Un jardinier ne fait pas pousser les plantes. Ça, ça se fait tout seul.
Ce que fait un jardinier, c’est préparer le sol, décider de ce qui va où, installer un tuteur, arroser régulièrement et arracher les mauvaises herbes avant qu’elles ne prennent le dessus. Le talent n’est pas dans la croissance. Il est dans les conditions.
Les agents de code sont des cultivateurs très productifs. Confiez-leur une tâche et ils produisent du code qui fonctionne, vite. Mais il y a un piège : un agent fait pousser ce que l’environnement favorise.
Dans un codebase aux conventions claires, au retour rapide et aux bons exemples, un agent écrit du code qui s’intègre.
Dans un codebase rempli de motifs incohérents, de tests lents et de couplages cachés, il écrit aussi du code qui s’intègre. Il reproduit fidèlement le désordre, à un rythme qu’aucune équipe humaine ne pourrait suivre.
C’est ça, le changement. Mon rôle principal n’est plus d’écrire chaque morceau de code. C’est de construire le jardin qui permet au code de pousser sainement, et d’arracher les mauvaises herbes avant qu’elles ne se propagent.
Pourquoi le travail ingrat compte davantage
Par « travail de plateforme », j’entends tout ce qui rend un codebase propre, rapide et facile à maintenir. Une architecture cohérente. Une suite de tests fiable. Un build rapide. Des conventions homogènes, et l’outillage qui va avec.
Pendant des années, c’était le travail qu’on repoussait dès qu’une échéance approchait. Je l’ai fait moi-même plus souvent que je ne voudrais l’admettre.
Avec des agents dans la boucle, je ne pense pas qu’on puisse encore se le permettre. Voici pourquoi.
Les agents imitent. Un agent apprend le fonctionnement de votre codebase en le lisant. S’il existe trois façons d’appeler une API, il en choisira une au hasard. Ou en inventera une quatrième. Chaque exemple propre est un modèle, et chaque raccourci aussi.
Les agents apprennent du retour, pas de la mémoire. Comment un agent sait-il que son changement est correct ? Les types passent, les tests passent, la CI est verte. Si ce retour est lent, instable ou absent, l’agent devine. Ou tourne en rond. Ou crie victoire trop tôt.
Les agents bloquent là où les humains improvisent. Un développeur expérimenté contourne la dette technique avec un savoir qui vit dans sa tête. « Ne touche pas à ce module. » « Ce test échoue toujours le lundi. » Un agent n’a rien de tout ça. Une mauvaise architecture ne fait pas que le ralentir. Elle le bloque, ou l’envoie avec assurance dans la mauvaise direction.
Mis bout à bout, cela mène à une conclusion inconfortable.
La qualité de votre plateforme fixe désormais le plafond de la qualité de tout ce que produisent vos agents.
Produit et plateforme, chez vidIQ
Je ne suis pas arrivé à cette idée grâce aux agents. J’y suis arrivé par une tension bien plus ancienne.
Chez vidIQ, j’ai travaillé des deux côtés de la ligne. J’ai livré des fonctionnalités visibles par les utilisateurs, et j’ai travaillé sur la plateforme qui les porte. Au début, les deux semblaient en concurrence. Chaque semaine passée sur le build, les tests ou l’architecture ressemblait à une semaine de fonctionnalités que je n’avais pas livrées.
Est-ce que je perdais mon temps ?
Pas vraiment. Mais je voyais les choses de travers.
Avec le temps, j’ai appris à les voir comme un seul système. La fonctionnalité est la plante. La plateforme est le sol. (J’espère que vous me pardonnerez de pousser cette métaphore un peu loin. Je vais continuer.)
Une fonctionnalité livrée dans un sol pauvre coûte plus cher à faire évoluer, casse plus souvent et ralentit la suivante. Et un travail de plateforme mené sans le produit en tête finit par polir des choses dont personne n’a besoin.
L’équilibre qui a fonctionné pour moi était simple :
- Chaque fonctionnalité doit laisser le code un peu meilleur qu’elle ne l’a trouvé.
- La plateforme a droit à un temps dédié et protégé, pas à un « sprint de nettoyage » qui n’arrive jamais.
Les agents accentuent encore ce déséquilibre. Quand produire une fonctionnalité coûte moins cher, le goulot d’étranglement se déplace vers tout ce qui l’entoure. À quelle vitesse peut-on la vérifier ? Avec quelle sécurité peut-on la modifier ? Avec quelle clarté le codebase montre-t-il à l’agent ce qui est bien fait ?
Tout cela, c’est du travail de plateforme.
Arracher les mauvaises herbes
Tout cela peut sembler un peu abstrait. Voici donc deux mauvaises herbes concrètes que j’ai arrachées.
Mauvaise herbe nº 1 : des tests qui ne servaient à rien
Les agents écrivent volontiers des tests. Et ils les écrivent à l’image de ceux qu’ils trouvent.
Avec le temps, nous avions accumulé beaucoup de tests unitaires qui vérifiaient des détails d’implémentation, simulaient presque tout et se dupliquaient entre eux. Ils ralentissaient la suite. Ils cassaient à chaque refactorisation sans attraper de vrais bugs.
Pire encore, ils apprenaient aux agents que c’est à ça que ressemble un test.
Alors nous les avons supprimés. En masse.
Nous avons gardé les tests qui protégeaient un vrai comportement aux frontières qui comptent, et ajouté quelques tests là où la couverture importait vraiment. La suite est devenue plus rapide, et quand elle échouait, l’échec voulait de nouveau dire quelque chose.
Puis il s’est passé quelque chose que je n’avais pas vraiment anticipé. Les nouveaux tests des agents se sont améliorés aussi. Pas parce que les agents avaient changé, mais parce que les exemples dont ils s’inspiraient avaient changé.
Parfois, le changement le plus productif consiste à supprimer du code.
Mauvaise herbe nº 2 : des agents aveugles à la CI
La deuxième mauvaise herbe était plus discrète.
Un agent faisait un changement, lançait quelques contrôles en local et annonçait que c’était terminé. Quelques minutes plus tard, la CI échouait sur quelque chose qu’il n’avait jamais vu. Quelqu’un devait alors s’en apercevoir, lire les journaux et renvoyer l’agent au travail.
L’agent était-il négligent ?
Pas vraiment. Il ne voyait simplement pas. Il terminait le travail qu’il pouvait vérifier, et s’arrêtait là. Les humains (moi compris) font exactement la même chose.
Alors nous lui avons donné des yeux. Nous avons ajouté un outillage qui permet à l’agent de suivre sa propre exécution de CI : voir quels jobs ont échoué, lire les journaux d’erreur et corriger le problème avant de déclarer le travail fini. Nous avons aussi rendu visibles les jobs instables, pour que l’équipe les corrige au lieu de cliquer sur « relancer ».
La définition de « terminé » est passée de « j’ai écrit le code » à « le pipeline est vert ». Toute une catégorie d’allers-retours a tout simplement disparu.
Voici la boucle à laquelle nous sommes arrivés :
- IngénieurFixer les conventionsConsignes écrites, exemples de référence, frontières d’architecture.
- AgentL’agent implémente le changement
- ContrôleContrôles locaux rapidesTypes, lint et tests ciblés, en quelques secondes.
- ContrôleLa CI tourne, et l’agent la surveilleIl lit les journaux d’échec et corrige avant de se déclarer terminé.
- IngénieurRevue du changementOn juge les choix, pas seulement le résultat.
- PlateformeDésherber et améliorer la plateformeSupprimer les tests inutiles et les doublons, mettre à jour les conventions.
La liste du jardinier
Si vous voulez que les agents écrivent du code que vous aurez plaisir à maintenir, commencez par le terrain sur lequel ils travaillent.
- Écrivez vos conventions là où les agents les lisent. Un fichier de consignes à la racine du dépôt, avec des liens vers des exemples de référence.
- Gardez une seule façon de faire chaque chose. Quand vous trouvez deux motifs pour le même besoin, choisissez-en un et supprimez l’autre.
- Rendez le retour rapide et fiable. Supprimez les tests qui ne testent que les simulations, corrigez les tests instables, gardez les contrôles locaux à quelques secondes.
- Bouclez la boucle avec la CI. Un agent qui voit son propre pipeline cesse de vous rendre du travail cassé.
- Gardez des modules petits et des frontières explicites, pour qu’un changement se comprenne sans lire tout le système.
- Quand vous voyez une mauvaise herbe, traitez la racine. Corriger une mauvaise occurrence en revue aide une fois. Corriger la convention ou l’exemple dont elle vient aide tous les changements suivants.
Plus amusant, pas moins
Notre secteur change plus vite qu’à aucun autre moment dont je me souvienne. Il est facile d’y voir une menace.
Mon expérience a été inverse.
Confier les parties répétitives aux agents laisse plus de place à ce qui m’a fait aimer ce métier au départ : la conception, le jugement, et la construction de systèmes qui tiennent.
Honnêtement, c’est plus amusant que ça ne l’a jamais été.
Il faut juste prendre soin du jardin.
Si votre équipe adopte des agents de code et que le codebase résiste, c’est précisément le travail de plateforme que couvrent nos services d’ingénierie logicielle. Dites-moi où ça coince.