Alberto Denia compare le code à de l’argile : avec les agents IA, le coût des modifications chute, permettant d’expérimenter et de remodeler rapidement un logiciel. Il distingue deux approches complémentaires : l’artisan, qui intervient à chaque itération pour affiner le produit et son code, et l’usine, qui automatise les tâches répétitives grâce aux spécifications, tests et contrôles. Dans les deux cas, le jugement humain reste indispensable, mais il s’exerce à des moments différents : pendant la création ou lors de la conception du processus.
Pour intégrer l’IA générative à Symfony sans déléguer les règles métier au modèle, l’auteur distingue les rôles du RAG (recherche documentaire), de MCP (accès aux outils), des agents (enchaînement d’actions) et de l’orchestrateur (coordination des parcours autorisés). Il propose une architecture en cinq niveaux, inspirée de l’architecture hexagonale, où les services métier conservent les décisions et les contrôles d’accès. L’article détaille aussi les exigences de production : validation des arguments, protection contre les injections de prompt, confirmations humaines, observabilité, coûts et tests.
Une architecture logicielle réussie dépend autant des contraintes qu’on accepte d’abandonner que de celles qu’on respecte. Tolérer des données temporairement périmées, des écritures non transactionnelles ou quelques pertes de métriques peut simplifier fortement un système et améliorer ses performances. Ces arbitrages exigent un dialogue entre ingénieurs et responsables produit. Avec les agents de programmation, le risque s’accentue : les LLM ajoutent spontanément des vérifications, verrous et garanties non demandés, produisant une complexité inutile. La revue de code doit donc aussi supprimer ces exigences imaginaires.
Chris Richardson précise ce qui distingue réellement un pattern logiciel d’une simple technique, pratique, règle ou conception : un problème récurrent dans un contexte donné, des forces à équilibrer, une solution applicable, ses conséquences et ses relations avec d’autres patterns. Il explique aussi qu’un « pattern language » suppose des relations riches entre patterns, et montre pourquoi cette rigueur améliore les décisions d’architecture, limite le battage technologique et fournit un vocabulaire commun aux équipes.
L’IA rend désormais le code beaucoup moins coûteux à écrire et à réécrire, mais cela ne le rend pas moins important. Au contraire, les agents de codage s’appuient fortement sur les conventions et abstractions déjà présentes dans un projet : un code cohérent produit de meilleurs résultats, tandis que les défauts se propagent. Le rôle du développeur se déplace donc vers la recherche des bonnes abstractions, de la meilleure architecture et d’un modèle de domaine solide, que l’IA peut ensuite appliquer rapidement partout.
L’auteur soutient que les mauvais résultats d’un agent de code ne viennent pas toujours du modèle : une architecture ambiguë lui fournit aussi de mauvais repères. À partir d’un exemple Symfony, il montre qu’une séparation claire entre domaine, application, infrastructure et interface, complétée par du DDD, des tests et des règles de dépendances vérifiables, réduit les choix implicites. L’objectif n’est pas de sur-architecturer, mais de rendre les responsabilités et contraintes suffisamment explicites pour les humains comme pour l’IA.
Le problème majeur du code généré par IA n’est pas nécessairement sa qualité moyenne, mais la perte progressive de compréhension du système par les équipes. Quand spécifications, code, tests et décisions passent presque entièrement par des LLM, l’architecture, l’intention et les choix techniques deviennent opaques. L’auteur insiste sur l’importance des fondamentaux, du jugement humain et surtout de la maintenabilité : générer vite est facile, mais maintenir un système que personne ne comprend devient le véritable risque.
Une pipeline de quatre subagents Claude Code accompagne le développement en privilégiant l’apprentissage : cadrage produit, design, génération du squelette et revue. L’IA prépare les interfaces et le code répétitif, tandis que la développeuse implémente la logique métier à partir de TODOs explicites. Les décisions sont documentées et la revue devient progressivement plus fine, par fichier. Cette approche favorise la compréhension du code, mais reste coûteuse en temps et en tokens ; son rapport coût/bénéfice et les garde-fous pédagogiques restent à évaluer.
Face aux défis de la vélocité des décisions dans les grands projets logiciels, le modèle mental des "portes à sens unique" (one-way doors) contre les "portes à double sens" (two-way doors) permet d'éviter l'accumulation de dette technique. Une décision est une porte à sens unique si elle est rare, conséquente et difficile à inverser, comme le choix d'une base de données. Inversement, une porte à double sens concerne des décisions à faible risque et facilement réversibles, tel qu'un nom de variable locale.
Pour maintenir une haute vélocité décisionnelle en toute sécurité, il est crucial d'intégrer la réversibilité dans le code grâce à des patterns architecturaux spécifiques. L'objectif est de concevoir des "trappes de sortie" intégrées plutôt que de se retrouver enfermé dans un coin du code. Cette approche délibérée permet d'éviter la paralysie d'analyse et de garantir que l'équipe puisse progresser rapidement et de manière fiable.
Parmi les patterns favorisant les portes à double sens, on trouve les feature flags pour découpler le déploiement de la mise en production, la limitation de l'exposition des API pour permettre des itérations sur les interfaces sans impacter les clients en aval, le découplage des formats de données pour isoler les modifications des structures de stockage permanentes, et les dark launches pour valider de nouvelles logiques en parallèle avec un impact nul sur les utilisateurs.
L'article aborde la problématique du "code sloppé" généré par l'intelligence artificielle, en soulignant que cette notion englobe divers types d'échecs sans cause unique ni solution universelle. Il identifie des schémas récurrents tels que des validations redondantes, la création de fonctions quasi-identiques ou des vérifications excessives pour des entrées impossibles, qui nuisent à la qualité et à la maintenabilité du code.
Une cause majeure de cette accumulation de code de mauvaise qualité réside dans le manque de contexte pour les agents d'IA. Ces derniers, ne disposant pas des informations complètes sur les validations précédentes ou les fonctions existantes, ont tendance à synthétiser des solutions locales et redondantes, exacerbant le "problème de localité" où le code qui devrait évoluer ensemble est difficile à trouver et à modifier.
Pour remédier à ce problème, l'article propose d'identifier précisément les comportements ou problèmes récurrents, de préférer des descriptions de problèmes spécifiques plutôt que des termes vagues comme "code sloppy". L'utilisation d'outils comme des règles de linting ciblées, inspirées par des travaux comme ceux de Dillon Mulroy, peut aider à identifier ces schémas de code problématiques et orienter les efforts de nettoyage, qu'il s'agisse de corrections locales ou de refontes architecturales.
Le projet Agojie vise à automatiser le jeu de société Dice Throne. Le développement a débuté par des décisions fondamentales avant même la première ligne de code, abordant la structure du modèle du jeu, la mécanique de défense des héros, la découpe des tâches de développement et le choix de la pile technologique. L'objectif initial est de modéliser le cœur du jeu en un contre un, en se concentrant sur la gestion des dés, avant d'intégrer les cartes et les effets de statut.
Trois idées d'architecture ont été envisagées dès le départ : la séparation entre la définition d'un héros et l'état d'une partie, la modélisation du jeu comme un "Aggregate" pour garantir l'intégrité des règles métier, et l'utilisation d'"Domain Events" pour enregistrer les faits importants du domaine. Cependant, ces idées n'ont pas été appliquées immédiatement, privilégiant une approche où les décisions sont justifiées par les règles du jeu et non par l'intuition.
Ce projet est structuré en quatre étapes principales : la mise en place du cœur du jeu sans cartes, le développement d'une interface utilisateur basique avec sauvegarde des parties, l'intégration de la couche de cartes pour influencer le jeu, et enfin la gestion des effets de statut qui affectent les héros. La première phase consiste en la rédaction d'une spécification détaillée des règles du jeu de Dice Throne, incluant des exemples concrets pour guider le développement du code.
Résumé pour Shaarli:
Le projet Agojie se lance dans l'automatisation de Dice Throne, un jeu de dés et de combat stratégique. Les premières étapes se concentrent sur les décisions architecturales et la modélisation des règles fondamentales, sans écrire de code. L'objectif est de développer le cœur du jeu, puis d'ajouter progressivement des fonctionnalités comme les cartes et les effets de statut, en s'appuyant sur des principes de conception logiciel rigoureux.
L'article soutient que la tendance actuelle à diviser les systèmes d'IA en de multiples agents spécialisés, à l'instar des microservices, peut être prématurée et coûteuse. Il souligne que de nombreux agents médiocres ne surpassent pas un seul agent performant, et que la complexité croissante d'un agent unique conduit à une dégradation progressive. Les problèmes majeurs incluent la difficulté de sélectionner le bon outil parmi une liste étendue, la contradiction des instructions dans un unique prompt, et la difficulté de modifier le système sans affecter l'ensemble.
Le moment idéal pour opérer une scission en agents multiples est lorsque ces difficultés deviennent mesurables et nuisibles, et non sur la base d'une esthétique ou d'une tendance. La solution proposée est le schéma "supervisor pattern", où un agent superviseur centralise la classification et le routage des requêtes vers des agents spécialisés. Chaque agent spécialiste est confiné à un domaine unique, disposant de son propre prompt clair, d'un ensemble d'outils limité et distinct, et gérant son propre état de conversation.
Ce modèle permet de retrouver la précision dans le choix des outils et d'éviter les conflits d'instructions, offrant ainsi une meilleure maintenabilité et évolutivité. L'idée principale est de ne pas commencer avec une architecture multi-agents avant que la nécessité ne soit clairement établie par des problèmes concrets liés à la complexité d'un agent unique, puis d'adopter une approche structurée avec un superviseur et des spécialistes.
Cet article met en évidence la convergence architecturale entre des frameworks web populaires tels que Spring Boot (Java), Symfony et Laravel (PHP), ainsi que NestJS (Node.js). Malgré leurs langages distincts, ces outils partagent une philosophie commune visant à faciliter la maintenance des applications serveur sur le long terme. Ils s'appuient sur des concepts clés tels que l'injection de dépendances, le routage déclaratif, les patrons de conception de type "repository" et une gestion de configuration adaptable aux différents environnements.
L'auteur illustre cette similarité en comparant des exemples de contrôleurs dans chaque framework. Il observe que l'injection par constructeur, l'isolement des services métiers et la déclaration des routes directement dans le code de la méthode sont des pratiques récurrentes. Cette approche, notamment celle de Spring Boot avec ses "starters" qui simplifient la configuration initiale, rappelle des concepts déjà présents dans l'écosystème PHP, suggérant une influence mutuelle et une standardisation des solutions architecturales pour les applications web modernes.
Dans une architecture CQRS, la synchronisation entre la base de données de lecture et celle d'écriture est un défi majeur pour éviter la présentation d'informations obsolètes. Une stratégie de synchronisation en deux étapes est nécessaire pour équilibrer la performance de la base de données de lecture et la cohérence de la base de données d'écriture.
Face à des volumes importants de données et à des besoins de recherche performante, comme dans le cas d'une recherche de disponibilités hôtelières, une base de données unique avec de nombreux index peut devenir inefficace. L'adoption d'une architecture CQRS, séparant la gestion des commandes et des requêtes, permet d'optimiser ces aspects en utilisant une base de données dédiée à la lecture, telle que MongoDB, enrichie d'index appropriés.
Pour maintenir la cohérence entre la base de données principale (PostgreSQL) et la base de données de recherche (MongoDB), une approche asynchrone est privilégiée. Les modifications apportées à PostgreSQL sont publiées sur un broker de messages, et MongoDB les traite lorsque sa charge de lecture le permet, garantissant ainsi que les opérations d'écriture restent rapides. Pour pallier les risques liés aux opérations asynchrones, des reconstructions planifiées de la base de données de lecture sont effectuées, généralement pendant les périodes de faible activité, afin d'assurer la mise à jour des données.
-
La distinction entre les "sub-agents" et le "Master Control Panel" (MCP) est cruciale pour l'architecture des systèmes d'IA. Historiquement, la confusion a conduit à mélanger la fonction de raisonnement ("qui pense") et celle d'exécution ("qui agit"), entraînant des problèmes de gouvernance, de traçabilité et de permissions.
Un sub-agent est conçu pour un rôle cognitif spécialisé, recevant un prompt, un périmètre et des règles pour produire une sortie structurée et utile. Il se concentre sur la pensée critique et la formulation. À l'inverse, un serveur MCP est une infrastructure dont le rôle est d'exécuter des actions de manière contrôlée, en exposant des capacités et des données avec des contrats clairs et une traçabilité.
Cette séparation est particulièrement pertinente lors de la gestion d'incidents. Dans un modèle bien conçu, un orchestrateur délègue des tâches à des sub-agents spécialisés (diagnostic, mitigation), qui formulent des hypothèses et proposent des actions. L'exécution réelle de ces actions est ensuite gérée par les serveurs MCP appropriés, laissant une trace écrite et permettant de comprendre précisément qui a décidé quoi et pourquoi.
L’article remet en question l’idée reçue selon laquelle l’utilisation de microservices serait un signe de compétence avancée en ingénierie logicielle. L’auteur, Devrim Ozcay, souligne que la complexité n’est pas une preuve de qualité, mais plutôt un choix facile à faire, souvent au détriment de la maintenabilité et de la fiabilité. Il explique que les microservices, bien qu’utiles dans certains cas, génèrent des coûts opérationnels et techniques importants, comme des problèmes de réseau, de duplication de requêtes ou de gestion de dépendances, transformant des opérations simples en défis de systèmes distribués.
L’auteur critique l’"Arms Race" (course à l’armement) architecturale, où les équipes adoptent des microservices par mimétisme (ex. : "Netflix le fait") sans évaluer si cette solution répond à un besoin réel. Il insiste sur la nécessité de se demander quel problème les microservices résoudront mieux qu’une architecture monolithique bien conçue, laquelle peut offrir des avantages comme une cohérence transactionnelle, un déploiement simplifié et une complexité opérationnelle réduite. Un monolithe modulaire, avec des frontières de domaine claires, peut ainsi servir de base solide avant toute éventuelle décomposition.
Enfin, l’article rappelle que la maîtrise des systèmes distribués, et non leur simple utilisation, distingue les ingénieurs expérimentés. L’auteur met en garde contre la tentation de créer de la complexité artificielle, soulignant que la véritable compétence réside dans la capacité à évaluer quand une solution simple (comme un monolithe) est préférable, et à anticiper les problèmes inhérents aux architectures distribuées, comme les pannes de réseau, les données obsolètes ou les comportements inattendus des consommateurs.
L’article relate une expérience où des agents d’IA chargés de refondre une architecture logicielle ont involontairement effacé des mois de savoir-faire intégré dans le code, sans enfreindre aucune règle formelle. Les régressions apparues ensuite ont révélé que ces outils, bien que produisant un code propre et conforme aux patterns, avaient ignoré des ajustements empiriques cruciaux, non documentés et non testés, car sans valeur apparente pour un algorithme. Leur comportement par défaut, sans garde-fous explicites, a ainsi détruit une connaissance implicite accumulée sur des années.
Pour éviter de reproduire cette situation, l’équipe a restructuré son approche en s’appuyant sur des contraintes techniques strictes, notamment via ESLint, seul outil capable de bloquer efficacement les agents. L’architecture du nouveau dépôt a été repensée non pour son élégance conceptuelle, mais pour imposer des règles d’import et de modularité que les IA ne peuvent contourner, transformant ainsi des recommandations en obligations incontournables.
L’expérience illustre les limites des agents de codage en production : leur efficacité dépend entièrement des contraintes qu’on leur impose, et leur manque de compréhension contextuelle les rend incapables d’intégrer des savoirs informels. La solution retenue repose donc sur une délégation encadrée, où la qualité du code est garantie par des mécanismes automatiques plutôt que par une revue humaine systématique.
L’article critique l’approche traditionnelle des systèmes multi-agents en IA, qui se concentre souvent sur l’orchestration des agents plutôt que sur la modélisation du domaine métier. L’auteur souligne que les règles et contraintes (comme les seuils d’approbation) ne devraient pas être intégrées dans les prompts des agents, mais plutôt encapsulées dans un modèle de domaine bien défini. Cela permet aux agents d’agir dans un environnement structuré, recevant des retours immédiats en cas d’erreur, et favorise une autonomie plus robuste.
Plutôt que de concevoir des workflows complexes entre agents, l’article plaide pour une architecture où le domaine est modélisé en premier : processus, état, invariants et règles métier. Les agents interagissent ensuite avec ce modèle partagé, sans avoir à gérer eux-mêmes les contraintes. Cette séparation réduit les risques liés aux erreurs de compréhension des règles et évite les systèmes soit trop risqués, soit trop restrictifs.
L’auteur présente Mozaik, un framework qui adopte cette approche en introduisant un état partagé et concurrentiel pour les agents, tandis que le modèle de domaine garantit le respect des règles. L’objectif est de construire des systèmes plus fiables et évolutifs, en s’appuyant sur une modélisation précise du monde réel plutôt que sur des workflows artificiels.
L’auteur, Derek Mwale, explique qu’il conçoit désormais des logiciels en anticipant leur maintenance sur dix ans, ce qui influence ses choix techniques : structure des dossiers, nommage des variables, documentation ou encore conception des API. Cette approche vise à faciliter la compréhension du code par son "moi futur", souvent moins familier avec le contexte initial, et à éviter les solutions trop complexes ou abstraites qui deviennent rapidement incompréhensibles.
Il compare le logiciel à un jardin plutôt qu’à un bâtiment, soulignant que sans entretien, il se dégrade avec le temps (dépendances obsolètes, changements de frameworks, etc.). Pour lui, la lisibilité n’est pas un simple bonus mais une fonctionnalité essentielle, car un code trop astucieux ou obscur devient un fardeau pour les développeurs futurs, voire pour lui-même quelques mois plus tard.
Enfin, il met en garde contre le "code trop malin", qui peut sembler élégant à court terme mais se transforme en dette technique. Il privilégie des solutions simples et claires, car elles résistent mieux à l’épreuve du temps, contrairement aux abstractions génériques ou aux fonctionnalités superflues.
L’auteur partage sa réflexion sur la conception d’un outil logiciel personnel simple, un logiciel de bureau pour usage exclusif, rejetant les solutions SaaS ou cloud. Il opte pour une application macOS développée en Flutter, avec une base de données SQLite locale, évitant ainsi toute dépendance à internet ou infrastructure serveur. La simplicité prime, avec une gestion automatique des données pour éviter toute maintenance utilisateur.
Pour étendre l’application à mobile (Android et iOS) sans dupliquer le code, il sépare la logique métier des données utilisateur, comparant cela à partager une recette de gâteau plutôt que les ingrédients. Flutter permet de compiler une seule base de code Dart en applications natives pour chaque plateforme, sans recourir à une architecture client-serveur coûteuse ou complexe.