Bibliothèque · Résumé et avis

Learning Domain-Driven Design

De Vlad Khononov. La porte d'entrée moderne et praticable du DDD : du sous-domaine à l'Event Sourcing et au CQRS.

FR EN
Couverture de Learning Domain-Driven Design, Vlad Khononov

Learning Domain-Driven Design

Learning Domain-Driven Design: Aligning Software Architecture and Business Strategy

8.6 /10

« La porte d'entrée moderne du DDD : tout ce qu'Evans a fondé, rangé pour qu'on s'en serve enfin. »

  • AuteurVlad Khononov
  • VOO'Reilly, 2021 · 340 pages
  • Édition lue1re (2021)
  • LangueEn anglais uniquement
  • Fiche~15 min de lecture
Notation du livre sur 5 dimensionsIdées8/10Applicable9/10Lisibilité9/10Actualité9/10Exemples8/10

Le livre qui rend le Domain-Driven Design enfin praticable : du sous-domaine au code, via Event Sourcing, CQRS et saga.

Pourquoi ce livre

Je suis architecte backend dans une fintech crypto. Mon quotidien, c'est de l'Event Sourcing et du CQRS en Go : deux gros mots que ce livre décode justement de fond en comble. Le Domain-Driven Design (conception pilotée par le domaine métier), je l'ai d'abord rencontré chez Eric Evans, le « blue book » fondateur. C'est une cathédrale. Magnifique, et à peu près impraticable quand on débute : dense, en Java, écrite pour des gens qui savaient déjà.

Khononov fait l'inverse. Il prend les mêmes idées et les range pour qu'on s'en serve. Il le dit lui-même : son but est de « démocratiser » le DDD. Là où la fiche du blue book d'Evans pose les fondations et où la DDD Reference sert de glossaire, celle-ci est le livre qu'on lit pour faire. C'est la suite logique des deux, et de loin la plus actionnable.

Les idées qui restent

Le livre se lit en deux temps : la conception stratégique (quoi construire, et pourquoi), puis la conception tactique (comment l'écrire). Voici les neuf idées qui restent.

1La vraie cause des échecs n'est pas technique

À son premier job, Khononov demande à un collègue ce qu'est la « logique métier ». Réponse : « Oh, c'est toutes les boucles et les if-else dont tu as besoin pour implémenter les specs. » Il lui faudra des années pour comprendre que c'est faux, et que cette logique métier est le cœur du logiciel.

Le décor est là pour planter le problème. Selon les études que cite le livre, environ 70 % des projets logiciels ne tiennent ni les délais, ni le budget, ni les besoins du client. On a même un mot pour ça depuis 1968 : la « crise du logiciel ». Cinquante ans, des dizaines de méthodes (Agile, TDD, DevOps), et le taux d'échec n'a presque pas bougé. Le point commun de toutes les enquêtes sur ces échecs tient en un mot : la communication.

Le DDD attaque ce problème par un angle simple : aligner la conception du logiciel sur le domaine métier qu'il sert. Une citation ouvre le chapitre et résume tout, signée Alberto Brandolini : « C'est l'incompréhension des développeurs, pas le savoir des experts métier, qui part en production. » Tout le reste du livre découle de là.

2Tout le code ne mérite pas le même soin

Vous avez un temps fini et vos meilleurs ingénieurs sont une ressource rare. Où les mettre ? Le livre découpe toute entreprise en sous-domaines (des ensembles cohérents de cas d'usage) et en distingue trois types, à traiter très différemment.

  • Le core (cœur de métier) : ce que l'entreprise fait mieux que ses concurrents, sa raison d'exister. Complexe, mouvant, source d'avantage. À écrire en interne, avec vos meilleurs gens. On ne l'achète pas, on ne le sous-traite pas.
  • Le generic (générique) : ce que tout le monde fait pareil, l'authentification, le paiement, le chiffrement. Complexe, mais déjà résolu. À acheter ou adopter : payer pour réinventer une roue standard serait absurde.
  • Le supporting (de soutien) : la glu sans avantage concurrentiel, des écrans de saisie, du CRUD basique. Logique simple. À confier à des juniors ou à un framework rapide.

L'heuristique qui tranche core vs reste : « est-ce que quelqu'un pourrait payer pour ce sous-domaine tout seul ? » Si oui, c'est probablement du core. Exemple fil rouge du livre, une plateforme de support client en mode SaaS (Software as a Service, du logiciel loué en ligne) baptisée WolfDesk : l'algorithme qui gère le cycle de vie des tickets est du core (c'est son modèle économique), le SSO d'authentification (Single Sign-On, la connexion unique : un seul login pour tout) est du generic, la saisie des horaires des agents est du supporting. Trois soins différents pour trois enjeux différents.

3Une seule langue, du métier au code

Le problème, c'est le téléphone arabe. L'expert métier explique à l'analyste, qui rédige une spec, que le développeur traduit en code. À chaque relais, le sens se déforme. Personne ne ment, et pourtant ce qui arrive en production n'est plus ce que le métier voulait.

La parade du DDD s'appelle l'Ubiquitous Language (la langue omniprésente) : une seule langue, celle du métier, parlée par tout le monde (développeurs, product, experts) et dans tout, les conversations, la documentation, les tests, et jusque dans le code lui-même. Deux règles de fer : un terme a un seul sens (si « police » désigne à la fois une règle et un contrat d'assurance, on invente deux mots distincts), et deux mots ne désignent jamais la même chose. Le nom d'une classe, d'une méthode, d'une variable doit être un mot que l'expert métier reconnaîtrait.

Dans son retour d'expérience, l'auteur va plus loin : la présence d'une vraie langue commune a été chez lui le meilleur prédicteur du succès d'un projet, avant même la qualité de l'architecture. C'est, dit-il, le « cœur de métier » du DDD lui-même.

Comment fabrique-t-on cette langue, concrètement ? Elle ne se décrète pas, elle se négocie : développeurs et experts métier nomment ensemble chaque concept, un seul nom par idée, et ce nom part tel quel dans le code, les tests et la doc. Le jour où un terme se révèle ambigu (un même mot pour deux réalités), on le coupe en deux et on renomme partout. La langue n'est jamais figée, elle s'affine à chaque conversation.

Pour l'amorcer sans réunion interminable, le livre propose un atelier, l'EventStorming : tout le monde dans une pièce couvre un mur de post-it, un orange par « quelque chose s'est passé » (un événement métier, comme « commande payée »). Ces événements donnent le premier vocabulaire partagé, et deviennent les premiers événements du futur modèle.

Quatre personnes jouent au téléphone arabe : la première tient une bulle nette, la dernière un gribouillis emmêlé.
Le téléphone arabe : expert → analyste → développeur → production. À chaque oreille, le sens se déforme. La langue commune supprime les relais.

4Découper là où la langue se contredit

Poussez la langue commune à l'échelle de toute l'entreprise et elle finit par se contredire. Le mot « lead » (un prospect commercial), dans une boîte de télémarketing, désigne pour le marketing un événement (un contact qui arrive) et pour les ventes un long processus de plusieurs mois. Forcer un modèle unique qui satisfait les deux donne un schéma monstrueux qui couvre un mur entier et ne sert bien personne.

La solution est de découper. Un Bounded Context (contexte délimité) est la frontière à l'intérieur de laquelle une langue commune reste cohérente. Dehors, le même mot peut signifier autre chose. La phrase qui résume tout : « les sous-domaines se découvrent, les bounded contexts se conçoivent. » Les sous-domaines vous sont imposés par la stratégie de l'entreprise, vous les constatez ; les bounded contexts sont une décision d'ingénieur, vous les dessinez. Une règle de propriété va avec : une seule équipe par bounded context.

L'image que j'ai retenue, c'est la tomate. En botanique c'est un fruit, en cuisine un légume, et en 1893 la Cour suprême des États-Unis l'a classée légume pour pouvoir la taxer à l'import. Même objet, trois modèles, chacun juste dans son contexte. Une fois les contextes séparés, ils communiquent par des contrats. Deux patterns reviennent : l'anticorruption layer (couche anticorruption : vous traduisez le modèle de l'autre dans le vôtre pour ne pas vous laisser polluer) et l'open-host service (service à hôte ouvert : vous publiez une interface publique stable que les autres consomment). Evans avait déjà nommé tout ça ; Khononov le rend enfin clair.

5L'agrégat, frontière de cohérence forte

On entre dans le tactique. Pour la logique simple, le livre pose d'abord deux patterns légers : le transaction script (une procédure par opération) et l'active record (un objet qui sait se sauvegarder lui-même en base). Mais dès que les règles s'entremêlent, il en faut un vrai, le domain model, dont la pièce maîtresse est l'agrégat.

Où tracez-vous alors la frontière d'une transaction ? L'Aggregate (agrégat) répond avec une seule règle : une transaction modifie un seul agrégat. Un agrégat est une grappe d'objets traités comme un tout, et seule sa propre logique peut changer son état. On ne lui pousse pas des valeurs avec des setters, on lui envoie des commandes qu'il valide.

Dedans, deux briques. Les entities (entités) sont des objets avec une identité qui dure, comme le ticket. Les value objects (objets-valeurs) sont des paquets immuables qui portent leurs propres règles (un montant d'argent, une adresse de wallet) et tuent l'habitude de balader des chaînes et des entiers nus.

La phrase exacte du livre : « l'agrégat est une frontière qui fait respecter la cohérence. » Dedans, tout est en cohérence forte (validé et committé d'un bloc, atomique). Dehors, tout est en cohérence à terme (« eventual consistency » : on se synchronise un peu plus tard, par des événements, et on se référence par identifiant, jamais par objet entier). Le signal d'une mauvaise conception devient mécanique : si vous avez besoin de modifier deux agrégats dans la même transaction, c'est que vos frontières sont mal tracées.

Pourquoi cette discipline aide ? Khononov emprunte à Goldratt la notion de degrés de liberté. Une classe avec cinq champs publics modifiables, c'est cinq degrés de liberté, donc cinq sources de bugs. La même classe où quatre champs se déduisent du premier par des règles n'a que deux degrés de liberté. Elle est plus simple, alors que son code paraît plus compliqué. Encapsuler les règles dans l'agrégat réduit la complexité pour de vrai, pas juste à l'œil.

6Stocker l'histoire, pas l'état

Voici l'idée qui m'occupe au quotidien. Regardez une ligne de table : le prospect Casey Davis est « CONVERTED ». Vrai, mais la table ne dit que le présent. Elle a perdu l'histoire : combien d'appels avant la conversion ? Une vente éclair ou un parcours de six mois ? Toutes ces questions, essentielles pour optimiser, sont introuvables. La table garde l'état final et jette le chemin.

L'Event Sourcing (sourcing par événements) renverse ça. Au lieu d'enregistrer l'état courant, on enregistre chaque événement qui l'a fait évoluer : lead-initialized, contacted, followup-set, order-submitted, payment-confirmed. Ces événements deviennent la source de vérité, rangés dans un event store (magasin d'événements) en mode append-only : on ajoute, on ne modifie ni ne supprime jamais. L'état courant n'est plus stocké, il est reconstruit en rejouant les événements dans l'ordre. L'analogie de l'auteur est parfaite : c'est le grand livre comptable. On n'efface pas une ligne, on ajoute une écriture, et le solde se déduit en parcourant le journal.

Ce que ça débloque vaut son surcoût.

  • Le voyage dans le temps : rejouez les cinq premiers événements et vous obtenez l'état exact à ce moment-là, idéal pour rejouer un bug là où il s'est produit.
  • L'insight : ajoutez demain une nouvelle projection (une nouvelle façon de lire les mêmes événements) pour répondre à une question qu'on ne se posait pas hier.
  • Le journal d'audit gratuit : pour qui gère de l'argent, la loi l'exige souvent, et là il est natif.

Le prix à payer, le livre l'assume : courbe d'apprentissage raide, schéma d'événements pénible à faire évoluer (Greg Young a écrit un livre entier rien que là-dessus), et plus de pièces mobiles. Et la peur classique sur la performance ? Reconstruire l'état coûte, mais ça ne pince qu'au-delà de 10 000 événements par agrégat, quand la durée de vie moyenne en compte moins de cent.

Ce « moins de cent », c'est tout le propos : une commande accumule une poignée d'événements dans sa vie — créée, lignes ajoutées, validée, payée, expédiée, livrée — quelques dizaines au plus, jamais des milliers. Rejouer ça pour reconstruire son état est instantané. La peur ne se matérialise que pour de rares agrégats à très longue vie (un compte bancaire de trente ans, un capteur qui émet sans fin) qui franchiraient les 10 000 — et là encore, un snapshot périodique borne le coût : on sauvegarde une « photo » de l'état tous les N événements et on ne rejoue que les quelques-uns depuis.

7Un modèle pour écrire, plusieurs pour lire

L'Event Sourcing a un défaut : on ne peut interroger qu'un agrégat à la fois. Comment fait-on une recherche, un rapport transversal ? Réponse : le CQRS (Command-Query Responsibility Segregation, séparation des responsabilités entre commandes et requêtes). On sépare en deux le système.

D'un côté le command model (modèle de commande) : le seul à porter la vérité en cohérence forte, celui qui valide les règles et protège les invariants (les contraintes métier qui doivent toujours rester vraies, par exemple un solde qui ne passe jamais sous zéro). De l'autre les read models (modèles de lecture) : des projections en lecture seule, en cohérence à terme, qu'on multiplie autant que de besoins, et qu'on peut effacer puis régénérer de zéro. Comme une vue matérialisée en base : la source change, la vue précalculée se met à jour.

Ça ouvre la persistance polyglotte : Greg Young le dit, « toutes les bases sont imparfaites, chacune à sa façon », alors on en combine plusieurs, une relationnelle pour les commandes, un index de recherche pour le texte, des fichiers plats pour la lecture ultra-rapide.

Khononov démonte au passage une idée fausse répandue : « une commande ne doit jamais rien renvoyer, on lit toujours via un read model. » Faux, dit-il. Une commande peut, et souvent doit, renvoyer une donnée, tant qu'elle vient du modèle fortement cohérent, parce qu'on ne peut pas attendre d'une projection à terme qu'elle soit déjà à jour. Le CQRS est obligatoire avec l'Event Sourcing, mais utile tout seul.

Côté architecture, il complète deux autres patterns :

  • la layered architecture (architecture en couches : présentation au-dessus de métier au-dessus de données) : bien pour de l'Active Record, ce pattern où un objet sait se sauvegarder lui-même en base.
  • les ports & adapters : la logique métier au centre, l'infrastructure qui dépend d'elle via des interfaces. Bien pour un domain model, où la logique vit dans des objets riches.

8Publier fiable, orchestrer sans transaction distribuée

Un agrégat publie un événement pour prévenir le reste du système. Deux façons naïves de le faire, toutes deux fausses :

  • publier depuis l'agrégat : l'événement part avant que la base ait validé, et si la validation échoue, l'événement est déjà dehors, irrécupérable.
  • publier depuis la couche applicative après validation : si le process meurt juste après le commit mais avant la publication, l'événement est perdu pour toujours.

Le pattern Outbox (boîte d'envoi) résout ça. On valide l'état de l'agrégat ET les événements dans la même transaction atomique (tout ou rien : soit les deux passent, soit aucun), via une table d'envoi dédiée. Ensuite, un relais lit les événements non publiés et les pousse sur le bus de messages, puis les marque comme envoyés. Livraison garantie au moins une fois. C'est exactement la mécanique qui évite les fantômes en production.

Un point que le livre martèle : ce qu'on publie ainsi vers d'autres contextes doit être un événement public choisi exprès, distinct des événements internes (privés) de l'agrégat. Exposer ses événements de domaine bruts, c'est livrer ses détails d'implémentation et se recoupler à tout le monde.

Reste le cas où un processus métier traverse plusieurs agrégats, alors qu'une transaction n'en touche qu'un. Exemple : une campagne pub activée doit être soumise à l'éditeur, puis confirmée ou rejetée. Ça, c'est une Saga : un composant qui écoute les événements et émet les commandes correspondantes, avec des actions de compensation si une étape échoue. Le tout en cohérence à terme. Le livre prévient : n'abusez pas des sagas pour rattraper des frontières d'agrégats mal tracées.

Et il donne une règle de pouce que j'adore pour distinguer une saga d'un process manager (gestionnaire de processus, son cousin plus intelligent) : « si une saga contient des if-else pour choisir quoi faire ensuite, c'est probablement un process manager. » La saga fait du simple aiguillage événement → commande ; le process manager porte un état et arbitre un vrai workflow.

9Rien n'est figé : un sous-domaine change de nature

La dernière idée traverse tout le reste, et c'est celle qui sépare ce livre du blue book. Les types de sous-domaines ne sont pas gravés dans le marbre. Un core peut se banaliser quand un concurrent en fait un produit sur étagère, et un supporting qu'on croyait anodin peut devenir un core le jour où sa logique se met à faire mal à maintenir. Cette douleur est justement un signal : quand un sous-domaine de soutien devient pénible, c'est souvent qu'il a changé de nature sans qu'on le voie.

La conséquence est concrète : quand la nature change, le pattern d'implémentation doit suivre. Un module parti en simple Active Record peut devoir migrer vers un domain model, puis vers de l'Event Sourcing. Khononov montre comment opérer ces migrations dans l'event store, en rejouant l'historique pour générer les événements qu'on n'avait jamais enregistrés. Le DDD n'est donc pas une décision qu'on prend une fois au début, c'est un réglage qu'on rejoue à chaque fois que le métier bouge.

Trois choses que je ne savais pas

Mon avis, honnêtement

Ce livre, c'est mon métier. Je fais de l'Event Sourcing et du CQRS toute la journée, et c'est le premier qui me les a posés dans leur vrai cadre au lieu de les présenter comme des gadgets à la mode. Le blue book d'Evans est la fondation, mais il est dense et daté par son Java ; la Reference est un glossaire pour initiés. Celui-ci est celui qu'on lit pour passer à l'acte. Il démocratise sans abrutir, et c'est rare.

Le chapitre qui vaut le prix à lui seul, c'est l'annexe. Khononov y raconte Marketnovus, sa propre startup, « où nous avons commis toutes les erreurs de DDD possibles ». La boîte n'existe plus, donc il parle sans filtre. L'arc est imparable : ils partent de « des agrégats partout » (chaque nom du cahier des charges promu agrégat, un gros monolithe anémique) pour finir, des années plus tard, à « de la langue commune partout ».

Au milieu, une « tour de Babel 2.0 » où ils coupent leur entité la plus complexe, le Lead, entre deux équipes : l'une en code applicatif, l'autre en procédures stockées (de la logique métier écrite directement dans la base). Deux langues, des règles dupliquées, des données corrompues pendant des années, et une seule issue, tout réécrire.

Plus loin, un « marketing hub » sur-conçu en Event Sourcing, CQRS et microservices pour une logique métier si simple qu'elle tenait en Active Record. Le mot pour ça : complexité accidentelle. Voir un expert détailler ses propres plantages rend chaque pattern crédible, parce qu'on voit ce qu'il coûte quand on s'en sert mal.

Ce qui est plus faible : tout le code est en C#, à traduire soi-même dans son langage, et le chapitre data mesh sentait le buzzword pas encore mûr en 2021. Et soyons honnête, les idées ne sont pas de lui. Bounded context, agrégat, Event Sourcing, ce sont Evans, Vernon, Young. Lui-même le dit. Son talent, c'est la synthèse : l'arbre de décision qui relie le type de sous-domaine au pattern de logique, puis à l'architecture, puis à la stratégie de test. Personne n'avait rendu le DDD aussi navigable. La phrase de clôture est tout le bouquin : « Ne suivez pas le DDD aveuglément comme un dogme, comprenez le raisonnement qu'il y a derrière. » Pour moi qui bâtis des systèmes événementiels dans une fintech, c'est le manuel que j'aurais voulu avoir au départ.

Odilon

Toujours valable en 2026 ?

Plus que jamais. C'est LA référence DDD moderne. Microservices, architecture événementielle, Event Sourcing : les patterns sont d'aujourd'hui, pas de 2003. Seul le data mesh a un peu jauni. Et un angle s'ajoute depuis : nos API et nos événements sont maintenant consommés par des agents IA autant que par des humains, avec les mêmes besoins, du prévisible, du bien nommé, de l'auto-décrit. Quand l'IA génère du code à toute vitesse, c'est une langue commune nette qui l'empêche de partir en vrille. La discipline du DDD devient un garde-fou, pas un luxe.

Pour qui ?

Lisez-le si

  • Vous construisez des systèmes backend non triviaux, avec de la vraie logique métier qui s'entremêle, et vous voulez un cadre de décision, pas un dogme
  • Vous faites ou voulez faire de l'Event Sourcing ou du CQRS, et les voir dans leur cadre réel
  • Vous avez ouvert le blue book d'Evans et rebondi sur sa densité
  • Vous êtes architecte et vous découpez un système en services

Passez votre chemin si

  • Vous ne faites que du CRUD ou du sous-domaine de soutien : le livre lui-même vous dirait de ne pas sur-concevoir
  • Vous voulez du code prêt à coller dans votre langage : c'est du C#, par extraits
  • Vous cherchez la théorie d'origine : lisez Evans d'abord. Mais honnêtement, lisez celui-ci en premier

Pour aller plus loin

La fondation, c'est le blue book d'Evans, et le glossaire officiel des patterns tient sur la table à côté. Pour le versant données et cohérence qui sous-tend l'Event Sourcing et le CQRS, Designing Data-Intensive Applications creuse la mécanique de la réplication et de la cohérence à terme.

Commentaires (0)

Voir toute la bibliothèque

D'autres fiches arrivent : un livre à la fois, la substantifique moelle seulement.