Le glossaire officiel du Domain-Driven Design : tous les patterns d'Evans en soixante pages, disponible gratuitement en ligne.
Pourquoi ce document
Les termes DDD sont partout : "bounded context" dans un article sur les microservices, "aggregate root" dans une conférence Symfony, "ubiquitous language" dans un livre d'architecture. Tout le monde les utilise comme s'ils allaient de soi. Je voulais la source. Le Blue Book fait 560 pages (2004) : Evans a lui-même condensé tous ses patterns dans cette Reference gratuite de 59 pages. C'est la carte avant le territoire.
Avertissement honnête : ce n'est pas un livre pour apprendre DDD. C'est une référence pour ceux qui connaissent déjà DDD et ont besoin d'un rappel rapide, ou pour ceux qui veulent comprendre le vocabulaire avant de plonger dans le livre complet ou dans Implementing Domain-Driven Design de Vaughn Vernon.
Les idées qui restent
1Le modèle ET le code forment un seul objet
Le piège classique de l'architecture : l'architecte modélise en réunion, le développeur code ce qu'il peut, et les deux divergent en silence. Evans parle d'un fossé mortel entre analyse et conception : chaque camp travaille contre l'autre sans le savoir.
La réponse du Model-Driven Design est radicale : le code doit refléter le modèle de domaine de façon littérale. Un objet Commande dans le code correspond à une commande dans le domaine métier, pas à une table, pas à un DTO, pas à une entité Doctrine avec ses propres règles.
(Un DTO, Data Transfer Object, est un objet sans comportement dont le seul rôle est de transporter des données : ce n'est pas un modèle.)
La conséquence directe : un changement dans le code peut être un changement dans le modèle. Renommer une classe, c'est peut-être changer le vocabulaire du projet.
Sans cela, les pathologies sont prévisibles : l'architecte qui ne code pas finit par modéliser des choses qu'on ne peut pas implémenter, et le développeur isolé finit par coder autre chose que ce que le métier voulait. D'où le principe Hands-on Modelers : toute personne qui contribue au modèle doit toucher le code, et tout développeur doit avoir accès aux experts métier.
2L'Ubiquitous Language : quand le code parle comme le domaine
Dans un projet ordinaire, trois langages coexistent sans jamais se toucher : le jargon des experts métier, le vocabulaire technique des développeurs, et le code. Les experts parlent de "confirmation de commande", les développeurs codent OrderStatusUpdate, et le chef de projet traduit dans les deux sens à chaque réunion. Chaque traduction perd un peu de sens.
DDD impose une règle sans appel : il doit exister un seul vocabulaire, partagé sans traduction entre experts et développeurs, dans les conversations ET dans le code. Corollaire immédiat selon Evans : tout changement dans le langage est un changement dans le modèle. Si votre expert dit "réservation" et votre code dit Booking, vous avez déjà un problème de modèle.
Ce n'est pas une question d'élégance. C'est un test en temps réel : si vous ne pouvez pas expliquer votre code à l'expert avec ses propres mots, votre code ne modélise pas correctement son domaine.
L'Ubiquitous Language est à la fois un outil de conception et un outil de détection des désalignements : dès que la conversation avec l'expert accroche sur un terme, c'est le modèle qui est faux.
3Bounded Context : quand "client" ne veut plus rien dire
Sur un grand projet, le même mot recouvre des réalités différentes selon qui parle. Dans le CRM, un "client" a un historique d'achats et des préférences. Dans la facturation, un "client" est une entité légale avec un SIRET. Dans le support, un "client" est un ticket ouvert avec un niveau de priorité. Forcer un seul modèle "Client" pour tout le système produit un objet monstrueux qui ne satisfait personne, ou des bugs silencieux quand les modèles se contaminent.
Le Bounded Context trace une frontière explicite dans laquelle un modèle s'applique de façon cohérente. À l'intérieur, l'Ubiquitous Language règne sans ambiguïté. Entre deux contextes, une traduction explicite est nécessaire, et cette traduction est elle-même modélisée (voir idée 7).
Reste à garder cette cohérence dans le temps. Evans appelle ça la Continuous Integration, à ne pas confondre avec les pipelines CI/CD automatisés : ici, c'est une pratique d'équipe. Quand plusieurs personnes codent en parallèle, leurs versions du modèle divergent en silence, chacune affinant un terme dans son coin. On l'empêche en fusionnant souvent, pour que les écarts apparaissent tôt et petits, et en ré-alignant le langage en continu, pour qu'un mot garde un seul sens dans le code comme dans les conversations.
4Entité vs Value Object : la première question sur chaque objet
Pour chaque concept du domaine, la première question : est-ce que l'identité compte, ou seulement les attributs ?
Une entité est définie par son identité, pas ses attributs. Un utilisateur reste le même utilisateur même s'il change d'adresse email, de nom marital ou de photo de profil. Son identifiant persiste dans le temps. Deux entités avec exactement les mêmes attributs restent deux entités distinctes : ce qui compte, c'est QUI, pas QUOI.
Un Value Object décrit une caractéristique. L'adresse "12 rue de la Paix, 75001 Paris" n'a pas d'identité propre. Deux adresses identiques sont interchangeables. Les Value Objects sont immuables : quand quelque chose change, on crée un nouvel objet au lieu de modifier l'existant. Cette immuabilité les rend sûrs à partager sans risque d'effet de bord.
// Entité — l'identifiant fait l'identité, les attributs peuvent évoluer
class Commande {
public function __construct(
private readonly CommandeId $id, // identité stable
private Statut $statut // peut évoluer
) {}
}
// Value Object — immuable, deux instances égales = interchangeables
final class Montant {
public function __construct(
private readonly int $centimes,
private readonly string $devise // "EUR", "USD"…
) {}
public function ajouter(Montant $autre): self {
return new self($this->centimes + $autre->centimes, $this->devise);
}
}
La distinction n'est pas technique : elle est sémantique. Un numéro de facture peut être une entité ou un Value Object selon que votre domaine le traite comme une identité persistante ou comme un code imprimable.
5Aggregate : le gardien de la cohérence
Un système avec des associations complexes fait face à un problème de cohérence : si n'importe quel code peut modifier n'importe quel objet directement, les règles métier se violent silencieusement. Une LigneDeCommande modifiée sans passer par la Commande peut produire un total incohérent.
Un Aggregate regroupe des entités et des Value Objects en une unité traitée comme un tout. Un seul objet est l'Aggregate Root : le seul point d'accès depuis l'extérieur. Les objets internes ne peuvent pas être modifiés directement depuis l'extérieur de la frontière.
La règle d'Evans : les frontières d'aggregate gouvernent à la fois les transactions et la distribution. Une transaction = un aggregate. Si deux aggregates doivent changer ensemble, c'est une coordination asynchrone, pas une transaction synchrone étendue.
Quand la frontière est stricte, chaque aggregate peut vivre indépendamment : un nœud par aggregate, des événements asynchrones pour les mises à jour entre eux. Les systèmes distribués deviennent praticables.
Concrètement, comment deux aggregates se parlent-ils ? Valider une Commande et décrémenter le Stock ne partagent jamais une transaction. La Commande valide seule, puis annonce ce qui s'est passé en émettant un événement ; le Stock l'écoute et applique la conséquence plus tard, dans sa propre transaction séparée, avec ses propres règles :
// 1. Aggregate Commande — sa propre transaction, tout ou rien
$commande->valider(); // vérifie SES règles (total cohérent…)
$commande->enregistrerEvenement(new CommandeValidee($commande->id(), $commande->lignes()));
// 2. L'événement voyage seul — aucune transaction commune, aucun verrou sur Stock
// 3. L'aggregate Stock réagit plus tard, dans SA PROPRE transaction
function surCommandeValidee(CommandeValidee $evenement) {
$stock->reserver($evenement->lignes()); // vérifie SES règles (jamais sous 0)
}
La Commande ne va jamais modifier le Stock elle-même — elle ne connaît que l'identité du Stock, pas ses entrailles. Le prix de la frontière : entre les deux, il existe un bref instant où la commande est validée mais le stock pas encore réservé. À l'intérieur d'un aggregate, la cohérence est immédiate ; entre aggregates elle est « à terme » (eventual) — et ce délai est précisément ce qui permet à chacun de vivre sur sa propre machine.
6Repository : la base de données disparaît du modèle
Sans séparation explicite entre domaine et infrastructure, la logique métier se contamine de SQL. Le code domaine connaît les noms de tables, les colonnes, les jointures. Changer de moteur de base de données devient une réécriture.
Un Repository crée l'illusion d'une collection en mémoire de tous les objets d'un type. Le code métier agit comme si les objets étaient toujours là, sans connaître SQL, Redis ni aucun détail d'infrastructure :
// ✗ Sans repository : le domaine connaît l'infrastructure
$stmt = $pdo->prepare('SELECT * FROM commandes WHERE statut = "en_attente" AND client_id = ?');
$stmt->execute([$clientId]);
// ✓ Avec repository : le domaine parle son propre langage
$commandes = $commandeRepository->commandesEnAttentePour($clientId);
La méthode commandesEnAttentePour est nommée dans l'Ubiquitous Language, pas en termes SQL. L'implémentation Doctrine, Redis ou fichier plat se cache derrière l'interface. Les tests peuvent utiliser un repository en mémoire. Le domaine reste pur. Evans précise : fournir des repositories seulement pour les Aggregate Roots qui en ont besoin, pas pour chaque entité interne.
7Context Mapping : la politique entre équipes, rendue visible
Quand un projet touche plusieurs Bounded Contexts (votre système, un CRM externe, un ERP legacy), DDD propose une taxonomie des relations. Ce n'est pas seulement une question technique : c'est souvent une question de rapports de force. DDD inclut même cette dimension politique : l'équipe upstream qui refuse d'adapter son API parce qu'elle a d'autres priorités a un nom dans la taxonomie.
- Anticorruption Layer (ACL) : quand le modèle upstream est une catastrophe (legacy non maintenu, Big Ball of Mud), on construit une couche de traduction défensive. Elle parle deux langues : les termes du système externe d'un côté, votre modèle propre de l'autre. Votre domaine ne se contamine pas.
- Conformist : quand l'équipe upstream n'a aucune raison de s'adapter à vos besoins, vous pouvez choisir d'adopter leur modèle sans vous battre. Ça simplifie l'intégration au prix d'un modèle parfois mal adapté à vos besoins réels.
- Open-host Service : vous exposez votre sous-système comme un ensemble de services avec un protocole clair et documenté. Chaque consommateur s'adapte à votre interface publique. C'est le pattern des APIs REST bien conçues.
- Partnership : deux équipes dont le succès est lié planifient ensemble et font évoluer leurs interfaces en commun. Coûteux en coordination, mais nécessaire quand une défaillance d'un côté fait tomber les deux.
Ces relations identifiées forment un Context Map. Ce n'est souvent pas un diagramme formel : c'est un dessin sur tableau blanc qui rend explicites des dépendances qui existaient déjà mais n'avaient jamais été nommées.
8Core Domain : où mettre vos meilleurs développeurs
Tout ne mérite pas le même investissement. Une boutique en ligne a un Core Domain : l'algorithme de recommandation, le moteur de tarification dynamique, la gestion de l'inventaire en temps réel. Ces parties font la valeur compétitive de l'entreprise. À l'opposé, la gestion des emails de confirmation ou la génération de PDF sont des Generic Subdomains (sous-domaines génériques) : nécessaires, mais standardisés.
Evans est direct : les meilleurs profils doivent aller sur le Core Domain, recrutement compris. Les développeurs les plus seniors ne devraient pas passer leur temps sur des Generic Subdomains qu'on peut acheter ou externaliser. Evans recommande explicitement de considérer des solutions sur étagère pour les Generic Subdomains : pourquoi implémenter votre propre gestion de permissions quand vous pouvez en acheter une éprouvée ? Libérez l'énergie pour le domaine qui fait votre valeur compétitive.
La distillation va plus loin :
- Identifier : identifier explicitement le Core Domain.
- Documenter : le documenter dans un Domain Vision Statement (un texte d'une page qui décrit en quoi votre domaine cœur crée de la valeur unique).
- Marquer : marquer ses éléments dans le code.
Cette visibilité permet à l'équipe de faire les bons arbitrages quand les ressources manquent.
Trois choses que je n'attendais pas
- CQRS cité comme une évolution, pas une contradiction : Evans remercie Greg Young et Udi Dahan pour CQRS (séparer les opérations de lecture et d'écriture) et l'Event Sourcing (stocker l'historique des événements plutôt que l'état courant). Il y voit le premier grand départ réussi de l'architecture héritée du tournant du siècle. DDD n'a pas été obsolété par eux : il a gagné de nouvelles options architecturales.
- Le Big Ball of Mud est un pattern légitime : Evans ne le condamne pas sans appel. Il cite Foote et Yoder : parfois le Big Ball of Mud est la solution pratique pour un contexte donné. Le conseil est d'en tracer une frontière pour qu'il ne contamine pas le reste, sans essayer d'y appliquer DDD à l'intérieur.
- "Separate Ways" (voies séparées) comme stratégie valide : ce pattern DDD reconnaît que parfois la meilleure chose que deux bounded contexts peuvent faire est de n'avoir rien à faire l'un avec l'autre. L'intégration a toujours un coût. Si le bénéfice est faible, déclarer l'indépendance.
Mon avis, honnêtement
Le titre dit "Reference" et il tient parole : un glossaire, pas un roman. Trente patterns, chacun sur une demi-page, format identique : contexte, "Therefore:" (la clé de voûte du pattern), solution. On n'apprend pas DDD ici. On vérifie.
Ce qui me frappe, c'est la tenue dans le temps. Evans a écrit l'original en 2004, cette Reference en 2015. Vingt ans plus tard, les patterns n'ont pas bougé. CQRS et l'Event Sourcing, qu'il salue dans les remerciements, ont renforcé DDD plutôt que de l'obsoléter. Les Bounded Contexts sont devenus le vocabulaire naturel des microservices. L'Anticorruption Layer décrit exactement ce qu'on fait quand on consomme une API legacy.
Le problème, c'est ce qui manque : les histoires. Le Blue Book original fait 560 pages remplies de cas concrets, d'exemples qui ratent, de refactorings progressifs. Cette Reference donne le vocabulaire sans la grammaire. On peut dire "Aggregate Root" sans forcément savoir quand délimiter un aggregate, ni pourquoi cette délimitation fait toute la différence.
Cela dit, la Reference est gratuite, courte, et couvre les 30 patterns en 59 pages sans digressions. C'est exactement ce qu'on attend d'une référence.
DDD a profondément influencé Symfony :
- Entités Doctrine : implémentent le pattern Entity (identité de persistance via un ID).
- Form Objects : peuvent être des Value Objects.
- Repositories : sont des citoyens de première classe avec leur propre interface.
Le composant Messenger implémente naturellement les Domain Events. Les concepts de cette Reference ne sont pas des abstractions théoriques : ce sont les mots derrière les frameworks que vous utilisez déjà au quotidien.
Lisez-le si
- Vous travaillez sur un projet à logique métier complexe et cherchez un vocabulaire commun pour l'équipe
- Vous avez croisé "bounded context" ou "aggregate root" quelque part et voulez la source primaire
- Vous voulez une référence d'une heure, sous licence libre, partageable sans restrictions
- Vous connaissez déjà DDD et avez besoin d'un aide-mémoire pour rafraîchir la taxonomie
Passez si
- Vous débutez complètement en DDD : la Reference sans le livre, c'est l'index sans les chapitres
- Vous faites du CRUD simple sans logique métier : DDD a un coût d'entrée non négligeable
- Vous voulez des exemples travaillés et des études de cas concrètes : c'est le Blue Book original ou Implementing Domain-Driven Design (IDDD) de Vernon
Pour aller plus loin
- PDF gratuit (CC BY 4.0) : domainlanguage.com/ddd/reference
- Pour apprendre DDD avant de revenir à la Reference : Implementing Domain-Driven Design de Vaughn Vernon (le Big Red Book), plus accessible que le Blue Book original
- Sur ce site : Clean Architecture (inversion de dépendances) et Software Architecture: The Hard Parts (context mapping en pratique) s'appuient directement sur le vocabulaire DDD
Commentaires (0)