Cet article prolonge ce que j'ai écrit dans mon livre Le contexte. Pour le lire, téléchargez-le ou achetez-le sur Amazon.
Le TDD utilise les tests pour guider le développement. Et si nous utilisions aussi une ontologie pour préserver la cohérence métier d'un logiciel ? C'est la piste que j'explore avec Claude Code : partir du code pour construire une ontologie, puis inverser progressivement la démarche pour que cette ontologie guide, contrôle et accompagne les évolutions du logiciel.
Le code fonctionne. Mais fait-il toujours le bon métier ?
Avec les agents IA comme Claude Code, nous sommes entrés dans une période où produire du code devient de moins en moins difficile.
Je décris une fonctionnalité. L'agent explore le code existant, modifie plusieurs classes, ajoute des fonctions, adapte des interfaces, écrit des tests. Quelques minutes plus tard, il me présente son travail.
Le code compile. Les tests passent.
Mais une question demeure : ce nouveau code respecte-t-il toujours la logique métier de mon application ?
Un agent peut produire une implémentation techniquement correcte et introduire une incohérence dans le modèle métier. Il peut employer deux noms pour désigner un même concept, réintroduire une notion abandonnée ou créer une règle qui contredit celles qui existent déjà.
Le problème devient particulièrement intéressant lorsque l'application grandit et que les agents IA réalisent une part croissante des modifications.
Comment leur donner un référentiel métier commun ? Comment détecter une dérive ? Et comment éviter que ce référentiel devienne une documentation de plus, qui finit par ne plus correspondre au logiciel ?
C'est à partir de ces questions que j'ai commencé à expérimenter, dans mes développements personnels avec Claude Code, une approche que j'appelle ici Ontology-Driven Design (ODD).
Pour illustrer cette démarche, je prendrai l'exemple d'un ERP fictif.
Première étape : extraire l'ontologie du code
Mon point de départ était assez simple.
Je considère le code source comme la source de vérité du comportement effectivement implémenté. Une spécification décrit une intention ; le code révèle ce que l'application fait réellement.
J'ai donc demandé à Claude Code d'explorer le code de mon application et d'en extraire une représentation du domaine métier dans un fichier Markdown : ontology.md.
Ce fichier décrit notamment :
- les concepts métier : Client, Commande, Devis, Facture, Avoir… ;
- leurs propriétés et leurs relations ;
- les règles métier et les invariants ;
- les états et leurs transitions ;
- le vocabulaire utilisé pour désigner ces concepts.
Dans notre ERP fictif, une commande client est associée à un client. Elle possède une ou plusieurs lignes. Elle peut être issue d'un devis. Elle peut être validée, annulée ou facturée.
Ces informations ne sont pas nécessairement décrites au même endroit dans le code. Certaines règles sont explicites, d'autres sont dispersées dans plusieurs fonctions.
Claude Code peut les rechercher et tenter de les reconstituer.
Le résultat n'est pas une spécification parfaite. C'est une interprétation structurée du métier à partir de son implémentation, avec les limites que cela suppose : une règle implicite peut lui échapper, et un comportement historique peut être pris à tort pour une règle intentionnelle.
Mais j'obtiens quelque chose d'intéressant : une représentation du domaine indépendante des détails techniques de l'implémentation.
Le fichier ontology.md devient un point de référence pour comprendre le logiciel.
Deuxième étape : vérifier le nouveau code par rapport à l'ontologie
Une fois cette ontologie disponible, j'ai demandé à Claude Code de s'en servir lorsqu'il développait de nouvelles fonctionnalités.
L'idée était de comparer les modifications réalisées avec les concepts et les règles d'ontology.md.
Imaginons par exemple que l'ontologie indique qu'une facture validée ne peut plus être modifiée.
Si Claude Code ajoute une fonctionnalité qui permet d'en changer les lignes après validation, il doit relever cette contradiction.
De même, si l'ontologie distingue clairement un devis d'une commande, l'agent ne doit pas introduire une fonction qui mélange les responsabilités de ces deux concepts sans raison explicite.
C'est un premier filet de sécurité.
Mais il a un défaut.
La vérification intervient après la production du code.
L'agent a déjà fait son travail. Il a peut-être créé plusieurs classes, ajouté des méthodes et construit des tests autour d'une mauvaise interprétation du métier.
Nous pouvons détecter le problème, mais il faut ensuite revenir sur le code produit.
Autrement dit, j'ai ajouté un contrôle a posteriori. C'est utile, mais insuffisant.
Troisième étape : s'inspirer du Test-Driven Development
C'est là que j'ai pensé au TDD.
Le principe du Test-Driven Development est connu : avant d'implémenter un comportement, on écrit un test qui exprime ce qu'on attend. Le test échoue, on écrit le code nécessaire pour le faire passer, puis on améliore l'implémentation en conservant ce filet de sécurité.
Pourquoi ne pas appliquer une logique comparable à l'ontologie ?
J'ai donc demandé à Claude Code de changer son processus.
Avant de coder, il doit d'abord confronter la fonctionnalité demandée à l'ontologie existante.
L'ordre des opérations change.
Prenons une nouvelle demande :
« Je veux permettre la création d'une commande client sans passer obligatoirement par un devis. »
Si l'ontologie indique qu'une commande doit obligatoirement provenir d'un devis, l'agent détecte une contradiction avant de modifier le code.
Mais cette contradiction n'est pas nécessairement une erreur dans la demande.
Elle peut correspondre à une évolution parfaitement légitime du métier.
L'agent doit donc reconnaître que l'intention du développeur modifie une règle existante, proposer son évolution et déterminer les conséquences sur les concepts associés.
Il pourra ensuite développer la fonctionnalité en tenant compte du modèle métier révisé.
Le processus devient :
- Comprendre la fonctionnalité demandée.
- Identifier les concepts et les règles ontologiques concernés.
- Relever les éventuelles contradictions entre la demande et le modèle existant.
- Résoudre ces contradictions, en distinguant évolution volontaire et erreur de conception.
- Développer la fonctionnalité.
- Vérifier que le code produit est cohérent avec le modèle métier attendu.
Ce n'est pas du TDD au sens strict : une ontologie n'est pas une suite de tests automatisés, et une analyse par LLM n'offre pas les mêmes garanties qu'une assertion déterministe.
Mais la philosophie est proche : définir les attentes et les contraintes avant d'implémenter, plutôt que découvrir les incohérences après coup.
À ce stade, l'ontologie commence à jouer un rôle actif dans le développement.
Ce qui fait apparaître un nouveau problème.
Quatrième étape : une ontologie qui doit évoluer avec le code
Si l'ontologie devient un référentiel pour le développement, comment la maintenir à jour ?
Je ne veux surtout pas créer un nouveau document qu'il faudra penser à modifier à la main à chaque évolution de l'application.
Ce serait revenir au problème initial : une documentation qui se désynchronise du code.
L'idée suivante consiste donc à introduire une part mécanique dans le processus.
Un script analyse les changements du code source, notamment à partir de Git, et identifie les éléments ajoutés, modifiés ou supprimés :
- fonctions et méthodes ;
- classes et interfaces ;
- modules et packages ;
- signatures et contrats d'API ;
- outils, ressources et contrats exposés via MCP ;
- relations et comportements métier identifiables dans les modifications.
L'objectif n'est pas de reconstruire l'ontologie à partir des détails techniques de l'application.
Au contraire, je veux rester indépendant des choix d'implémentation. Une architecture hexagonale, le Domain-Driven Design ou toute autre organisation du code (même très sale) ne doivent pas imposer leur structure à l'ontologie.
L'ontologie représente le domaine métier, pas l'architecture technique.
Une classe n'est pas nécessairement un concept métier. Un nouveau package peut n'être qu'une réorganisation technique. Une fonction peut implémenter une règle métier sans constituer elle-même un nouveau concept.
Il faut donc séparer deux opérations.
La première est mécanique : déterminer précisément ce qui a changé.
La seconde est sémantique : comprendre si ces changements introduisent, modifient ou contredisent des concepts métier.
C'est ici que le LLM intervient.
Le script produit un inventaire des modifications. Le LLM confronte cet inventaire à l'ontologie actuelle et aux directives qui ont déclenché le développement.
Plusieurs situations peuvent alors se présenter.
Un nouveau concept métier apparaît. L'agent peut proposer ou préparer son ajout dans l'ontologie, avec ses relations et les règles associées.
Un concept existant change de signification. Il faut déterminer s'il s'agit d'une évolution voulue ou d'une dérive.
Deux concepts deviennent incohérents. L'agent signale la contradiction, avec les références au code concerné.
Le vocabulaire diverge. Deux noms désignent la même réalité métier, ou un nom existant est utilisé pour une autre notion.
Le changement est purement technique. Aucune modification ontologique n'est nécessaire.
Un point reste essentiel : le code ne doit pas automatiquement avoir raison.
Si un agent introduit une erreur, je ne veux pas qu'un second agent modifie l'ontologie pour rendre cette erreur acceptable.
Le triangle : intention, code et ontologie
C'est ici, je pense, que se trouve la véritable évolution du concept.
Comparer le code et l'ontologie ne suffit pas.
Il faut confronter trois éléments :
L'intention : ce que le développeur a demandé à Claude Code.
Le code : ce qui a effectivement été implémenté.
L'ontologie : les concepts et les règles métier de référence.
C'est la comparaison de ces trois éléments qui permet de comprendre la nature d'un écart.
Reprenons notre ERP fictif.
L'ontologie indique qu'une commande client provient obligatoirement d'un devis.
Le développeur demande explicitement de rendre le devis facultatif.
Claude Code modifie les fonctions concernées et introduit la possibilité de créer directement une commande.
L'ontologie et le nouveau code sont désormais en contradiction. Mais le code respecte l'intention.
Le bon résultat n'est donc pas de refuser systématiquement la modification. C'est de proposer l'évolution correspondante de l'ontologie, puis de rechercher les autres endroits du logiciel qui supposent encore qu'un devis est obligatoire.
En revanche, si Claude Code avait supprimé cette obligation sans qu'aucune directive ne le demande, l'écart serait suspect.
La différence est fondamentale.
Une incohérence n'est pas toujours un bug. Elle peut signaler une transformation volontaire du métier.
Le rôle du système n'est pas d'empêcher le changement, mais de le rendre explicite, cohérent et traçable.
Vers un véritable cycle de développement piloté par l'ontologie
J'imagine maintenant un processus qui intervient à trois moments.
Avant le développement : comprendre le métier
À la réception d'une nouvelle fonctionnalité, Claude Code identifie les concepts ontologiques concernés.
Il n'a pas besoin de charger toute l'ontologie. Il peut sélectionner les concepts, relations et règles utiles à la demande.
Il vérifie ensuite que la fonctionnalité est compatible avec ce modèle, ou signale les évolutions nécessaires.
Le développement part ainsi d'une compréhension explicite du domaine.
Pendant et après le développement : détecter les dérives
Un analyseur mécanique repère les modifications du code source.
Des outils comme Tree-sitter permettent notamment d'en analyser la structure syntaxique et d'identifier les éléments modifiés (c'est mon prochain chantier). Les évolutions des contrats d'API et des interfaces MCP renseignent aussi sur les capacités exposées par l'application.
Le LLM s'appuie sur ces éléments pour rechercher les incohérences avec l'ontologie.
Cette opération pourrait être intégrée au workflow de Claude Code par des hooks, notamment après une modification ou à la fin d'une tâche.
Il ne s'agit pas de demander à un LLM de relire aveuglément toute l'application à chaque changement, mais de concentrer l'analyse sur les éléments impactés.
Avant l'intégration : contrôler la cohérence
Une dernière vérification pourrait intervenir avant la fusion du code.
Elle produirait un rapport indiquant :
- les concepts nouveaux ou modifiés ;
- les règles métier potentiellement impactées ;
- les incohérences détectées ;
- les modifications ontologiques proposées ;
- les décisions qui nécessitent une validation humaine.
L'objectif est d'obtenir un contrôle reproductible, assez précis pour être utile, sans transformer chaque modification du code en revue interminable du modèle métier.
Conserver le lien entre les concepts et leur implémentation
Une amélioration complémentaire consisterait à maintenir une traçabilité entre l'ontologie et le code.
Un concept comme Invoice pourrait être associé à plusieurs classes, fonctions, événements ou opérations d'API qui participent à son implémentation.
Ces associations ne définissent pas le concept. Elles indiquent où il est implémenté.
Cette distinction permettrait de répondre à des questions intéressantes.
Si je modifie le concept de facture, quelles parties du code risquent d'être affectées ?
Si une fonction métier disparaît, quelle règle ontologique pourrait ne plus être implémentée ?
Si une nouvelle opération d'API apparaît, expose-t-elle un concept existant ou révèle-t-elle une notion nouvelle ?
Et si une classe change de nom, s'agit-il d'un simple refactoring ou d'une modification réelle du domaine ?
Cette cartographie pourrait être entretenue progressivement, à mesure que le code évolue.
Elle devrait néanmoins conserver les preuves de chaque association : fichiers, symboles et changements observés. Une relation déduite par le LLM ne doit pas être confondue avec une correspondance démontrée.
Des invariants ontologiques aux tests automatisés
Une autre piste consiste à rendre une partie de l'ontologie exécutable.
Certaines règles métier peuvent s'exprimer sous forme d'invariants.
Par exemple :
- une facture validée ne peut plus être modifiée ;
- une facture doit posséder au moins une ligne ;
- un avoir référence la facture qu'il corrige ;
- une commande annulée ne peut pas être expédiée.
Certaines de ces règles pourraient servir à produire des tests automatisés, ou à vérifier que des tests existants les couvrent.
On obtiendrait alors deux niveaux complémentaires.
Le premier serait sémantique : le LLM examine la cohérence entre les intentions, les concepts et le code.
Le second serait déterministe : des tests et des contraintes exécutables vérifient les comportements qu'il est possible de formaliser.
L'ontologie ne remplacerait donc ni les tests unitaires ni les tests d'intégration.
Elle pourrait aider à expliquer pourquoi certains comportements doivent être testés, et à repérer des règles métier encore dépourvues de vérification.
Une ontologie vivante, mais pas une ontologie opportuniste
Ce dispositif comporte un risque majeur.
Si l'ontologie change systématiquement pour suivre le code, elle ne constitue plus un filet de sécurité. Elle devient une simple documentation continuellement régénérée.
À l'inverse, si elle interdit toute évolution qui contredit ses règles actuelles, elle empêche le produit de changer.
Il faut donc gérer explicitement les évolutions ontologiques.
Je distingue trois situations.
L'évolution est intentionnelle et claire. Le système peut préparer une modification versionnée de l'ontologie, voire l'appliquer dans une branche de travail avant validation.
La modification paraît incohérente avec l'intention. Le système propose une correction du code plutôt qu'une mise à jour de l'ontologie.
L'intention est ambiguë. Le système demande une décision au lieu d'inventer une nouvelle règle métier.
L'ontologie devient ainsi un contrat évolutif entre l'intention et l'implémentation.
Cela suppose aussi de conserver un historique, par exemple avec un petit registre de décisions inspiré des ADR. Un concept renommé ne doit pas devenir deux concepts indépendants. Une règle supprimée doit pouvoir être reliée à la décision qui a justifié sa disparition.
L'évolution de l'ontologie doit être aussi traçable que celle du code.
Mesurer la cohérence plutôt que compter les lignes de code
Cette approche pourrait aussi produire quelques indicateurs intéressants.
La couverture ontologique mesurerait la proportion des concepts métier identifiés dans le code qui ont une représentation dans l'ontologie.
La traçabilité mesurerait combien de concepts disposent de références vérifiables vers leur implémentation.
Le nombre d'incohérences confirmées et non résolues donnerait une idée de la dérive entre le code et le modèle.
Enfin, la proportion d'invariants associés à des tests exécutables pourrait aider à mesurer la solidité du filet de sécurité.
Ces chiffres ne seraient pas des indicateurs de qualité absolus. Leur intérêt dépend entièrement de la capacité du système à distinguer les vrais concepts métier du bruit technique.
Mais ils pourraient rendre observable quelque chose qui reste aujourd'hui largement implicite : la cohérence conceptuelle d'un logiciel au fil de ses évolutions.
Et si le processus fonctionnait dans les deux sens ?
Au départ, mon fonctionnement était unidirectionnel.
Le code produisait l'ontologie.
Puis j'ai ajouté un contrôle inverse : l'ontologie servait à vérifier le nouveau code.
En m'inspirant du TDD, j'ai introduit une étape préalable : confronter les intentions à l'ontologie avant de commencer à développer.
La prochaine évolution consiste à automatiser la détection et la qualification des changements, pour entretenir cette cohérence dans la durée.
Mais je vois désormais une possibilité supplémentaire.
Le code pourrait faire évoluer l'ontologie, et l'ontologie pourrait guider les évolutions du code.
Si une modification du code fait apparaître un nouveau concept métier, le système propose de l'intégrer à l'ontologie.
Si une demande implique l'évolution d'un concept existant, l'ontologie permet d'identifier les règles et les implémentations potentiellement concernées avant même de commencer.
Le référentiel n'est plus seulement produit par le logiciel. Il participe à sa transformation.
C'est cette boucle qui m'intéresse.
Une idée ancienne, un usage à réinventer
Il serait faux de présenter l'Ontology-Driven Design comme une idée entièrement nouvelle.
L'utilisation des ontologies pour concevoir des applications existe depuis longtemps. Pavel Hruby décrivait déjà en 2005 une approche d'Ontology-Based Domain-Driven Design.
Plus récemment, des travaux comme ODDToolkit ont exploré la génération d'artefacts logiciels à partir d'ontologies formelles.
Mon exploration est un peu différente.
Je ne cherche pas nécessairement à générer le logiciel depuis une ontologie. Je ne souhaite pas non plus imposer OWL, RDF ou un autre formalisme pour commencer.
Je cherche à utiliser une ontologie métier comme référentiel vivant de cohérence pour des agents IA qui modifient le code source.
La nuance est importante.
Le modèle métier ne remplace pas l'implémentation. Il ne prétend pas décrire toute la complexité d'un logiciel. Il ne garantit pas, à lui seul, l'absence de bugs.
Il fournit un cadre de référence explicite pour éviter que chaque agent, à chaque nouvelle tâche, reconstruise sa propre interprétation du métier.
Ce qui reste à démontrer
Je suis encore dans une démarche d'expérimentation personnelle.
J'ai commencé par générer une ontologie depuis le code, puis par demander à Claude Code de contrôler ses évolutions à partir de celle-ci. J'ai ensuite fait évoluer les directives pour déplacer cette vérification en amont du développement.
La boucle mécanique de synchronisation, la traçabilité systématique et les contrôles automatisés sont les prochaines pistes de travail.
Beaucoup de questions restent ouvertes.
L'analyseur pourra-t-il détecter une vraie modification métier lorsqu'aucun nom de classe ne change ? Combien de faux positifs produira le LLM ? JEV pourra-t-il répondre à ce besoin ? C'est un autre chantier, à ouvrir un jour. Comment éviter de surcharger l'ontologie de détails techniques ? À quelle fréquence faut-il réexaminer les correspondances entre concepts et code ? Et surtout, le gain de cohérence justifiera-t-il le coût d'exécution et de maintenance du dispositif ?
Il faudra éprouver cette approche sur de véritables évolutions logicielles, avec des changements métier volontaires, des incohérences introduites artificiellement et des refactorings purement techniques.
Je ne prétends donc pas avoir défini une nouvelle méthode de développement validée.
Je décris une direction que j'expérimente.
Le métier comme filet de sécurité
Les pratiques de développement ont progressivement multiplié les protections.
Les tests unitaires protègent des comportements. Les tests d'intégration protègent des interactions. Les vérifications de types et les outils d'analyse statique détectent certaines catégories d'erreurs. Les règles d'architecture aident à préserver la structure du logiciel.
Mais lorsque des agents IA produisent une part croissante du code, une autre question devient importante :
Qui protège la cohérence du modèle métier que ces agents manipulent ?
Le DDD apporte depuis longtemps une partie de la réponse, avec le langage ubiquitaire, les modèles de domaine et les frontières de contexte. L'architecture hexagonale aide à isoler le métier des préoccupations techniques.
L'Ontology-Driven Design que j'explore chercherait à ajouter à ces principes un mécanisme opérationnel : rendre le modèle métier explicite, le confronter aux intentions de développement, puis contrôler en continu sa cohérence avec le code.
Au fond, mon objectif n'est pas de produire davantage de documentation.
Il est de permettre à Claude Code de développer plus vite sans réinventer silencieusement le métier à chaque fonctionnalité.
Le code reste la vérité du comportement implémenté. L'ontologie devient la référence du sens métier. L'intention explique pourquoi ce sens peut changer.
Et c'est de leur confrontation que pourrait naître un nouveau filet de sécurité pour le développement assisté par IA.