Pourquoi le DDD aujourd'hui
Le Domain-Driven Design (DDD), formalisé par Eric Evans en 2003, n'est pas une mode : c'est une discipline d'ingénierie pensée pour les systèmes complexes, ceux où la logique métier dépasse largement le CRUD. En 2026, la majorité des SaaS B2B tombent dans cette catégorie, multi-tenant, facturation à l'usage, workflows réglementés, intégrations tierces, IA dans la boucle.
Quand on parle de « logiciel qui tient en production », le DDD répond à trois questions concrètes : où mettre la règle métier, comment la faire évoluer sans tout casser, et comment la rendre lisible par l'équipe (et par soi-même dans six mois).
Le langage ubiquitaire, brique zéro
Le DDD commence avant le code. C'est un accord explicite entre devs et experts métier sur les mots. Un « contrat » dans le back-office juridique n'a pas le même cycle de vie qu'un « contrat » côté facturation. Si l'équipe n'a pas tranché, le code traduira la confusion, et la dette s'accumulera silencieusement.
Concrètement : on tient un glossaire vivant (Notion, README, peu importe) avec les termes, leurs définitions, et leur contexte. Ce glossaire est référencé dans les noms de modules, de classes, de tables, d'événements.
Bounded contexts : découper avant d'architecturer
Le piège classique d'un SaaS qui grossit : un seul modèle User partagé par l'auth, la facturation, le support, l'analytics. Au bout de 18 mois, modifier ce modèle devient un acte de courage. Le DDD propose de découper par contexte métier, chaque contexte a son propre modèle, son propre langage, sa propre base éventuellement.
Pour un SaaS de pige automobile (cas réel chez Synapz), on isole typiquement :
- Identity & Access, comptes, organisations, rôles, sessions.
- Sourcing, flux d'annonces, dédoublonnage, scoring IA.
- Workspace, favoris, alertes, collaboration équipe.
- Billing, abonnements, quotas, factures.
Chaque contexte expose un contrat minimal aux autres : API interne, événements, ID externes. C'est ce qui permet à 2-3 devs de bouger en parallèle sans se marcher dessus.
Aggregates, entities, value objects
Dans un bounded context, on identifie les agrégats : des clusters d'objets traités comme une unité transactionnelle. Règle d'or : un agrégat = une frontière de cohérence. Si deux objets doivent être modifiés ensemble dans une seule transaction, ils appartiennent au même agrégat.
À l'intérieur, on distingue :
- Entities, objets avec une identité stable (un
Subscription, unLead). - Value objects, objets immuables définis par leurs valeurs (
Money,EmailAddress,DateRange). Pas d'ID, comparables par valeur, ultra-testables.
Le gain concret : la logique métier vit dans les objets, pas dispersée dans des services anémiques. Un Invoice.markAsPaid() garantit l'invariant ; unInvoiceService.markAsPaid(invoice) ne garantit rien.
Architecture hexagonale et ports/adapters
Le DDD se marie naturellement avec l'architecture hexagonale (ou « ports & adapters »). Le domaine est au centre, isolé du framework, de la base, des APIs tierces. Tout ce qui est I/O passe par des ports (interfaces) implémentés par des adapters (PostgreSQL, Stripe, OpenAI, etc.).
Résultat pratique : on peut tester le domaine sans base de données, swapper Stripe pour Paddle sans toucher à la logique métier, et déployer en serverless ou en monolithe selon la charge. La stack devient un détail d'implémentation, pas un facteur de couplage.
Événements de domaine et intégration entre contextes
Les bounded contexts communiquent par événements de domaine :OrderPlaced, SubscriptionRenewed, LeadQualified. Le contexte émetteur ignore qui écoute ; le contexte récepteur réagit à son rythme.
Sur la stack Node.js / TypeScript que Synapz utilise en production : on publie via une queue (SQS, Redis Streams, PostgreSQL outbox pattern) et on consomme côté abonné. L'outbox pattern est crucial pour garantir l'atomicité « écriture base + publication événement ».
CQRS, quand ça vaut le coup
Le CQRS sépare les modèles d'écriture et de lecture. Le modèle d'écriture protège les invariants ; le modèle de lecture est optimisé pour l'UI (projections dénormalisées, vues matérialisées, index dédiés).
Ce n'est pas systématique. Sur un CRUD simple, c'est de la complexité gratuite. Sur un dashboard avec 20 widgets agrégeant 6 tables, un modèle de lecture dédié évite des JOINs catastrophiques et des bugs de cohérence.
Anti-patterns fréquents
- Anemic Domain Model, entities avec uniquement des getters/setters, toute la logique dans des « services ». C'est du procédural déguisé en objet.
- God Aggregate, un agrégat qui contient la moitié du domaine et qu'on ne peut plus charger sans 12 jointures.
- Leaky abstractions, un repository qui retourne des entités ORM exposant lazy-loading, transactions, et tout le bazar à la couche application.
- Premature DDD, appliquer tout le bouquin sur un MVP de 3 écrans. Le DDD coûte ; il le rend sur la durée.
Quand NE PAS faire de DDD
Le DDD est cher en cadrage et en discipline. Il n'a pas sa place sur :
- Un prototype jetable ou un POC court.
- Un outil interne CRUD pur, sans règle métier complexe.
- Une équipe d'un seul dev sur un projet de moins de 6 mois.
En revanche, dès qu'il y a plusieurs experts métier, plusieurs équipes, ou un horizon supérieur à 2 ans, le DDD devient rentable très vite.
Stack et outils que nous utilisons
Chez Synapz, le DDD ne dépend pas d'un framework magique. Notre socle type :
- TypeScript strict, types comme premier outil de modélisation.
- Node.js (Fastify ou Hono) côté API, avec une couche application fine au-dessus du domaine.
- PostgreSQL avec repository pattern + outbox pour les événements ; Prisma ou Kysely comme adapter, jamais comme modèle.
- Vitest pour des tests unitaires du domaine ultra-rapides (sans base, sans réseau).
- Zod aux frontières (HTTP, jobs, événements) pour ne jamais laisser entrer de donnée invalide dans le domaine.
Questions fréquentes
- Le DDD, c'est réservé aux gros systèmes ?
- Non, mais son coût de mise en place ne se rentabilise que sur des domaines à vraie complexité métier (règles multiples, plusieurs experts, horizon >2 ans). Sur un CRUD simple ou un POC, c'est de la complexité gratuite.
- Faut-il faire du CQRS et de l'event sourcing pour faire du DDD ?
- Non. Le DDD stratégique (bounded contexts, langage ubiquitaire) et tactique (agrégats, value objects) sont indépendants de CQRS et event sourcing. On les introduit uniquement quand un besoin concret le justifie.
- Quelle stack recommandez-vous pour appliquer le DDD ?
- Chez Synapz : TypeScript strict, Node.js (Fastify/Hono), PostgreSQL avec repository pattern + outbox, Zod aux frontières, Vitest pour les tests de domaine. Le DDD ne dépend pas d'un framework, c'est une discipline de modélisation.
- Comment découper mes bounded contexts ?
- Par capacité métier, pas par entité technique. Un atelier EventStorming avec les experts métier révèle les frontières naturelles (là où le vocabulaire change, là où les responsabilités changent). Un contexte = une équipe autonome idéalement.
- DDD et microservices, même combat ?
- Non. Un bounded context peut vivre dans un monolithe modulaire. Les microservices sont un choix de déploiement ; les bounded contexts sont un choix de modélisation. Commencer par un monolithe bien découpé est presque toujours la bonne décision.
Pour aller plus loin
- Eric Evans, Domain-Driven Design: Tackling Complexity in the Heart of Software.
- Vaughn Vernon, Implementing Domain-Driven Design.
- Alberto Brandolini, EventStorming, l'atelier qui débloque le découpage en contextes.