Introduction
L'event sourcing révolutionne la façon dont on modélise les données dans les applications complexes, en stockant non pas l'état final d'un objet, mais la séquence d'événements qui l'ont conduit à cet état. Imaginez un compte bancaire : au lieu de ne garder que le solde actuel (500€), vous archivez chaque transaction – dépôt de 1000€, retrait de 300€, etc. – pour recalculer le solde à tout moment.
Pourquoi adopter cette approche en 2026 ? Les systèmes distribués explosent en complexité avec le cloud natif et l'IA. L'event sourcing offre une traçabilité infinie, une résilience aux pannes (replay d'événements), et une scalabilité horizontale via des projections asynchrones. Il s'intègre parfaitement au CQRS (Command Query Responsibility Segregation) et au Domain-Driven Design (DDD), patterns incontournables pour les microservices.
Ce tutoriel intermédiaire, purement conceptuel, vous équipe pour concevoir des architectures événementielles robustes. Sans un seul ligne de code, nous disséquons la théorie avec des analogies concrètes, des études de cas réels (comme chez Netflix ou Uber), et des frameworks pratiques. À la fin, vous saurez quand et comment l'implémenter pour des gains mesurables : réduction de 40% des downtimes et audits instantanés. Prêt à transformer vos données en histoire vivante ? (248 mots)
Prérequis
- Connaissances solides en Domain-Driven Design (DDD) : aggrégats, entités, bounded contexts.
- Familiarité avec les patterns CQRS et bases de données NoSQL (pour projections).
- Expérience en modélisation de domaines métier complexes (e-commerce, finance).
- Notions d'architecture événementielle (pub/sub, Kafka-like streams).
Fondations : Qu'est-ce que l'event sourcing ?
L'event sourcing repose sur un principe simple : tout changement d'état est un événement immuable. Contrairement au CRUD traditionnel où l'on écrase l'état (UPDATE table SET balance=500), on append only : on ajoute un événement au journal.
Analogie : Comme un film VHS. L'état courant est la frame actuelle ; pour revenir en arrière, on rembobine et rejoue les frames (événements). Étude de cas : Chez EventStoreDB (outil leader), un agrégat 'Commande' stocke [CommandeCree], [ArticleAjoute], [PaiementEchoue]. Le solde se calcule en fold/replay : état = fold(événements, état_initial).
Avantages immédiats :
- Audit parfait : Qui a fait quoi, quand ? Pas de 'magie' dans les données.
- Temporalité : États à toute date via replay partiel.
- Debugging : Reproduire un bug en rejouant jusqu'au point de défaillance.
Dans un e-commerce, une 'Panier' passe de {} à {produit1:2} via [PanierInitialise], [ProduitAjoute]. Pas d'UPDATE, juste append. Cela force une modélisation domaine-centrée, alignée DDD. (212 mots)
Différences avec les approches CRUD classiques
CRUD vs Event Sourcing : Tableau comparatif pour clarifier.
| Aspect | CRUD | Event Sourcing |
|---|---|---|
| -------- | ------ | ---------------- |
| Stockage | État final (mutable) | Séquence d'événements (immuable) |
| Query | Directe sur DB | Projections matérialisées |
| Historique | Logs séparés (perte possible) | Natif, replayable |
| Scalabilité | Verrouillages ACID | Événements partitionnés |
| Complexité | Simple pour OLTP basique | Élevée, mais puissante pour OLAP |
UPDATE stock SET qty=10 WHERE id=1. Problème : 'Pourquoi 10 ?' Event Sourcing : [StockInitialise:100], [Vente: -20], [Restock: +30] → qty=110. Pour query 'stock actuel', on projette en vue SQL.
Migration hybride : Commencez par dual-write (CRUD + events), puis migrez vers pure event sourcing. Chez Amazon, cela a réduit les incohérences de 60% dans les inventaires distribués. L'event sourcing brille quand les règles métier évoluent : nouveau calcul de solde ? Juste nouveau projecteur, sans toucher le journal source. (198 mots)
Composants clés de l'architecture
Un système event sourcing s'articule autour de 4 piliers :
- Event Store : Journal append-only (EventStoreDB, Kafka). Événements : {id, aggregateId, type, data, timestamp, metadata}.
- Command Side : Reçoit commandes (CreateOrder), valide via aggrégat, émet événements.
- Projections : Lecteurs souscrivent au stream, matérialisent vues (MongoDB pour queries rapides).
- Snapshots : États périodiques pour accélérer replay (tous les 1000 events).
Flux : Commande → Aggrégat (load snapshot + replay) → Événements → Event Store → Projections async. Garantit éventual consistency, idéal microservices. (187 mots)
Cycle de vie d'un agrégat événementiel
Étape par étape :
- Chargement : Récupérer snapshot + événements depuis lastVersion.
- Application commande : Aggrégat.apply(commande) → génère nouveaux événements.
- Validation : Vérifier invariants (ex: solde >=0 avant Retrait).
- Persistance : Append batch d'événements avec version incrémentale (optimistic concurrency).
- Publication : Notifier projecteurs via pub/sub.
Cas complexe : 'Réservation Hôtel'. Événements : [ChambreReservee], [Annulee], [ReReservee]. Invariant : max 1 réservation active. Commande 'Annuler' : si active, émettre [Annulee]. Replay garantit cohérence. Chez Netflix, cela gère billing avec 0% perte de revenus lors de rollbacks. (192 mots)
Projections et séparation CQRS
Les projections transforment le journal en modèles de lecture optimisés. CQRS sépare writes (events) de reads (vues).
Types :
- Live projections : Temps réel (dashboards).
- Ad-hoc : Queries ponctuelles (replay jusqu'à date).
- Matérialisées : DB dénormalisées (Elasticsearch pour search).
Framework pratique :
- Définir projecteurs : Pour 'OrderSummary', sur [OrderCreated] → insert {id, total}.
- Tolérance : Si projecteur crash, il reprend du dernier checkpoint.
Étude Booking.com : Projections pour analytics (taux conversion) scalent à 10k/sec sans impacter writes. Inconvénient : Lag éventuel (secondes), compensé par UX (squelettes loading). En 2026, avec event streaming natif (Kafka Streams), les projections serverless deviennent standard. (178 mots)
Bonnes pratiques essentielles
- Événements petits et atomiques : Un événement = un fait métier unique (pas [OrderUpdated] générique).
- Versioning des événements : Ajoutez v2 en parallèle (schema evolution sans downtime).
- Snapshots intelligents : Tous les 500-1000 events, ou par taille (1MB).
- Idempotence : Projecteurs gèrent duplicates via eventId unique.
- Bounded Contexts DDD : Un store par context (évite monolithe event stream).
Erreurs courantes à éviter
- Sur-modélisation : Ne pas event-sourcer tout (seulement aggrégats riches). Piège : perf plombe pour lookups simples → hybride CRUD.
- Événements anémiques : Data minimale seulement (ex: {qty:2}, pas UI state).
- Ignore concurrency : Sans version check, race conditions → utilisez expectedVersion.
- Projections synchrones : Bloque writes → toujours async avec dead-letter queues.
Pour aller plus loin
Plongez dans les outils : EventStoreDB, Axon Framework, Kafka pour streams.
Études avancées :
Formations expertes : Découvrez nos formations Learni sur l'architecture événementielle pour hands-on avec DDD + Event Sourcing.