Event Sourcing
Stocker l'historique complet des faits métier, pas l'état courant — et accepter que l'état n'est qu'une projection du journal.
Problème
L'EDI produit naturellement un flux d'événements métier (ORDERS, ORDRSP, DESADV, INVOIC, REMADV) qui s'enchaînent dans le temps. Un système modélisé en CRUD (« mettre à jour la commande à l'état expédiée ») perd cette traçabilité fine et rend difficile l'audit, le rejeu et l'investigation d'incident.
Forces
- L'audit est exigé en EDI — preuve fiscale 10 ans, conformité douanière, traçabilité réglementaire. Stocker l'historique brut est une fonctionnalité, pas une charge.
- Les événements métier sont la vérité. L'état n'est qu'un cache local et reconstructible.
- Le rejeu permet l'évolution de modèle. Quand le schéma change, on rejoue l'historique pour reconstruire la projection nouvelle.
- Le coût de stockage est faible. Un log compressé d'événements métier coûte un ordre de grandeur moins qu'un data lake équivalent dénormalisé.
Solution
Tout fait métier dérivé d'un message EDI entrant ou sortant est persisté comme événement immuable dans un journal append-only (Kafka, EventStoreDB, table append-only PostgreSQL). L'état courant d'une entité (commande, expédition, facture) est calculé en rejouant les événements qui la concernent. Les projections sont matérialisées dans des tables de lecture (read models) optimisées par cas d'usage — l'écran exploitant, l'API partenaire, le data lake BI tirent chacun leur vue de la même source de vérité.
# event-log topic
2026-05-14T08:31Z OrderReceived { orderId: ORD789, lines: [...] }
2026-05-14T08:42Z OrderAcknowledged { orderId: ORD789, status: "accepted" }
2026-05-15T07:11Z ShipmentDispatched { orderId: ORD789, asn: ASN9001 }
2026-05-15T15:02Z GoodsReceived { orderId: ORD789, asn: ASN9001 }
2026-05-15T17:30Z InvoiceIssued { orderId: ORD789, invoice: INV-7811 }
2026-05-20T09:00Z PaymentRemitted { orderId: ORD789, invoice: INV-7811, amount: 1240.00 } Implémentation EDI
Cas typique en hub EDI : chaque message reçu est traduit en
événement métier (OrderReceived, ShipmentDispatched, InvoiceIssued,
PaymentRemitted) publié sur un topic Kafka edi.events.orders partitionné par orderId.
Le projecteur ERP consomme et matérialise une table orders ; le projecteur audit alimente un index
fiscal ; le projecteur partenaire publie un statut JSON dans une
API REST. Sur incident (« j'ai perdu une commande »), le
rejeu du topic recompose l'état à n'importe quel instant —
impossible avec un CRUD classique.
Anti-patterns
- Stocker l'état dans l'événement. L'événement doit porter le fait, pas la projection. Mettre l'état complet annule le bénéfice.
- Pas de versionnement des événements. Quand le schéma
change après 18 mois, on ne peut plus rejouer : il faut un
eventVersiondès le premier sprint. - Compactage agressif. Supprimer les vieux événements perd la possibilité d'audit historique — proscrit en EDI fiscal.
- Couplage projecteur / event store. Le projecteur doit pouvoir être ajouté, supprimé, rejoué sans impact sur la source de vérité.
- Event Sourcing partout. Pour un petit annuaire partenaires statique, CRUD reste plus simple. ES s'applique aux entités à cycle de vie riche, pas aux tables de référence.
Patterns liés
- CQRS — Event Sourcing s'accompagne presque toujours de CQRS.
- Message Store — l'équivalent EIP appliqué au journal.
- Change Data Capture — l'alternative non-intrusive pour les systèmes legacy qu'on ne peut pas réécrire.
Sources
- Fowler M. — Event Sourcing, martinfowler.com, 2005. martinfowler.com/eaaDev/EventSourcing.html
- Young G. — CQRS Documents, 2010. Le compagnon canonique d'Event Sourcing. cqrs_documents.pdf
- Kleppmann M. — Designing Data-Intensive Applications, O'Reilly 2017, chap. 11 sur les systèmes log-based.
- EventStoreDB documentation — l'implémentation open-source de référence. eventstore.com/event-sourcing