# Event Sourcing

Event Sourcing (ES) ist ein Verfahren, bei dem alle Veränderungen des Zustands einer Softwareanwendung als Sequenz von Events abgebildet und aufgezeichnet werden. Event Sourcing wird zu den Analysemustern gezählt.

## Beispiel

Bei einem Onlineshop können Bestellungen aufgegeben werden. Anstatt den aktuellen Zustand der Bestellung einfach auf einer Datenbank-Tabelle zu persistieren, wird ein Event Bestellung erstellt persistiert. Soll ein Posten zur Bestellung hinzugefügt werden, wird ein Event Posten hinzugefügt persistiert. Weitere Events wären beispielsweise Bestellung bestätigt und Bestellung abgeschlossen. Möchte man nun den aktuellen Zustand der Bestellung wissen, so müssen alle Events, in der Reihenfolge in der sie erstellt wurden, wieder geladen werden. Auf die gleiche Weise kann auch ein beliebig anderer, früherer Zustand wiederhergestellt werden. Events werden nie gelöscht. Soll ein ein Posten entfernt werden, muss entsprechend ein Posten entfernt Event persistiert werden.

## Event Store

Die Persistierung von Events erfolgt in einem sogenannten Event Store. Ein Event Store kann eine relationale Datenbank sein. Es gibt auch spezialisierte Event Stores. Grundsätzlich können Events aber auch einfach in einer Datei oder einer NoSQL-Datenbank etc. gespeichert werden. Ein Event Store könnte wie folgt mit einer relationalen Datenbank implementiert werden. Es ist zu beachten, dass dies lediglich ein Beispiel ist und viele mögliche Varianten denkbar sind:
| Globale Sequenznummer | Persistierungs-ID | Sequenznummer | Event | Event Typ |
| 1 | Bestellung|1 | 1 | <blob> | Bestellung erstellt |
| 2 | Bestellung|1 | 2 | <blob> | Posten hinzugefügt |
| 3 | Bestellung|2 | 1 | <blob> | Bestellung erstellt |
| 4 | Bestellung|1 | 3 | <blob> | Posten entfernt |
Zunächst gibt es eine globale (und eindeutige) Sequenznummer, welche aufsteigend vergeben wird. Dies erlaubt es Events dann auch wieder in der Reihenfolge zu lesen, wie sie erstellt wurden. Die Persistierungs-ID definiert, auf welche Persistierungseinheit sich das Event bezieht. Die Sequenznummer ist eine Fortlaufnummer, welche innerhalb der gleichen Persistierungseinheit eindeutig ist. Sie erlaubt es, Events zu einer Perisiterungseinheit in der richtigen Reihenfolge zu lesen. In der Spalte Event wird das eigentliche Event gespeichert. Dies kann im Prinzip in einem beliebigen Format erfolgen (z.B. JSON). Der Event Typ schlussendlich erlaubt die Deserialisierung der Event Daten und auch das Suchen nach bestimmten Events.
Ein Event Store bietet ggf. auch einen optimistischen Locking-Mechanismus an, damit Regeln strikte eingehalten werden können und nicht durch paralleles Hinzufügen von Events zu einer Persistierungseinheit ungültige Zustände erzeugt werden. Dies wird z.B. dadurch erreicht, dass der Schreibende dem Event Store mitteilt, welches die Sequenznummer des letzten Events ist, welches er erwartet. Sollte in der Zwischenzeit ein weiteres Event dazu gekommen sein, wird das Schreiben des Events abgelehnt.

## Snapshots

Wenn viele Events geladen werden müssen, kann dies lange dauern. In solchen Fällen können sogenannte Snapshots erstellt werden. D.h. es wird z.B. nach zehn Events zusätzlich der aktuelle Zustand gespeichert. Beim Laden müssen dann nur noch die Events nach diesem Snapshot und nicht alle Events geladen werden.

## Vorteile

* Nachvollziehbarkeit der aufgezeichneten Änderungen
* Nachträgliche Datenanalyse der aufgezeichneten Änderungen
* Deterministische Fehleranalyse innerhalb der aufgezeichneten Änderungen möglich
* Kann im Kontext von verteilten Applikationen andere Muster wie z.B. das Transactional Outbox Pattern überflüsstig machen

## Nachteile

* Erfordert eine andere Denkweise als z.B. CRUD-Applikationen
* Führt zu mehr Speicherplatz und daher potentiell zu höheren Kosten
* Kann zu geringerer Performanz bei Abfragen führen
* Benötigt eine Sonderbehandlung für aus datenschutzrechtlicher Sicht zu löschende Daten

## CQRS

Eine Kombination von Event Sourcing und CQRS kann sinnvoll sein, ist aber nicht zwingend. Bei CQRS wird, basierend auf den Events, ein sogenanntes Lesemodell aufgebaut, welches für lesende Zugriffe verwendet wird. Dies erlaubt eine separate Skalierung von schreibenden und lesenden Zugriffen. Das Lesemodell kann z.B. den aktuellen Zustand direkt verfügbar machen, ohne dass alle Events geladen werden müssen.