Domain Event
Le fait métier figé dans le temps qui devient la frontière temporelle entre bounded contexts — base de toute architecture event-driven sérieuse.
Problème
Un hub EDI reçoit un INVOIC d'un partenaire. Trois équipes indépendantes en ont besoin : la finance pour comptabiliser, la logistique pour libérer le paiement, l'audit pour archiver 10 ans avec signature. Si le service de réception appelle directement les trois (HTTP synchrone), il connaît leur existence et leur API. Une nouvelle équipe (machine learning, conformité fiscale) doit être branchée explicitement à chaque fois. Pire : si la finance tombe, la réception bloque. On a recréé un monolithe distribué via HTTP.
Forces
- Les conséquences d'un fait métier sont multiples. Une facture reçue déclenche compta, paiement, archivage, KPI, détection de fraude.
- Le producteur ne doit pas connaître les consommateurs. Sinon, ajouter un consommateur impose de modifier le producteur.
- Les consommateurs ont des cadences différentes. Compta = temps réel ; KPI = batch quotidien ; ML = trimestriel.
- L'historique métier est précieux. Une facture reçue le 12 mai à 14h32 reste vraie même si on rejoue le système 6 mois plus tard.
Solution
Modéliser le fait métier comme un Domain Event
immuable nommé au passé : InvoiceReceived, OrderApproved, ShipmentDispatched. Le
producteur émet l'événement sur un bus (Kafka, AWS EventBridge,
NATS), avec un identifiant unique, un horodatage signé, et une
charge utile portant les données nécessaires à la consommation
autonome. Les consommateurs s'abonnent. Ajouter un consommateur n'a
aucun impact sur le producteur. Les événements sont persistés —
rejouables — et peuvent fonder l'Event
Sourcing.
{
"type": "InvoiceReceived",
"eventId": "01H...ULID",
"occurredAt": "2026-05-16T08:30:12.345Z",
"aggregateId": "invoice-INV-2026-0001234",
"aggregateVersion": 1,
"payload": {
"invoiceNumber": "INV-2026-0001234",
"supplierId": "GLN-3010234567890",
"buyerId": "GLN-3060987654321",
"amount": { "value": 12500.00, "currency": "EUR" },
"issueDate": "2026-05-15",
"dueDate": "2026-06-14"
},
"metadata": {
"source": "edi.parser.edifact",
"traceId": "00-abc...-01"
}
}
Implémentation EDI
Cas concret : le parser EDIFACT reçoit un INVOIC, valide
syntaxe/sémantique, et publie InvoiceReceived sur
Kafka edi.events.v1. Trois consumers indépendants :
(1) le service compta qui crée une écriture, (2) le service archive
qui signe en XAdES et range dans S3 Object Lock 10 ans, (3) le
service notification qui prévient le client par email. Si demain
on ajoute un service de détection de fraude ML, on crée un nouveau
consumer : le parser n'est pas touché. Les événements sont
versionnés (InvoiceReceived.v1, InvoiceReceived.v2) pour gérer les évolutions de
schéma. Le pattern Outbox
sert à publier l'événement atomiquement avec le commit DB. Apache
Camel, Spring Modulith, Axon Framework outillent ce pattern en
Java ; EventCatalog documente
les schémas.
Anti-patterns
- Events nommés au présent.
SendInvoiceouCreateInvoicesont des commandes, pas des événements. Confondre commande et événement crée du couplage déguisé. - Events trop fins (CRUD événements).
InvoiceFieldUpdatedà chaque champ : bruit, perte de sens métier. ÉmettreInvoiceCorrectedavec le nouveau snapshot métier. - Events trop riches. Si la charge utile contient tout l'état possible, on revient à une bibliothèque partagée. Le consumer doit pouvoir l'utiliser tout en demandant des compléments via API si besoin (Content Enricher).
- Events tributaires de l'infrastructure.
KafkaMessageReceivedouJmsMessageDeliveredne sont pas des événements métier. Ils peuvent être utiles techniquement mais ne portent pas le sens domaine.
Patterns liés
- Event Message — la brique EIP du transport d'événement.
- Event Sourcing — la persistance du journal d'événements comme source de vérité.
- Saga Choreography — le couplage faible entre contextes via domain events.
- Outbox — pour publier l'event atomiquement avec le commit DB.
- Bounded Context — les domain events traversent les contextes en racontant leur histoire.
Sources
- Evans E. — Domain-Driven Design, Addison-Wesley 2003. Concept fondateur ; développé dans les éditions ultérieures et par la DDD community.
- Fowler M. — Domain Event (martinfowler.com, 2005). La définition pédagogique. martinfowler.com — DomainEvent
- Vernon V. — Implementing Domain-Driven Design, Addison-Wesley 2013. Chap. 8 « Domain Events » avec exemples Java.
- Microsoft Architecture Center — Domain events: design and implementation. Le pattern transposé .NET. learn.microsoft.com — Domain events
- CloudEvents spec. Le standard CNCF pour la sérialisation d'événements inter-systèmes. cloudevents.io