Bounded Contexts : Guide Complet de Mise en Œuvre
Comment identifier, concevoir et implémenter des bounded contexts efficaces dans des domaines complexes. Patterns stratégiques, techniques de context mapping et exemples concrets.
L'Ubiquitous Language (langage omniprésent) est sans doute l'un des concepts les plus sous-estimés du Domain-Driven Design. Pourtant, c'est la fondation sur laquelle repose toute implémentation DDD réussie.
Voici une méthode éprouvée pour construire et maintenir un langage partagé efficace.
Dans la plupart des projets, on observe un phénomène de "traduction" permanente :
Chaque traduction introduit des distorsions et des malentendus.
L'Ubiquitous Language vise à créer un vocabulaire partagé qui :
Participants essentiels :
Matériel nécessaire :
🟠 Événements métier
🟦 Commandes
🟡 Acteurs/Utilisateurs
🟪 Systèmes externes
🟢 Read Models/Vues
🔴 Points chauds/Problèmes
Règles de l'atelier :
Exemple concret d'ambiguïté découverte :
"Commande" peut signifier :
- 📋 Purchase Order (bon de commande du client)
- 📦 Work Order (ordre de fabrication interne)
- 🚚 Delivery Order (bon de livraison)
💡 Résolution :
- CustomerOrder
- ProductionOrder
- ShipmentOrder
Pour chaque terme identifié, créez une définition collaborative :
Template de définition :
Terme: CustomerOrder
Définition: Une demande d'achat formalisée émise par un client
pour l'acquisition de produits spécifiques
Synonymes: Purchase Order, Commande Client
Contexte: Utilisé dans le processus de vente depuis la création
jusqu'à la facturation
Exemple: "CustomerOrder #12345 contient 3 widgets à 50€ chacun"
// ❌ Code qui ne reflète pas l'Ubiquitous Language
public class Order
{
public List<Item> Items { get; set; }
public decimal Price { get; set; }
public string Status { get; set; }
}
// ✅ Code qui reflète l'Ubiquitous Language
public class CustomerOrder
{
public OrderNumber Number { get; private set; }
public List<OrderLine> Lines { get; private set; }
public Money TotalAmount { get; private set; }
public OrderStatus Status { get; private set; }
public void AddOrderLine(Product product, Quantity quantity)
{
// Logique métier avec les termes du domaine
if (Status != OrderStatus.Draft)
throw new OrderNotModifiableException(
"Cannot modify a confirmed CustomerOrder");
}
}
// Les invariants utilisent le vocabulaire métier
public class CustomerOrder
{
public void ConfirmOrder()
{
if (Lines.Count == 0)
throw new EmptyOrderCannotBeConfirmedException();
if (!Customer.HasValidCreditLimit(TotalAmount))
throw new InsufficientCreditLimitException();
Status = OrderStatus.Confirmed;
RaiseEvent(new CustomerOrderConfirmed(Number, Customer.Id));
}
}
Maintenez un glossaire partagé qui évolue :
# Glossaire Domaine E-commerce
## CustomerOrder (Commande Client)
**Définition :** Demande d'achat formalisée par un client
**Statuts possibles :** Draft, Confirmed, Cancelled, Fulfilled
**Règles métier :**
- Une CustomerOrder en statut Confirmed ne peut plus être modifiée
- Le montant total ne peut pas dépasser la limite de crédit du client
## OrderLine (Ligne de Commande)
**Définition :** Article individuel dans une CustomerOrder
**Propriétés :** Product, Quantity, UnitPrice, LineTotal
**Règles métier :**
- La quantité doit être positive
- Le prix unitaire doit correspondre au tarif actuel du produit
Fréquence recommandée : Toutes les 2-3 sprints
Format de session (1h) :
Signaux d'alarme :
Complément à l'Event Storming pour capturer les processus :
👤 Customer ➜ 📝 creates ➜ 🛒 CustomerOrder
🛒 CustomerOrder ➜ 📧 triggers ➜ 📨 OrderConfirmationEmail
👨💼 SalesRep ➜ ✅ validates ➜ 🛒 CustomerOrder
🛒 CustomerOrder ➜ 🔄 becomes ➜ 📦 ProductionOrder
Tracez l'impact des changements de vocabulaire :
Changement: "Order" → "CustomerOrder"
Impact:
├── Code
│ ├── 15 classes à renommer
│ ├── 45 méthodes à adapter
│ └── 120 tests à mettre à jour
├── Documentation
│ ├── API documentation
│ └── User stories
└── Formation
└── Équipe développement (2h)
[Fact]
public void CustomerOrder_WhenConfirmed_CannotBeModified()
{
// Given - Un CustomerOrder confirmé
var order = CustomerOrderBuilder
.WithOrderLines(Product.Widget, Quantity.Of(5))
.InStatus(OrderStatus.Confirmed)
.Build();
// When - On tente d'ajouter une ligne
var action = () => order.AddOrderLine(Product.Gadget, Quantity.Of(2));
// Then - Une exception métier est levée
action.Should().Throw<OrderNotModifiableException>()
.WithMessage("Cannot modify a confirmed CustomerOrder");
}
Métriques quantitatives :
Métriques qualitatives :
// Lint rule personnalisée
const forbiddenTerms = [
{ forbidden: 'Order', preferred: 'CustomerOrder' },
{ forbidden: 'Item', preferred: 'OrderLine' },
{ forbidden: 'Price', preferred: 'Money' }
];
// Vérifie que le code respecte l'Ubiquitous Language
function validateUbiquitousLanguage(codeFile: string): ValidationResult {
const violations = forbiddenTerms
.filter(term => codeFile.includes(term.forbidden))
.map(term => `Use '${term.preferred}' instead of '${term.forbidden}'`);
return {
isValid: violations.length === 0,
violations
};
}
Problème : "On a toujours appelé ça comme ça" Solution : Montrer l'impact business des malentendus actuels
Problème : Trop de nouveaux termes d'un coup Solution : Introduction progressive, focus sur les concepts centraux
Problème : Chaque équipe développe son propre vocabulaire Solution : Sessions de synchronisation inter-équipes régulières
L'Ubiquitous Language n'est pas un exercice académique, c'est un outil pratique qui :
Points clés à retenir :
L'investissement en temps pour construire un Ubiquitous Language solide est toujours rentabilisé par la réduction des malentendus et l'amélioration de la vélocité d'équipe.
Comment identifier, concevoir et implémenter des bounded contexts efficaces dans des domaines complexes. Patterns stratégiques, techniques de context mapping et exemples concrets.