
Alessandro Frank
CTO
Event Sourcing ersetzt spröde CRUD-Systeme durch einen flexiblen, zukunftssicheren Ansatz, der jede Aktion als Ereignis speichert, wodurch die Geschäftslogik transparent und an Veränderungen anpassbar wird.

Stellen Sie sich das vor: Jemand kommt mit Anforderungen an ein System. Technisch oder nicht, sie sind überzeugt, dass ihre allgemeine Idee richtig ist, und zukünftige Änderungen werden nur geringfügige Anpassungen sein. Das kanonische Beispiel: „Ich möchte, dass die Leute die Website durchsuchen und Artikel zu ihrem Einkaufswagen hinzufügen/entfernen.“
Einfach genug. Sie haben einen Produktkatalog, eine Benutzertabelle, also fügen Sie eine `ShoppingCart`-Ressource hinzu — nur ein Bündel von Produkt-IDs, die einem Benutzer gehören. Das funktioniert perfekt in der Produktion. Monate sind vergangen.
Dann überzeugt jemand aus der Wirtschaft die Entscheidungsträger: „Wenn wir verfolgen, was die Leute in ihren Einkaufswagen legen und wieder entfernen, den Rest aber trotzdem kaufen, können wir sie mit E-Mails ansprechen - 'Suchen Sie immer noch nach einem Staubsauger? Hier sind noch ein paar weitere Optionen — personalisierte Rabatte, das funktioniert.“
„Also, wann können wir anfangen, diese E-Mails zu versenden?“
„Nun, wir haben diese Daten nicht.“
„Ab jetzt dann? Aber die anvisierten Kunden der letzten Monate sind verloren?“
„Nein, wir müssen zuerst neue Tabellen hinzufügen: `cart_item_lifecycle` mit user_id, item_id, added_timestamp, removed_timestamp, purchased_on_same_day...“
Dieses Schema wird niemals „vollständig“ sein - Sie können der Darstellung Ihrer Daten unendlich viele Wendungen hinzufügen. Nachdem Sie dieses neue Verhaltens-Tracking implementiert haben, stellen Sie fest, dass Annahmen kaskadieren: „Diese Änderung wirkt sich auf diese Tabelle aus, aber nur in besonderen Fällen, in denen tatsächlich eine ganz andere Tabelle erforderlich ist...“
Sofern Sie die „resultierende Ansicht“ nicht von „den Aktionen, wie sie passiert sind“ trennen, holen Sie den Spaghetticode ewig auf.
Was wäre, wenn Sie stattdessen mit Ereignissen beginnen würden:
- `shop_action_navigate_page` (wer, wann, von_page)
- `shop_action_add_item_to_cart` (Bildschirmposition, Zeitstempel, welcher Artikel)
- `shop_action_remove_item` (nochmal die 5 W's - du siehst das Muster)
- `shop_action_checkout`
Sie zahlen eine hohe Vorabgebühr, nur um zu antworten: „Was ist in ihrem aktuellen Einkaufswagen?“ Aber wenn der Vertrieb nächsten Monat Kunden finden will, die am Zaun sitzen, fügen Sie einfach ein Geschwisterkind zu Ihrer `current_shopping_cart_of_user`-Prognose hinzu:
for event := range eventsOfUser {
switch event.Type {
case "put_in_cart":
items.Add(event.ItemID)
case "remove_from_cart":
items.Remove(event.ItemID)
abandonedItems.Track(event.ItemID, event.Timestamp)
case "checkout":
// Clear current cart, trigger purchase logic
}
}Eine Schleife, keine Spaghetti. Keine vorhandenen Tabellenbeziehungen zum Navigieren, keine Schemamigrationen. Nur die Idee für eine Projektion und der Iterator, um sie zu implementieren.
Denn wenn sie nächste Woche wiederkommen und sagen: „Tolle Analyse! Wir haben mit diesen CTAs Geld verdient, aber Putbacks innerhalb von 15 Sekunden nicht mit eingerechnet — das sind versehentliche Klicks, keine tatsächlichen Zinsen“ — mit CRUD fängt es wieder von vorne an, aber bei Ereignissen wird nur eine Zeitschwellenprüfung hinzugefügt:
case "remove_from_cart":
timeSincePut := event.Timestamp.Sub(lastPutTimestamp[event.ItemID])
if timeSincePut > 15*time.Second {
abandonedItems.Track(event.ItemID, event.Timestamp)
}Das gleiche Muster gilt für jede neue Anforderung. Jede Projektion ist in sich abgeschlossen. Denke dir einfach eine neue Idee aus und notiere dir ein paar Notizen.
„Ein solches System von Grund auf neu zu schreiben ist komplexer als 'nur an einer DB-Zeile arbeiten'“:
Stimmt, aber diese Komplexität steht im Vordergrund und zahlt sich aus. Außerdem müssen Sie sich nicht für das eine oder das andere entscheiden. Beginnen Sie mit der Entwicklung neuer Funktionen mit einem Event Store und behandeln Sie vorhandene Daten als besondere Ereignisse. Ich habe alte Tabellen genommen, Spalten umbenannt und sie im Grunde genommen „manual_entry_xyz“ -Ereignisse genannt, wobei es sich bei neueren Ereignissen um richtiges Event Sourcing handelt, nicht um „CRUD-Sourcing“. Ein Event-Store verhindert nicht, dass der HTTP-Verkehr normal verarbeitet wird.
Komplexität der Veranstaltungsreihenfolge: Ja, „in welcher Reihenfolge sollten Ereignisse angewendet werden?“ Bei Systemen, bei denen Benutzer „den Zeitplan rückwirkend ändern“ können, steigt die Komplexität über „SELECT * FROM events ORDER BY timestamp ASC“ hinaus. Die meisten Geschäftsbereiche haben jedoch eine natürliche zeitliche Reihenfolge.
Bedenken hinsichtlich der Leistung: „Das Ereignisprotokoll wird immer nur größer“ wird problematisch, es sei denn, Sie lernen Ihren Projection Builder auswendig. Jede Projektion kann als (last_version + next_event) definiert werden. Speichern Sie die letzte Version und bis zu welchem Ereignis sie integriert wurde.
Wartungsaufwand: Wenn niemand Ihr Produkt verwendet, wird niemand Änderungen wollen. Jede Software mit mehr als einem Benutzer ändert sich ständig. Die Frage ist, ob Sie an der Software arbeiten oder sie verwenden möchten.
„So hohe Vorabkosten“
Tatsächlich ist das Speichern umfangreicher Event-Streams mit minimalen Komplexitätskosten verbunden, während ihr Potenzial für rückwirkende Analysen extrem groß ist. Die Entwurfsarbeit im Vorfeld macht den Großteil der Entwicklung zum Schreiben fokussierter Projektionen mit klarem Umfang.
Dieser architektonische Ansatz bietet einen entscheidenden Vorteil: direkte Einbindung von Geschäftsleuten in die Entwicklung.
Sowohl automatische Tests als auch Plausibilitätsprüfungen können wie folgt dargestellt werden: „Stellen Sie sich diese Zeitleiste vor, in der diese Ereignisse passiert sind: [list]. Wenn diese hinzugefügt werden, wie ändert sich die gesamte Situation?“ Auf diese Weise können Entwickler die Validierung der Geschäftslogik an Fachexperten delegieren, da diese die Logik verstehen und validieren können, ohne sich in der Implementierungssyntax zu verlieren.
Hier ist ein echtes Beispiel, das zeigt, wie Event Sourcing die Geschäftslogik transparent macht. Ich habe den Produktionscode genommen und einen LLM-Pseudocode „für einen Domain-Experten, der nicht programmiert“ generieren lassen. Auf diese Weise können die Beteiligten die Logik validieren, ohne sich in Implementierungsdetails zu verlieren:
Inventory contains:
- Items: map of item_id -> InventoryItem
InventoryItem contains:
- Id: number
- Title: text
- Homeostatic: number (target stock level)
- Stocked: number (current stock)
- ConsumptionHistory: list of consumption periods
- PreviousUpdate: timestamp
Event Processing:
inventory_create_item:
item = new InventoryItem {
Id = event.ID
Homeostatic = 1
Stocked = 0
Title = data.Title
ConsumptionHistory = empty list
PreviousUpdate = event timestamp
}
Items[item.Id] = item
inventory_delete_item:
remove Items[data.Item]
inventory_set_homeostatic:
item = Items[data.Item]
if item not found: error
item.Homeostatic = data.Homeostatic
inventory_update_stock:
item = Items[data.Item]
if item not found: error
delta = item.Stocked - data.Stocked
time_elapsed = event_timestamp - item.PreviousUpdate
consumption_rate = delta / time_elapsed_hours
add to item.ConsumptionHistory: {
Delta: delta
Over: time_elapsed
End: event_timestamp
Rate: consumption_rate
}
item.Stocked = data.Stocked
item.PreviousUpdate = event_timestamp
recalculate when item will be empty
inventory_update_title:
item = Items[data.Item]
if item not found: error
item.Title = data.TitleGeschäftsbeteiligte können dieses Format lesen, Grenzfälle erkennen und die Logik direkt validieren. Die Bugs wechseln von „Warum haben Sie nicht an diese offensichtliche Sache gedacht“ zu „Unser Experte hat bestätigt, dass das vernünftig ist“.
Neben der Zusammenarbeit mit den Stakeholdern vereinfacht dieser Ansatz das API-Design. **Sie können aufhören, sich Gedanken darüber zu machen**, die perfekten REST-Endpunkte oder „eleganten“ Abstraktionen zu erstellen. Erfassen Sie stattdessen alles, wenn Ereignisse eintreten, und fragen Sie anhand von Prognosen ab, was Sie benötigen.
Das wiederholte Berechnen von Projektionen ist die perfekte Anwendung für das Auswendiglernen. Das „Bleib gleich, wenn sich nichts für dich relevantes geändert hat“ lässt sich oft einfach wie folgt handhaben: „Der Cache der Projektion X ist bis EventID 999 gültig, aber wir sind jetzt bei 1007. Gehen Sie die neuen durch, falls keine relevant sind, aktualisieren Sie von 999 auf 1007 und wir sind fertig.“
So können wir tatsächlich die Suchgeschwindigkeit von Tabellen ermitteln — vielleicht sogar noch mehr, da es realistisch ist, die Prognosen, die Sie möchten/benötigen, so zu haben, wie sie sind. Wenn Sie eine Küchenspüle mit verschiedenen Tabellen haben, die alle älter als 5 Jahre sind, können Sie die DB-Abfrage nicht einfach „mehr oder weniger zurückspucken“.
Wann kannst du es dir leisten, es nicht zu tun?
Es gibt keinen Kompromiss. Es gibt praxiserprobte Event-Sourcing-Systeme, die sofort verfügbar sind, und ein eigenes zu schreiben ist einmal erledigt. Sie können Ihre Entwickler dazu überreden, es am Wochenende zu schreiben, wenn Sie es zulassen.
Wenn ein „einfaches Crud-System“ geändert wird, durchsickert die Geschäftslogik und verunreinigt technische Einschränkungen im Normalfall. Mit Event Sourcing können Sie „es einfach machen“.
Der konzeptionelle Wandel ist einfach: Speichere das *Warum*, nicht nur das *Was*. Ereignisse als unveränderliche Fakten versus veränderlicher Zustand. Bei der Erklärung für nichttechnische Interessengruppen: „Was passiert dann?“ wird zu einer Frage, die Sie tatsächlich mit Zuversicht beantworten können, weil Sie die komplette Geschichte darüber haben, wie Sie zu einem bestimmten Staat gekommen sind.
Dieser Artikel bildet die konzeptionelle Grundlage. Im Follow-up wird genau aufgezeigt, wie das in der täglichen Entwicklung aussieht — die tatsächlichen Nutzungs-, Gefühls- und Implementierungsmuster, die Event Sourcing eher praktisch als theoretisch machen.
Alessandro ist technischer Mastermind und Chief Technology Officer bei Iridium Works. Im Laufe der Jahre hat er unzählige Systeme in Zusammenarbeit mit Front- und Backend, DevOps und als Tech Lead entwickelt. Er schreibt über neue Technologien und Softwareentwicklung.
Schauen Sie sich weitere, spannende Beiträge rund um die Iridium Works, Webdesign, Softwareentwicklung, IT-Beratung und Künstliche Intelligenz an.