Retour

Mon usine logicielle à l'heure de l'IA

Hugo
Hugo
Publié 28 juil. 2026
Lecture18 min

Je fais cette page pour documenter mon "usine logicielle" locale. Ce sera plus une page de référence qu’un article et je vais la référencer sur la page ressources du site.

Contexte : plusieurs applications dans des monorepos (hakanai, Writizzy, Bloggrify), polyglotte (Nuxt, Kotlin, JS), solo dev, du code écrit en grande partie par des agents, du déploiement continu en production.

Sommaire

L'idée directrice

Même si les agents de dernière génération sont désormais capables de produire du code de qualité (bien mieux que la majorité des développeurs humains), la production de code ne représente qu'une partie de ce que j'appelle la qualité logicielle. Le reste c'est :

  • l'intention (pourquoi, pour qui)
  • est-ce que ça satisfait les 4 risques identifiés par Marty Cagan :
    • Value : risque lié à la valeur
    • Usability : risque lié à la facilité d'utilisation
    • Feasability : risque lié à la faisabilité
    • Viability : risque lié à la viabilité commerciale
  • on peut rajouter : performance et fiabilité

Une partie de ces risques se résout avec une bonne compréhension de son marché, des benchmarks, des interviews, des tests manuels, des maquettes. Tout ça fait également partie de mon "usine logicielle" même si je ne décris pas tout ici.

Le code produit est désormais quasi 100% généré, mais ça ne veut pas dire que c'est du vibe coding. Le vibe coding tel que défini par Karpathy c'était de l'expérimentation et le fait de se laisser porter par une session de dev. Ici, je vais parler de context engineering. L'objectif c'est de donner tout le contexte nécessaire, au bon moment, pour que le logiciel corresponde à une intention et soit contrôlé systématiquement. Même si je n'écris pas le code, j'en suis responsable et je dois garder le contrôle dessus.

L'outillage décrit ici répond à plusieurs questions :

  1. Qu'est-ce que l'agent sait ? (contexte, mémoire, graphe de code)
  2. Qu'est-ce qu'il sait faire de façon déterministe, sans improviser ? (skills, procédures)
  3. Qu'est-ce qui l'arrête quand il se trompe ? (hooks, tests d'architecture, quality gates)

Couche 1 : le contexte

Voici les fichiers lus par les agents avant de démarrer. Attention, la taille du contexte doit rester contrôlée. Un trop gros contexte coûte de l'argent et dégrade la qualité des réponses s'il devient trop chargé. On cherche à économiser les tokens et à optimiser le moment où une information est chargée.

FichierContenu
CLAUDE.md (racine)Architecture, conventions transverses, index des specs
.claude/rules/*.mdRègles thématiques (commit, backend, front, contraintes long terme). Renvoie souvent vers une skill plus complète, chargée uniquement au besoin
.agents/*.mdContexte non technique (positionnement produit, personas, ton)

La séparation compte : le contexte permanent reste court, le contexte spécialisé se charge quand il sert.

Contrainte long terme comme contexte. Exemple concret : je prévois d'open-sourcer une partie du code. La règle « le code destiné à l'open source ne doit jamais dépendre du code propriétaire » est écrite dans les rules et vérifiée par un test (voir couche 4). Écrire une contrainte future dans le contexte évite de payer une refonte plus tard.

On peut trouver aussi des contraintes sur :

  • la copy marketing (les libellés dans l'application)
  • la façon d'écrire des migrations
  • les types à privilégier pour les champs en base
  • les patterns d'asynchronisme
  • etc. (liste très loin d'être exhaustive et qui s'enrichit régulièrement)

Une contrainte c'est propre à un projet et à une personne. C'est pas une question de qualité logicielle au sens strict du terme. C'est pas mieux ou moins bien de faire du feature flag par exemple, mais c'est ma préférence pour le déploiement partiel et l'activation de features en test.

Inutile de dire à une IA d'"écrire du code de qualité", ça ne rime à rien. Il faut expliciter ses propres contraintes.

Exemple de rule qui permet un chargement différé en fonction du contexte :

markdown
A chaque fois que je te demande de commiter, utilise le skill commit-convention

C'est tout con, mais ça évite de charger l'ensemble de la skill dans une rule (qui serait chargée systématiquement).

Voici une rule plus complexe :

markdown
---
paths:
  - "api/**/*"
---

Tu agis en tant qu'Expert Senior Kotlin et Spring Boot (DDD, Spring, JPA).
Tu as des patterns à respecter. AVANT d'écrire du code, tu DOIS invoquer le skill correspondant à la tâche que tu réalises.

## Skills à invoquer selon la tâche

| Tâche                                                                           | Skill             |
|---------------------------------------------------------------------------------|-------------------|
| Entités JPA, repositories, modèle de données                                    | `kotlin-jpa`      |
| Database schema changes, Flyway migrations, and Hibernate/Kotlin entity mapping | `db-migration`    |
| Services, logique métier, transactions                                          | `kotlin-services` |
| Controllers, APIs REST, DTOs                                                    | `kotlin-api`      |
| Tests unitaires ou d'intégration                                                | `kotlin-tests`    |
| Fin de tâche, validation avant de confirmer                                     | `kotlin-review`   |
| Feature gating par plan (offers.sql, FeatureService, quota, accès conditionnel) | `offers`          |
| Feature flags Unleash (rollout progressif, admin-only, maintenance, toggle runtime) | `feature-flags` |
| Producers RabbitMQ, consumers, outbox pattern, retry/quarantaine, config AMQP     | `rabbitmq`        |

Ici il y a deux choses importantes :

  • le pattern d'activation, qui précise que cette rule ne se charge que si on touche au répertoire api
  • le tableau qui liste toutes les skills disponibles, à n'ouvrir qu'en cas de besoin. Si l'IA ne fait pas de changement de schéma, aucun intérêt d'aller ouvrir la skill db-migration

Couche 2 : les skills

Une skill est une procédure écrite une fois, rejouée à l'identique. L'agent la charge tout seul quand le contexte matche. Ce chargement automatique peut parfois échouer. Dans ce cas, il faut demander explicitement d'utiliser la skill.

Le critère : est-ce que je me répète ? Si j'explique la même chose une troisième fois, ça devient une skill.

Chez moi, une trentaine, groupées par famille :

FamilleCe qu'elles encodent
BackendConventions de couche (API, persistance, services, transactions), stratégie de test, checklist de fin de tâche
FrontendArchitecture, typage, standards UI, récupération de la doc à jour (les frameworks JS bougent plus vite que l'entraînement du modèle)
DonnéesMigrations, requêtes d'investigation
Cycle produitRédaction de spec, clôture de spec, implémentation d'une maquette de thème
ExploitationRunbooks : traiter une erreur de production, modérer, auditer le SEO
ÉcritureConvention de commit, nettoyage des tics d'écriture IA

Deux choses que j'ai apprises :

  • Les skills « procédure multi-fichiers » sont les plus rentables. Exemple : ajouter un bloc à l'éditeur de contenu touche trois surfaces de rendu différentes. Sans skill, l'agent en oublie systématiquement une.
  • Les skills « doc à jour » sont très importantes sur du code qui évolue rapidement. Ça permet à un agent de comprendre les points d'entrée et les intentions d'une feature.

Sous-agents : pour les tâches qui génèrent beaucoup de lecture sans beaucoup de décision (audit, exploration large, rédaction de doc), je délègue à un sous-agent. Il consomme son propre contexte et me rend une conclusion, pas un dump de fichiers. Je les utilise de moins en moins, les agents récents font eux-mêmes des délégations assez ciblées.

Couche 3 : les outils

On entend souvent qu'une IA est non déterministe et qu'elle peut se tromper sur des choses triviales et qui doivent être déterministes, par exemple calculer 2+2.

C'est globalement faux désormais, et une IA ce n'est plus "juste un LLM" : elle dispose de nombreux outils pour contrôler une sortie. Il n'en reste pas moins que le meilleur moyen d'assurer une forme de reproductibilité, c'est de déléguer à des outils dont c'est le boulot.

La compilation, l'exécution des tests, les linters, tout ça c'est de la délégation. On peut déléguer à des MCP, ou à des skills qui utilisent elles-mêmes un outil en ligne de commande (CLI). J'essaie d'éviter les MCP qui sont plus consommateurs en contexte, mais j'en ai quand même quelques-uns.

MCP

Type de serveurCe que ça débloque
IDE (JetBrains)Build, inspections, refactorings, recherche indexée. Bien plus rapide et structuré qu'un build en ligne de commande
Graphe de code (GitNexus)Voir plus bas
Services métier (paiement, monitoring d'erreurs)Lire l'état réel du système au lieu de deviner
Base de donnéesInvestigation directe, dev et prod
NavigateurReproduire un bug côté client, QA

GitNexus

Le repo est indexé dans un graphe (symboles, relations, flux d'exécution). Ça permet de mesurer les niveaux d'impact et de retrouver tous les liens avec le code en cours de modification :

  • impact(symbole) avant de modifier : rayon d'explosion, appelants, niveau de risque
  • detect_changes() avant de commiter : est-ce que je n'ai touché que ce que je voulais ?
  • chercher un flux d'exécution plutôt que grepper un nom de fonction
  • renommer via le graphe d'appels plutôt qu'en find-and-replace

Le vrai sujet c'est pas la vitesse, c'est de détecter tous les effets de bord d'une modification.

Claude-mem, mémoire persistante

J'utilise deux niveaux de mémoire :

  • la mémoire interne de Claude
  • Claude-mem, qui permet de capturer des décisions entre les sessions

Ce qu'on veut avec ces outils, c'est éviter de reproduire des erreurs, documenter des décisions et ne pas repartir à chaque fois d'une session vide.

Le mécanisme de mémoire interne de Claude Code s'est amélioré et devient plus pertinent qu'avant avec les dernières versions. Il faut cependant le contrôler et ne pas hésiter à lui demander de supprimer des règles qu'il se crée tout seul et qui sont parfois un peu idiotes. Claude-mem, j'ai honnêtement un peu de mal à mesurer l'impact négatif ou positif. J'ai pas encore assez de recul dessus.

Filtrage des sorties

Un wrapper (ici RTK) préfixe les commandes shell et ne renvoie que ce qui est nécessaire. Ça reste très limité, uniquement disponible pour quelques outils. Le gain est parfois annulé car Claude lance deux fois la commande. Ça mange pas de pain, mais je pense qu'il y a encore une marge de progression. À savoir que Claude se construit ses propres outils à la volée en Python ou en Bash, et sait aussi utiliser des mécanismes de filtrage à base de grep, tail, etc. pour optimiser lui-même les sorties des outils qu'il utilise et économiser des tokens.

Débogage avec accès aux logs et à la base de données

J'utilise deux skills pour la résolution d'incidents :

  • une skill Sentry pour aller lire les informations sur Sentry et récupérer les stack traces
  • une skill db-query qui donne les droits d'accès en lecture seule sur la base (l'accès en lecture/écriture est possible directement via psql sur le container Docker en dev local)

Je pourrais aussi mentionner le MCP Stripe, en lecture seule également, qui permet dans certains cas spécifiques d'aller investiguer des soucis de configuration de Stripe.

Couche 4 : les garde-fous exécutables

Les garde-fous évitent le côté aléatoire lié à la compréhension et à l'exécution d'une consigne. Il arrive qu'un LLM ignore une rule. Il faut donc fournir des outils qui s'exécutent automatiquement.

Hooks

Des scripts déclenchés par le harness de l'agent, pas par l'agent lui-même.

DéclencheurEffet chez moi
Avant un appel shellRefuse la commande de build native, redirige vers le build IDE (plus rapide, erreurs structurées) et explique le fallback
Après une écriture de fichierLance le formateur/linter automatiquement sur le fichier touché

Autres usages qui marchent bien : bloquer l'édition de fichiers générés, exiger un test à côté de tout nouveau module, interdire un pattern dangereux.

Tests d'architecture

Les règles structurantes deviennent des tests qui cassent la CI.

Exemple réel, j'ai un test d'architecture qui préserve la frontière entre le futur code open source et le reste :

  • aucun fichier du côté « ouvert » ne référence le côté « propriétaire »
  • tout fichier de production appartient à l'un des deux côtés

Ça fait partie des tests automatiques, donc ça ne peut pas être contourné, à l'inverse d'une rule.

Lint de patterns

J'utilise plusieurs choses :

  • ESLint pour la syntaxe
  • ast-grep pour les décisions d'architecture, par exemple interdire tout appel à fetch sans passer par le client OpenAPI
  • le typecheck pour le typage

Couche 5 : l'usine

Une quality gate bloquante, par application

Chaque app a son workflow sur GitHub Actions.

text
push sur main
   └─> quality gate : lint → lint de patterns → typecheck → tests
        └─> build image docker
             └─> push registry
                  └─> webhook de déploiement

Le job de déploiement a un needs: sur le job de qualité. Rien ne part en production sans passer la gate. C'est indispensable en règle générale, encore plus pour du code produit automatiquement.

Tester à plusieurs étages

Je devrais pas avoir besoin de réexpliquer ça, mais dans le doute, j'ai plusieurs types de test.

ÉtageCe que ça couvre
UnitaireLa logique pure, rapide, massivement
Intégration avec conteneurs jetablesBase de données et broker réels, pas de mock
ArchitectureLes frontières structurantes (couche 4)
Composants frontRendu et composables dans un environnement framework
End-to-endLes parcours critiques uniquement

Je donne des instructions à Claude pour expliquer la hiérarchie des tests, gitnexus lui indique quoi rejouer pour valider ces modifications, et il a des consignes pour en écrire quand il ajoute/modifie du code.

Couche 6 : Le process produit

Comme je le disais en intro, le but c'est pas juste de produire du code, c'est de produire du code qui sert à quelque chose.

Le process commence souvent par une spec, puis un design, puis une implémentation.

Spec d'abord. J'ai un dossier de specs numérotées, une par domaine fonctionnel, indexées dans le contexte permanent. Deux skills encadrent le cycle : une pour rédiger la spec et son plan, une pour la clôturer en la mettant à jour avec ce qui a réellement été construit.

Cette spec et les discussions peuvent s'appuyer sur un fichier 'product-marketing-context.md' que je créé dans chaque projet et qui récapitule mes personas, mes compétiteurs, mon positionnement etc...

Le design. Par design j'entends deux choses : la conception technique et l'interface. La conception technique fait partie de l'étape de spec. La majorité du temps une spec suffit, mais certains cas un peu tricky nécessitent une spec dédiée à une brique technique ou à un choix technologique. Par contre l'étape de design/maquettage est à part. Je la réalise dans Claude Design. Je fais une maquette fonctionnelle et j'itère jusqu'à ce qu'elle soit parfaite. Je vérifie la compréhension, les libellés, l'utilisabilité. Ensuite je peux passer le résultat à Claude Code.

L'implémentation. Claude part de la spec et de la maquette. Il suit le plan réalisé dans la phase de spec. La spec est faite pour être livrée par étapes (protégées par feature flag). Ça me permet de faire plusieurs petites sessions d'implémentation plutôt qu'une grosse session, qui a tendance à se dégrader en qualité si elle se remplit trop.

L'étape de clôture est importante : sans elle, les specs deviennent obsolètes en six mois.

Règle explicite dans le contexte : si une spec est floue ou incohérente avec l'existant, l'agent doit poser la question, pas deviner.

Livraison progressive.

Je travaille en trunk based. Par contre j'utilise du feature flipping et du gating, ce qui représente deux choses différentes :

BesoinMécanisme
Activer/désactiver sans redéployer (rollout, kill-switch, maintenance)Feature flags (Unleash chez moi)
Restreindre selon le contrat client / le planTable de configuration + service de gating

J'ai des skills qui expliquent la différence, pour que les agents ne fassent pas n'importe quoi et respectent mon process de travail.


Par où commencer

Si vous partez de 0, la première étape c'est la quality gate si vous n'en avez pas. Vous devez avoir un mécanisme de contrôle qui joue les tests, les linters etc... Ensuite faut commencer léger avec un Claude.md qui décrit l'essentiel, le pourquoi. Ajoutez des rules au fur et à mesure pour les patterns d'architecture importants. Dès que vous voyez des procédures qui reviennent souvent, documentez ça sous forme de skills. Et puis équipez-vous des cli et MCP pour interagir avec vos outils principaux, jira, sentry, etc...

Attention, tout skills, MCP, code repris depuis l'extérieur doit être scruté. Ce sont des dépendances qui peuvent être des vecteurs d'attaques.

A retenir

  1. Ce qui compte doit être exécutable. Une consigne est suivie « la plupart du temps », mais elle peut être oubliée. Un hook ou un test est suivi tout le temps.
  2. Une erreur doit être documentée. Chaque erreur doit être consignée dans une skill ou dans la mémoire.
  3. Le contexte est un budget. Wrappers, filtres, sous-agents, résumés : tout ce qui réduit le bruit garde le raisonnement sur le problème.
  4. Mesurer les impacts avant et après l'édition. On veut éviter l'effet « 1 bug résolu, 10 de produits ».
  5. Les procédures répétitives ne s'improvisent pas. Une skill par procédure.
  6. La doc de spec meurt si sa clôture n'est pas dans le process. Il faut prévoir l'étape de mise à jour et de maintenance.

A améliorer

La mise à jour des skills/rules

Il faut prendre en compte que la techno est encore très jeune, février 2025 si on considère la programmation agentique. L'outillage se perfectionne mais il faut constamment aussi le revoir. Milieu 2025, certaines consignes dans un Claude.md faisaient sens, par exemple "écris un test pour chaque nouveau service". Aujourd'hui c'est du bruit et Claude le fait naturellement. Donc il faut se méfier de ses anciennes rules, parfois elles sont obsolètes et créent du bruit. J'ai aucun moyen de mesurer et de savoir si une ancienne rules est devenu obsolète.

Les dernières versions d'Opus sont de plus en plus autonomes. L'IA prend l'initiative tout seul de builder, de regarder le contenu produit, de lire le code des dépendances pour comprendre les appels, trouver des bugs, lancer des tests dans le navigateur. C'est limite flippant et plus rigoureux que 99% des humains. Soyons honnête, je suis de moins en moins utile sur les phases d'implémentation, mais je ne veux pas perdre le contrôle du code produit. Je suis partagé entre la satisfaction d'avoir une usine logicielle de plus en plus efficace et le risque de perdre la connaissance. Je dois trouver un moyen pour contrôler a posteriori les designs, de m'approprier le résultat.

Le problème du rabbit hole

J'ai ajouté récemment une rule boyscout.md

markdown
Laisser le code toujours un peu meilleur qu'il n'était avant. Si tu vois des erreurs flagrantes, signale moi des améliorations. Si tu constates des écarts avec la doc ou des infos présentes dans tes skills, ou dans ce fichier, idem, signale les.

Mais je me retrouve à faire des sessions sans fin. Je pense que je n’ai jamais bossé sur une base de code qui se maintient autant à jour. J’ai rarement autant amélioré le produit à ce niveau de détail. Mais ça vient avec un coût, la surcharge cognitive.

Je pense que j'aurais besoin plutot de noter automatiquement ces éléments là et de les catégoriser dans une TODO list en ligne (trello, todoist etc...). Je pense que le workflow pour la maintenance devrait se déplacer ailleurs, et être partiellement automatisé.

Le manque de standardisation

Je copie colle encore mes skills/rules etc… d’un projet à l’autre. Et parfois c’est dépendant à mon poste en fonction d’un skill installé en local.

Je dois trouver un moyen de packager mes skills pour les déployer là où c’est pertinent et pour centraliser la maintenance.

Le reste

Dans les autres points d'amélioration en suspens :

  • ma dépendance à Claude. Je souhaite tester des modèles open weight mais je n'ai pas le matériel pour ça. Risque modéré selon moi, tout l'écosystème bouge vers le haut
  • l'IDE devient obsolète par rapport à ce nouveau workflow. J'utilise encore intellij mais je ne le trouve plus adapté à notre époque. Je n'ai pas encore vu une alternative intéressante.

Stay in the loop

New articles delivered to your inbox. No spam, unsubscribe anytime.

0 Comments

No comments yet. Be the first to comment!