TL;DR
- Unterschiedliches Verständnis: Bedeutung und Motivation von „Domain Event”, „ECST” und „ECST-Events” werden oft unterschiedlich verstanden und unscharf verwendet.
- ECST ist eine Eigenschaft von Events, kein eigener Event-Typ: Es sagt nur, ob ein Event alle Daten selbst mitbringt – Gegenpol ist die Event Notification, nicht der Domain Event.
- Zwei unabhängige Achsen: Fachlicher Auslöser vs. Zustand im Event ist etwas anderes als ECST vs. Event Notification oder ECST vs. Domain Event. Deshalb ist „ECST-Event” als Begriff irreführend.
- Besserer Name „Replication Event”: Es repliziert nur fremde Daten – ohne fachlichen Grund.
- Faustregel: Domain Event = auf fachliches Ereignis reagieren; Replication Event = fremde Daten zur Steigerung der Autonomie lokal vorhalten.
Als Software Architekt, DDD-Practitioner und Berater arbeite ich mit meinen Kunden normalerweise an komplexen Geschäftssystemen, welche mit Domain-Driven Design fachlich modularisiert und als Self-Contained Systems abgebildet werden. In dieser Tätigkeit erlebe ich bei Reviews von Architekturkonzepten, in Workshops zur Modularisierung und Integration und generell in Diskussionen immer wieder, dass Architekten und Entwickler Begriffe aus dem Kontext von DDD und Event-Driven Architecture verwenden, ohne ein gemeinsames Verständnis davon zu haben.
Man kann diesen Leuten nun Nachlässigkeit unterstellen, aber manchmal ist ein gemeinsames Verständnis auch deshalb schwierig, weil Konzepte und Begriffe mehrdeutig sind und sich die alltägliche Verwendung von der ursprünglichen Definition wegbewegt hat. Oder weil die ursprüngliche Motivation für die Entstehung und den Einsatz von spezifischen Konzepten nicht (mehr) bekannt ist.
Genau dies trifft aus meiner Sicht auf Domain Events, ECST (Event-Carried State Transfer) und den in der Praxis verbreiteten Begriff „ECST-Event” zu. In diesem Artikel soll es um genau diese Begriffe und deren Klärung (zumindest aus meiner Perspektive) gehen.
Domain Events
Domain Events sind das zentrale (wenn auch erst nachträglich eingeführte) Konzept für die Analyse der Fachlichkeit z.B. mittels Event Storming, für die explizite Modellierung dieser Fachlichkeit im Domain Model eines Bounded Context, aber auch für die Integration von Bounded Contexts untereinander. Durch Domain Events lässt sich die Fachlichkeit gut aus der dynamischen Sicht beschreiben (statt auf die statische Datensicht zu fokussieren), und jeder Domain Event steht für das Resultat der Wahrnehmung einer konkreten fachlichen Verantwortlichkeit innerhalb eines Bounded Contexts.
Ein „richtig” modellierter Domain Event hat eine hochwertige fachliche Semantik und erlaubt es dem Konsumenten zu verstehen, was beim Erzeuger des Domain Events passiert ist, so dass der Konsument im Rahmen seiner Fachlichkeit korrekt auf das Domain Event - innerhalb des gleichen Bounded Context, aber auch über Bounded Context-Grenzen hinweg - reagieren kann („immer wenn im Bounded Context „Registration” ein Kunde erfolgreich registriert wurde, muss im Bounded Context „Accounting” ein Wallet mit initialem Guthaben eröffnet werden”).
„ECST-Events”
Im Unterschied dazu stehen Events, welche nur den Zustand kommunizieren, der aufgrund der Fachlichkeit innerhalb eines Bounded Contexts neu entstanden ist oder verändert wurde (z.B. den Zustand des Aggregats „Kunde” nach der erfolgreichen Registrierung). Der fachliche Grund für die Veränderung wird dabei nicht kommuniziert, nur das Resultat nach der Veränderung.
Solche Events werden in der Praxis (zumindest meiner Wahrnehmung nach) oft als Abgrenzung zu Domain Events als „ECST-Events” bezeichnet. Der Begriff „ECST-Event” ist hier in mindestens zweierlei Hinsicht problematisch: zum einen ist er ursprünglich nicht so definiert worden, und zum anderen kommuniziert der Begriff sehr schlecht, für welchen Zweck diese Art von Events existiert.
ECST nach Fowler
Der Begriff ECST wurde von Martin Fowler 2017 in [1] beschrieben, sinngemäss als:
ECST: ein Ereignis trägt alle relevanten Zustandsdaten direkt mit sich, damit Konsumenten ihren lokalen Datensatz eigenständig aktualisieren können, ohne erneut beim Ursprungssystem nachfragen zu müssen.
Das Konzept beschreibt also einen Event, welcher allen Zustand bereits in sich trägt, der für die Verarbeitung des Events beim Konsumenten notwendig ist (welcher Zustand dies im konkreten Fall sein muss, ist eine Aufgabe der Modellierung bzw. des Context Mappings und ausserhalb des Scopes dieses Artikels). Der Konsument muss also nicht erneut zum Erzeuger des Events gehen und um zusätzliche Daten nachfragen.
Dies macht den Event nicht nur eigenständiger (der Event wird „selbstsprechender”), sondern erlaubt vor allem auch eine temporale Entkopplung des Konsumenten vom Produzenten zum Zeitpunkt der Verarbeitung des Events (der Konsument kann den Event verarbeiten, ohne dass der Erzeuger verfügbar sein muss). Wenn ein Konsument ein auf ECST-basierendes Event „Kunde registriert” empfängt, ist im Event bereits der ganze für den Konsumenten relevante Zustand des Kunden enthalten - und zwar genau zu dem Zeitpunkt, als der Event beim Erzeuger entstanden ist. Falls sich seit der Erzeugung des Events und der Verarbeitung des Events beim Konsumenten der Zustand des Kunden bereits geändert hat (z.B. weil der Kunde kurz nach der Registrierung bereits gesperrt wurde), dann verändert dies nicht den Zustand im Event, sondern erzeugt (möglicherweise) ein zweites Event „Kunde gesperrt” wiederum mit dem relevanten Zustand des Kunden.
Event Notification nach Fowler
Im Gegensatz dazu beschreibt Fowler im gleichen Artikel das Konzept der Event Notification, welches nur verwendet wird, um Konsumenten über das Auftreten einer Veränderung beim Erzeuger zu informieren, ohne dabei viel Kontext zur Änderung selbst als Teil der Event Notification mitzuliefern. In der Praxis wird typischerweise nur eine Referenz (eine Id) auf den veränderten Zustand mitgegeben, welche ein Konsument nutzen kann, um bei Bedarf mehr Daten nachzuladen.
Eine Event Notification selbst beschreibt also einen schmaleren Kontrakt zwischen Erzeuger und Konsument, bringt aber eine temporale Kopplung zum Zeitpunkt der Verarbeitung des Events (der Erzeuger muss gleichzeitig mit dem Konsumenten verfügbar sein, damit der Konsument die gewünschten Daten nachladen kann) und einen zusätzlichen Kontrakt (inkl. separater Versionierung, Authentisierung, Autorisierung) zwischen Erzeuger und Konsument mit sich, falls der Konsument zur Verarbeitung der Event Notification zusätzlichen Zustand vom Erzeuger anfragen muss.
Hierbei muss auch beachtet werden, dass ein Erzeuger nicht automatisch in der Lage ist, diesen Zustand auch so zu liefern, wie er genau zum Zeitpunkt der Erzeugung der Event Notification beim Erzeuger vorgelegen hat. Oft wird in naiven Implementierungen dem Konsumenten der aktuelle Zustand des referenzierten Objekts geliefert. Wenn also ein Erzeuger zwei Event Notifications „Kunde registriert” und „Kunde gesperrt” jeweils mit der Kundennummer als Referenz publiziert, aber der Konsument die Kundendaten aufgrund der Verarbeitung von „Kunde registriert” nachfragt, erst nachdem der Kunde beim Erzeuger bereits gesperrt wurde, wird dem Konsument ohne weitere Vorkehrungen beim Erzeuger der Zustand des bereits gesperrten Kunden zurückgeliefert. Je nach Fachlichkeit beim Konsumenten kann das in Ordnung sein, kann aber auch zu Verwirrung führen, wenn der Konsument z.B. davon ausgeht, dass ein gerade registrierter Kunde im Zustand „aktiv” statt „gesperrt” sein muss.
In der Praxis empfiehlt sich der Einsatz von Event Notification (statt ECST) vor allem dann, wenn der Zustand des Events sehr gross wäre (und so z.B. die Limitierungen der Infrastruktur überschreiten würde), der Zustand sehr kurzlebig ist (sich sehr rasch ändert) oder Teile des Zustands nicht für alle Konsumenten zugänglich sein darf und deshalb beim Nachladen des Zustands durch den Konsumenten spezifische Autorisierungsregeln angewendet werden sollen.
ECST vs. „ECST-Event”
Der entscheidende Punkt hier: ECST ist nicht der Gegenpol zu Domain Event. ECST ist der Gegenpol zu Event Notification. ECST vs. Event Notification ist eine Dimension, welche orthogonal zu Domain Events vs. „ECST-Event” steht. Sowohl Domain Events als auch „ECST-Events” können auf ECST basieren, oder können als Event Notification realisiert werden. Dies macht den Konflikt in der Bedeutung von ECST und „ECST-Event” offensichtlich.
Die Darstellung als Matrix mit Zustand im Event vs. fachlichen Auslöser im Event zeigt, dass ECST sowohl als Dimension auf der Achse „Zustand im Event” als auch als konkreter Event-Typ verstanden wird.
Um diesen Konflikt aufzulösen, empfiehlt es sich, die Motivation für den Einsatz von Domain Events vs. „ECST-Events” zu beleuchten:
-
Domain Events sind ein enorm ausdrucksstarkes Konzept, um fachliche Ereignisse innerhalb eines Domain Models explizit auszudrücken. Sind sind zudem ein wertvolles Mittel, um Prozesse, welche sich über mehrere Bounded Contexts hinweg ziehen, durchgängig abzubilden.
Dieser Bedarf entsteht, weil wir typischerweise die fachliche Komplexität aus der Problemwelt in der Lösungswelt auf unterschiedliche Bounded Contexts abbilden müssen, um diese mittels geeigneten, lokal konsistenten Domain Models und von dedizierten Teams als möglichst autonome Teilsysteme umsetzen zu können. Dabei helfen Domain Events, Bounded Contexts über fachliche Ereignisse zu integrieren.
-
„ECST-Events” sind ein Mittel, um Daten aus einem fremden System zu replizieren, ohne dessen Fachlichkeit im Detail kennen zu müssen. Dank der Replikation liegen im eigenen System die fremden Daten bereits vor, wenn diese für die Durchführung der eigenen Fachlichkeit benötigt werden, und müssen nicht erst in dem Moment mittels einer synchronen Integration vom fremden System bezogen werden.
Dieser Bedarf entsteht aus dem Wunsch, die Autonomie von einzelnen Teilsystemen zu steigern und diese als Self-Contained Systems zu realisieren. Die Autonomie wird durch die Reduktion der temporalen Kopplung zwischen Teilsystemen zum Zeitpunkt der Ausführung von Fachlichkeit erhöht.
Diese Betrachtung erlaubt, den „ECST-Events” einen Namen zu geben, der ihre Natur und ihren Zweck besser beschreibt: Replication Event.
Replication Events
Replication Events sind da, um Daten von einem Teilsystem zu einem (oder mehreren) anderen Teilsystem zu replizieren. Der Name Replication Event fokussiert dabei auf den Zweck des Events. Der Konsument benötigt nur ein Replikat der Daten (einer Entität) zur Steigerung der Autonomie - und nicht zur Reaktion auf ein fachliches Ereignis aus einem fremden Bounded Context. Entsprechend kommuniziert ein Replication Event auch keinen fachlichen Grund für die Veränderung an den enthaltenen Daten, sondern nur die Daten selbst.
Tatsächlich lässt sich über den Teil „Event” im Namen streiten, da es sich eigentlich nur um eine Nachricht und kein eigentliches Ereignis handelt - wird ein Replication Event aber mit der Semantik von „Entität aktualisiert” oder „Entität gelöscht”, ist „Event” wiederum passend.
Somit zeigt sich die Matrix nun wie folgt:
Konkrete Beispiele für die unterschiedlichen Quadranten in der Matrix könnten sein:
| Domain Event | Replication Event | |
|---|---|---|
| ECST | „Kunde registriert" mit allen relevanten Kundendaten | Typ „aktualisiert" (oder „gelöscht") mit allen relevanten Kundendaten |
| Event Notification | „Kunde registriert" nur mit Kundennummer; Konsument autorisiert sich für Zugriff auf sensitive Kundendaten beim Abruf via Kundennummer | Typ „aktualisiert" (oder „gelöscht") nur mit Kundennummer; Konsument autorisiert sich für Zugriff auf sensitive Kundendaten beim Abruf via Kundennummer (*) |
(*) Replication Events als Event Notification führen natürlich zu einer temporalen Kopplung zum Zeitpunkt der Verarbeitung des Replication Events (dem Aufbau des Replikats), der Einsatz von Replication Events als solcher vermeidet aber die temporale Kopplung zum Zeitpunkt der Ausführung der Fachlichkeit, welche auf die Daten des fremden Systems angewiesen ist (der Nutzung des Replikats).
Domain Events vs. Replication Events
Nach der Auflösung des Namenskonflikts bleibt noch die Frage, wann welcher Event-Typ der Richtige ist. Hierzu kann folgende Heuristik helfen:
Domain Events sind das passende Konzept, wenn ein Bounded Context auf ein fachliches Ereignis aus einem fremden Bounded Context reagieren soll („immer wenn sich ein Kunde registriert hat, muss ein Wallet eröffnet werden”). Es erlaubt dem Konsumenten, auf das konkrete fachliche Ereignis zu reagieren, ohne weiteres Wissen zur konkreten Fachlichkeit kennen zu müssen.
Replication Events sind das passende Konzept, wenn ein Bounded Context bei der Ausführung seiner Fachlichkeit nur den Zustand benötigt, welcher von einem fremden Bounded Context verantwortet wird (sofern hohe Autonomie gewünscht ist). Hier ist Datenreplikation das eigentliche Ziel.
Domain Events können auch genutzt werden, um beim Konsumenten basierend auf der Abfolge von Domain Events ein Replikat aufzubauen, sofern die Domain Events jeweils den notwendigen Zustand für die Sicht des Replikats beim Konsumenten enthalten.
Allerdings benötigt dies eine Projektion von fachlichen Ereignissen auf Zustände (es muss z.B. entschieden werden, mit welchem fachlichen Ereignis eine Entität aus dem Replikat gelöscht werden soll), und es führt zu einer engeren semantischen Kopplung zwischen Erzeuger und Konsument, weil der Konsument die relevanten Domain Events verstehen muss, nur um ein Replikat aufzubauen. Ergänzt ein Erzeuger sein Domain Model um einen weiteren Domain Event, muss dieser auch beim Konsumenten erkannt und verarbeitet werden, um sein Replikat aktuell zu halten. In einem solchen Fall ist es empfehlenswert, den Aufbau des Replikats über Replication Events zu ermöglichen.
- Aus einem Replication Event (oder aus der Abfolge von mehreren Replication Events) sollten beim Konsumenten keine fachlichen Ereignisse abgeleitet werden (z.B. Ableiten des fachlichen Ereignis „Kunde gesperrt” aus der Veränderung der Eigenschaft „Status” eines Kunden von „aktiv” zu „blockiert” aus zwei Replication Events auf der Seite des Konsumenten), da der Konsument dabei über den fachlichen Auslöser spekulieren muss, aber nur dessen Auswirkungen auf den Zustand kennt (der fachliche Auslöser für den Status „blockiert” könnte z.B. ja auch eine fehlgeschlagene Identifikation sein). In einem solchen Fall ist es semantisch besser, das fachliche Ereignis explizit als Domain Event (z.B. „Kunde gesperrt”) zu publizieren, damit ein Konsument explizit darauf reagieren kann.
In der Sprache des Event Storming [2] ausgedrückt:
- Wenn im Domain Model eine Regel („Policy”) existiert, welche ein eingehendes Event verarbeitet und daraus eine fachliche Aktion („Command”) auslöst, welche von einem Aggregate verarbeitet wird, muss das Event ein Domain Event sein.
- Immer, wenn für die Evaluation der Regel externer Zustand (eine Art von „Read Model”) notwendig ist, sollte dieser über Replication Events zuvor als Replikat bereitgestellt worden sein.
Daraus wird auch ersichtlich: ein Domain Event kann Teil des Domain Models sein, ein Replication Event hingegen schlägt sich nicht direkt im Domain Model nieder.
Als Konsequenz: falls ein verteiltes System nicht basierend auf den Ideen von Self-Contained Systems realisiert werden soll und die Autonomie nicht notwendig sein sollte, erübrigt sich der Bedarf an Replication Events - die bei der Ausführung der Fachlichkeit notwendigen Daten des fremden Systems werden direkt zu dem Zeitpunkt via synchrone Integration (z.B. über eine REST-Schnittstelle) bezogen. Der Bedarf für Domain Events besteht jedoch nach wie vor - er entsteht nicht aus dem Bedarf an Autonomie, sondern aus der Tatsache, dass sich durch die Modularisierung der Fachlichkeit in der Lösungswelt fachliche Prozesse über mehrere Bounded Contexts hinweg ziehen können.
Ausblick
Auf welche Weise Domain Events und Replication Events (innerhalb einer Onion Architektur) konkret modelliert und auf einer geeigneten Infrastruktur abgebildet werden können, und welche Möglichkeiten zur Kombination hierbei existieren, wird Gegenstand eines zukünftigen Artikels sein.