La mauvaise métrique

La plupart des discussions sur la qualité du code généré par AI se concentrent sur la correction au moment de la génération. Est-ce que la sortie compile ? Est-ce qu’elle passe les tests ? Est-ce qu’elle correspond à la spec ?

C’est le strict minimum. Cela ne vous dit rien sur le coût réel.

La vraie métrique, c’est la remplaçabilité : à quel coût pouvez-vous supprimer ce module et le réimplémenter derrière le même contract quand les besoins évoluent ?

Si la réponse est « trivialement », la vitesse de l’AI se cumule. Si la réponse est « il faut d’abord retracer six dépendances implicites », vous avez déjà perdu l’avantage de vitesse que vous pensiez acheter.

Pourquoi le code AI tend vers le couplage

Les grands modèles de langage optimisent la demande immédiate. Ils n’optimisent pas les changements futurs.

Quand vous promptez pour obtenir un flux de connexion, vous obtenez un flux de connexion qui fonctionne. Vous n’obtenez pas un flux de connexion derrière une interface d’auth qu’on peut faire passer de Firebase à Supabase puis à un service JWT personnalisé sans toucher à aucun écran qui le consomme.

Ce n’est pas un échec du modèle. C’est un échec de contexte. On n’a pas demandé au modèle d’optimiser la remplaçabilité, donc il ne l’a pas fait.

Résultat : le code généré par AI tend par défaut vers un couplage serré. Non pas parce que le modèle est mauvais, mais parce que l’isolation n’est jamais le chemin de moindre résistance pour un prédicteur de prochain token.

La remplaçabilité est une décision d’architecture

La remplaçabilité n’arrive pas par accident. C’est un choix structurel délibéré :

  • Chaque dépendance externe se trouve derrière une interface dont l’application est propriétaire.
  • Chaque module généré expose un contract, pas une implémentation.
  • Chaque capacité optionnelle est injectée, jamais importée directement.
  • Chaque décision de composition vit dans un seul composition root, pas éparpillée dans cinquante fichiers.

Ce n’est pas nouveau. C’est l’inversion de dépendances de base. Ce qui est nouveau, c’est que le code généré par AI rend la violation de ces principes presque sans effort et invisible jusqu’au moment où vous devez changer quelque chose.

L’effet composé

Quand chaque module est remplaçable :

  • Les mauvaises générations coûtent des minutes, pas des jours.
  • Les changements de fournisseur sont des échanges d’interface, pas des rewrites.
  • La vitesse de l’AI reste linéaire au fil des itérations, pas logarithmique.
  • L’équipe peut dire « regénérez ceci derrière le même contract » et le penser réellement.

Quand les modules sont enchevêtrés :

  • Chaque changement exige de comprendre le graphe complet de dépendances.
  • Chaque refactor assisté par AI risque de casser des systèmes sans rapport.
  • L’équipe cesse peu à peu de faire confiance aux sorties de l’AI parce que le rayon d’impact est imprévisible.
  • La vitesse retombe au niveau pré-AI, mais avec davantage de code à maintenir.

Le test pratique

Avant d’accepter un module généré par AI dans une codebase, appliquez un test :

Puis-je supprimer ce fichier et le réimplémenter à partir de zéro, en n’utilisant que l’interface qu’il expose, sans modifier aucun consommateur ?

Si oui, mettez-le en prod. Si non, corrigez la boundary avant de le mettre en prod.

Le coût de cet enforcement est faible. Un composition root combiné à une conception interface-first vous donne cette propriété de façon structurelle. Vous n’avez pas besoin d’une gouvernance élaborée. Vous avez besoin d’une règle d’architecture appliquée avec constance.

Le lien avec l’architecture AI-native

J’ai écrit sur ce problème plus large dans Stanford CS146S a raison sur l’AI coding. Le sujet manquant, c’est l’architecture. Le principe de remplaçabilité est le mécanisme précis qui rend les codebases AI-native vivables au-delà de la version un.

Stanford apprend aux développeurs à utiliser efficacement les outils AI. C’est important. Mais l’aisance avec les outils, sans remplaçabilité, est un piège : vous livrez plus vite jusqu’au moment où la codebase devient coûteuse à faire évoluer, puis vous livrez plus lentement que des équipes qui n’ont jamais utilisé l’AI.

La discipline n’est pas « mieux prompter ». La discipline, c’est « architecturer de sorte que les erreurs de prompting soient peu coûteuses à annuler ».

FAQ

Que signifie une « architecture remplaçable » pour du code généré par AI ?

Une architecture remplaçable signifie que chaque module généré par AI se trouve derrière une interface dont dépend le reste du système — pas derrière l’implémentation elle-même. Quand les besoins changent ou que la génération est mauvaise, vous supprimez le module et vous le réimplémentez sans toucher aux consommateurs.

Comment faire respecter la remplaçabilité dans une codebase générée par AI ?

Trois mécanismes : des interfaces possédées par l’application (pas par la dépendance), un composition root unique où toutes les implémentations sont câblées ensemble, et une vérification CI qui échoue si un module importe directement les internals d’un autre module.

Est-ce que la remplaçabilité ralentit le développement initial ?

Non. Définir une interface avant de générer une implémentation ajoute quelques secondes. Le coût de ne pas le faire apparaît des semaines plus tard, quand un changement de fournisseur ou un refactor se transforme en rewrite complet.

Est-ce la même chose que la dependency injection ?

La dependency injection est un mécanisme parmi d’autres pour obtenir la remplaçabilité, mais ce n’est pas toute l’histoire. La remplaçabilité exige aussi des contract tests, une validation des frontières et un composition root — pas seulement des paramètres de constructeur.