Bounded contexts¶
Découper le domaine en zones de cohérence — la decomposition fonctionnelle qui précédé tout choix de topologie.
Le concept¶
Quelle que soit la topologie choisie — monolithe modulaire ou microservices — la decomposition fonctionnelle suit les mêmes règles. Le concept clé est le bounded context (contexte delimite), issu du Domain-Driven Design strategique.
Un bounded context est une frontiere explicite à l'intérieur de laquelle un modèle métier est cohérent et unifie. Le même mot peut avoir un sens différent dans deux contextes différents : un Produit dans le contexte Catalog (fiche technique, photos) n'est pas le même que dans le contexte Orders (prix, disponibilité) ni dans Shipping (dimensions, poids).
Cette ambiguite semantique n'est pas un bug — c'est un signal. Quand un même terme désigne des concepts différents selon le département ou l'équipe, on est en présence de bounded contexts distincts. Forcer un modèle unique pour satisfaire tous les usages crée un "God Object" qui porte trop de responsabilités et que tout le monde modifie.
graph LR
subgraph Catalog["Catalog Context"]
CAT_P["Product\n(fiche, photos, attributs)"]
end
subgraph Orders["Orders Context"]
ORD_P["Product\n(prix, SKU, dispo)"]
ORD_O["Order"]
ORD_O --> ORD_P
end
subgraph Shipping["Shipping Context"]
SHP_P["Product\n(dimensions, poids)"]
SHP_S["Shipment"]
SHP_S --> SHP_P
end
Catalog -->|"Shared Kernel\n(ProductId)"| Orders
Orders -->|"Customer-Supplier\n(OrderConfirmed)"| Shipping
Shipping -.->|"Anti-Corruption Layer"| EXT["Carrier API\n(externe)"] Chaque contexte possédé son propre Product, avec uniquement les attributs pertinents pour ses opérations. Les contextes communiquent via des identifiants partages (Shared Kernel) ou des événements (Intégration Events), jamais par un accès direct aux données internes d'un autre contexte.
Identifier les bounded contexts¶
L'identification des bounded contexts est un exercice collaboratif entre développeurs et experts métier. Quatre heuristiques guident le travail.
1. Ambiguite semantique¶
Chercher les mots qui changent de sens selon le contexte. Si le mot "Client" désigne un prospect pour l'équipe marketing, un acheteur pour l'équipe ventes, et un identifiant technique pour l'équipe support, il y a trois bounded contexts.
2. Frontieres organisationnelles¶
Conway's Law fait que les frontieres organisationnelles et techniques convergent. Les équipes qui travaillent independamment sur des sujets distincts sont souvent des bounded contexts naturels. Observer qui parle a qui et à quelle fréquence révélé la structure réelle du domaine.
3. Anti-patterns dans les données¶
Chercher les tables qui sont jointurees de partout. Un modèle de données "central" est un anti-pattern de bounded context. Quand une table products a 80 colonnes dont 30 ne sont utilisées que par un seul module, cette table porte les responsabilités de plusieurs contextes.
4. Event Storming¶
L'Event Storming (Alberto Brandolini) est un atelier collaboratif ou les participants identifient les événements métier (ce qui se passe), puis les regroupent en clusters. Ces clusters révèlent les bounded contexts.
graph LR
subgraph "Cluster 1 : Catalog"
E1["ProductCreated"]
E2["ProductUpdated"]
E3["CategoryChanged"]
end
subgraph "Cluster 2 : Orders"
E4["CartCreated"]
E5["OrderPlaced"]
E6["OrderConfirmed"]
end
subgraph "Cluster 3 : Payments"
E7["PaymentRequested"]
E8["PaymentProcessed"]
E9["RefundIssued"]
end
E6 -->|"trigger"| E7 L'Event Storming produit une carte des événements métier en quelques heures. C'est l'outil le plus efficace pour aligner développeurs et experts métier sur la structure du domaine.
Context mapping — les patterns de relation¶
Une fois les bounded contexts identifiés, il faut définir comment ils interagissent. Le context mapping de DDD propose sept patterns de relation, chacun avec des implications différentes sur le couplage et l'autonomie.
Shared Kernel¶
Deux contextes partagent un petit sous-modèle commun. Les équipes se coordonnent pour le faire évoluer.
Le Shared Kernel doit rester petit. S'il grossit, les contextes deviennent couples et la coordination entre équipes augmente. La règle : le Shared Kernel ne contient que des value objects immuables et des identifiants.
Customer-Supplier¶
Un contexte (le supplier) fournit des données ou services a un autre (le customer). Le supplier adapté son API selon les besoins du customer — la relation est collaborative.
Exemple : Catalog (supplier) fournit les informations produit
a Orders (customer). Catalog evolue son API en tenant
compte des besoins d'Orders.
Conformist¶
Le contexte aval adopte le modèle de l'amont sans negociation. L'amont ne s'adapté pas. On subit son modèle tel quel.
Exemple : Integrer un ERP existant dont on ne peut pas modifier l'API.
Le contexte interne se conforme au modele de l'ERP.
Le pattern Conformist est acceptable quand le coût d'un Anti-Corruption Layer dépassé le benefice. C'est un choix pragmatique, pas un défaut.
Anti-Corruption Layer (ACL)¶
Une couche de traduction isole le contexte interne du modèle externe. Le contexte interne garde son propre modèle, l'ACL traduit entre les deux.
graph LR
subgraph Interne["Contexte interne"]
M["Modele\ninterne"]
end
subgraph ACL["Anti-Corruption Layer"]
T["Translator"]
A["Adapter"]
end
subgraph Externe["Systeme externe"]
EXT["Modele\nexterne"]
end
M --> T
T --> A
A --> EXT L'ACL est le pattern le plus utilisé pour intégrer des systèmes legacy ou des APIs tierces. Il protégé le modèle interne de la contamination par des concepts externes. Le coût est une couche de code supplémentaire a maintenir, mais le benefice est l'independance du modèle interne.
Open Host Service¶
Un contexte expose une API publique bien documentee, stable, consommable par plusieurs contextes. C'est l'inverse du Customer-Supplier : l'API est générique, pas adaptée a un consommateur spécifique.
Exemple : Un service de paiement interne expose une API REST
versionee que tous les contextes utilisent.
Published Language¶
Un langage commun explicitement documente pour l'intégration. Des schémas d'événements (Avro, Protobuf), des formats de fichiers standardises, des protocoles documentes.
Exemple : Les evenements sur le bus Kafka utilisent des schemas Avro
versionnes. Un schema registry garantit la compatibilite.
Separate Ways¶
Deux contextes n'ont pas besoin de s'intégrer. Chacun géré sa propre version du concept, sans communication. C'est souvent le bon choix quand l'intégration couterait plus qu'elle ne rapporte.
Context map : vue d'ensemble¶
La context map est un diagramme qui représenté tous les bounded contexts et leurs relations. C'est l'artefact le plus important du DDD strategique.
graph TB
subgraph Core["Core Domain"]
CATALOG["Catalog\nContext"]
ORDERS["Orders\nContext"]
PRICING["Pricing\nContext"]
end
subgraph Supporting["Supporting Domain"]
SHIPPING["Shipping\nContext"]
NOTIF["Notification\nContext"]
LOYALTY["Loyalty\nContext"]
end
subgraph Generic["Generic Domain"]
AUTH["Auth\nContext"]
BILLING["Billing\nContext"]
end
subgraph External["Externe"]
CARRIER["Carrier\nAPI"]
PSP["Payment\nService Provider"]
end
CATALOG -->|"Shared Kernel\n(ProductId)"| ORDERS
CATALOG -->|"Customer-Supplier"| PRICING
ORDERS -->|"Customer-Supplier"| SHIPPING
ORDERS -->|"Published Language\n(events)"| NOTIF
ORDERS -->|"Published Language\n(events)"| LOYALTY
PRICING -->|"Open Host\nService"| ORDERS
SHIPPING -.->|"ACL"| CARRIER
BILLING -.->|"ACL"| PSP
AUTH ---|"Separate Ways"| NOTIF Cette carte se lit comme un plan de metro. Les lignes entre contextes indiquent le type de relation. Les contextes sans connexion (Separate Ways) sont volontairement isoles.
Exemple pratique : e-commerce¶
Un e-commerce typique decompose en bounded contexts :
| Bounded Context | Type | Responsabilité | Entités principales |
|---|---|---|---|
| Catalog | Core | Gestion des fiches produit, catégories, recherche | Product, Category, Attribute |
| Orders | Core | Cycle de vie des commandes | Order, OrderLine, Cart |
| Pricing | Core | Règles de prix, promotions, remises | PriceRule, Discount, Coupon |
| Payments | Generic | Traitement des paiements (délégué a un PSP) | Payment, Refund, Transaction |
| Shipping | Supporting | Expedition, suivi des colis | Shipment, TrackingEvent, Address |
| Inventory | Supporting | Gestion des stocks, reservation | Stock, Reservation, Warehouse |
| Notifications | Supporting | Emails, SMS, push notifications | Template, Channel, Recipient |
| Identity | Generic | Authentification, autorisations | User, Rôle, Permission |
| Loyalty | Supporting | Points de fidelite, avantages | LoyaltyAccount, Points, Reward |
Observations :
- Le
Productexiste dans Catalog (fiche), Orders (référence), Pricing (prix), Inventory (stock), Shipping (dimensions). Ce n'est pas de la duplication — ce sont des projections différentes du même concept physique, adaptées aux besoins de chaque contexte. - Les contextes Generic (Payments, Identity) sont des candidats à l'achat ou à l'intégration de SaaS (Stripe, Auth0). Investir du temps de développement sur un contexte Generic est rarement un bon usage des ressources.
- Les contextes Core (Catalog, Orders, Pricing) sont ceux ou l'avantage concurrentiel se joue. C'est la qu'on investit les meilleurs développeurs et le plus de temps de conception.
Bounded contexts et topologie¶
Les bounded contexts sont orthogonaux à la topologie. Un bounded context peut être :
- Un module dans un monolithe modulaire
- Un microservice
- Une fonction serverless
- Un ensemble de fonctions serverless
La frontiere est la même — seul le mécanisme de communication change (appel de fonction vs appel réseau vs événement).
La recommandation : dessiner les bounded contexts d'abord, choisir la topologie ensuite. Les contextes révèlent la structure naturelle du domaine. La topologie est une décision d'implémentation qui dépend du contexte organisationnel (taille d'équipe, maturité ops) et technique (volume, scalabilité).
Bounded context = unite de déploiement potentielle
Un bounded context bien delimite est un candidat naturel à l'extraction en service indépendant. Mais l'extraction n'est justifiee que quand un signal concret le demande (scalabilité differentielle, équipe autonome, technologie différente). Sans signal, le module dans le monolithe est suffisant.
Chapitre suivant : Integration de systèmes — topologies d'intégration, patterns EIP et ingénierie des systèmes.