
En bref
|
En tant qu’ingénieurs seniors et architectes principaux, la plupart d’entre nous avons passé des années à réfléchir à la santé à long terme des systèmes. On tient compte des objectifs commerciaux et de la stratégie de l’entreprise, de l’accumulation de la dette technique et du risque opérationnel. Pour nous, la question n’est pas de savoir si le code fonctionne aujourd’hui, mais si l’ingénieur qui en héritera dans trois ans sera capable de comprendre ce qu’il essayait de faire et pourquoi. C’est ce qui rend une base de code maintenable, et pas seulement fonctionnelle.
Les assistants de codage basés sur l’IA sont en train de saper ça. Une grande partie du débat actuel se concentre sur la rapidité et sur le fait de permettre aux développeurs d’en faire plus en moins de temps. Mais, à mesure que de nouveaux outils s’ajoutent à l’ensemble, ce qu’on perd, c’est la compréhension de l’intention du développeur. Même si, techniquement, on avance plus vite, on génère une nouvelle catégorie de dette technique, mais ça ne ressemble pas à de la dette technique. Ça ressemble à du code propre, bien structuré et qui passe les tests, mais sans aucun raisonnement humain derrière.
Point clé : la génération automatisée de code masque la perte de l’intention du développeur. Les dépôts de code « propres » accumulent du code hérité deux fois plus vite qu’auparavant.
En apparence, la boucle de développement locale avec l’IA semble productive. Un développeur ouvre son éditeur, sélectionne un bloc de code et demande au modèle : « Refactorise ce gestionnaire d’authentification pour prendre en charge les échanges de jetons multi-locataires. » Le modèle renvoie un diff de 200 lignes. Le développeur le survole, lance un test local, effectue un commit avec un message du genre « refactorisation de l’authentification pour le multi-locataire », puis pousse vers la branche.
Sur le papier, la tâche est terminée. En pratique, le dépôt vient d’hériter d’un fardeau.
Le contrôle de version a enregistré le « quoi » : le diff brut des lignes nouvellement générées. Il n’a rien capturé du « pourquoi ». La requête, le contexte à partir duquel le modèle travaillait, les chemins logiques qu’il a évalués puis écartés, les hypothèses structurelles intégrées dans le résultat : tout ça s’est évaporé à la fermeture de la session de l’éditeur.
Imagine ce même gestionnaire d’authentification, six mois plus tard, qui plante à 2 heures du matin à cause d’une configuration de jeton dans un cas limite que personne n’avait prévu. Un ingénieur senior lance la commande `git blame`. Il ne trouve pas de décision de conception. À la place, il tombe sur un artefact, résultant d’un choix d’agent. Il n’y a pas de message de commit qui explique le raisonnement, pas de commentaire de PR qui rende compte des compromis, aucun moyen de reconstituer ce que le modèle cherchait à optimiser quand il a choisi cette structure particulière. Le contexte a disparu parce qu’il n’a jamais été consigné nulle part qui ait survécu à la session qui l’a produit.
On a toujours accumulé de la dette technique. Mais aujourd’hui, on l’accumule plus vite, et sous une forme plus difficile à rembourser, à cause de l’absence de contexte.
Point clé : quand un ingénieur révise et fusionne un diff qu’il ne peut pas retracer, il devient responsable de décisions qu’il n’a pas prises.
Git a été conçu sur un principe fondamental : le nom associé à un commit représente l’esprit qui a planifié la modification. Cette relation s’est discrètement effritée.
Les développeurs qui utilisent des outils d’IA locaux sont passés du statut d’auteurs à celui d’éditeurs de texte généré par une machine. Ce changement a des conséquences qui ne sont pas réparties de manière équitable. Le développeur qui a donné les instructions au modèle passe à autre chose. C’est le réviseur qui se retrouve avec le diff sur les bras.
On demande désormais à un ingénieur senior qui examine une pull request complexe comportant plusieurs fichiers de valider des choix architecturaux (par exemple, un modèle de verrouillage de base de données spécifique, une approche particulière des appels asynchrones imbriqués) sans savoir si ces choix étaient des décisions intentionnelles ou la meilleure supposition du modèle, compte tenu d’une fenêtre contextuelle que le réviseur n’a jamais vue. Le modèle n’est pas disponible pour répondre aux questions. Le développeur qui a lancé la requête ne comprend peut-être pas non plus entièrement pourquoi le résultat se présente ainsi.
Deux conséquences en découlent. La première est un problème de qualité de la révision : sous la pression du backlog, la réponse honnête à la question « tu comprends pourquoi ce code est structuré comme ça ? » est de plus en plus souvent « non », mais la fusion a lieu quand même. La seconde est un problème de responsabilité dont la plupart des équipes n’ont pas encore pleinement pris la mesure : la personne qui clique sur « fusionner » est opérationnellement responsable des conséquences d’un code qu’elle n’a pas conçu et dont elle ne peut pas entièrement retracer l’origine.
Point clé : la solution, ce n’est pas de restreindre l’utilisation de l’IA. C’est de capturer le contexte que l’exécution de l’IA ignore actuellement.
On est tenté de considérer ça comme un problème d’outils qu’on peut résoudre avec des outils : une meilleure discipline dans les messages de commit, des modèles de PR obligatoires, des niveaux de révision du code par l’IA. Ces mesures aident un peu, mais elles ne résolvent pas le problème sous-jacent.
Le problème sous-jacent, c’est que le raisonnement de l’IA se déroule dans un environnement qui ne produit aucune trace durable. Un modèle qui tourne dans l’éditeur local d’un développeur traite le contexte, prend des décisions et génère un résultat, puis le contexte disparaît. Ce qui est enregistré dans le contrôle de version, c’est le résultat. Tout ce qui y a mené a disparu.
Les équipes qui commencent à s’attaquer sérieusement à ce problème repensent l’étape du processus où l’IA intervient, et pas seulement son mode de fonctionnement. Quand le contexte à partir duquel un agent travaille, les décisions qu’il prend et la révision humaine de ces décisions sont tous consignés dans le même enregistrement que la modification du code elle-même, tu disposes d’un élément que tu peux réellement auditer. Six mois plus tard, quand quelque chose ne fonctionne plus, le raisonnement est toujours là.
C’est un type d’exigence d’infrastructure différent de celui auquel la plupart des équipes sont habituées. Mais c’est la bonne façon d’aborder le problème. On n’a pas un problème de qualité du code. On a un problème de préservation du contexte. Et pour le résoudre, il faut considérer le raisonnement derrière une modification de code comme faisant partie intégrante de l’artefact d’ingénierie, et non comme un sous-produit qu’on jette à la fin de la session.
C’est le problème qu’on cherche à résoudre avec Upsun Dispatch™ : capturer l’intégralité de la chaîne de contexte, de raisonnement et de validation humaine comme partie intégrante du dossier d’ingénierie lui-même, et non comme quelque chose recréé après coup.
C’est quoi exactement, le « dark code » ?
C’est du code qui se compile, passe les revues et arrive en production sans qu’il y ait de trace vérifiable expliquant pourquoi il a été écrit ainsi. Les choix architecturaux sont invisibles pour tout le monde, sauf pour le développeur qui les a faits, et ce développeur a peut-être quitté l’équipe depuis longtemps.
Pourquoi un bon message de commit ne suffit-il pas à éviter le « dark code » ?
Un message de commit reflète ce qu’un humain a choisi de résumer. Il ne rend pas compte des invites, du contexte ni de la chaîne de raisonnement qui ont conduit une IA à prendre des décisions structurelles spécifiques. Un développeur qui écrit « refactorisation de l’authentification pour le multi-tenant » résume son interprétation du résultat, il ne documente pas le processus qui l’a produit. Ce sont deux choses très différentes.
La traçabilité ne ralentit-elle pas les développeurs ?
Seulement si tu la mets mal en place. Le but n’est pas de faire en sorte que les développeurs documentent manuellement chaque interaction avec l’IA. C’est de capturer ce contexte automatiquement, au moment même où l’IA est en train de fonctionner, sans alourdir le processus du développeur.
Quel est le lien entre le « dark code » et la conformité ?
Des normes comme l’ISO 27001 exigent que tu prouves pourquoi une modification a été apportée, qui l’a autorisée et comment elle a été vérifiée. Un code généré localement par un assistant IA, sans trace partagée du contexte ni de l’autorisation, est vraiment difficile à justifier lors d’un audit. C’est un risque que la plupart des équipes n’ont pas encore pleinement cerné.