Event Sourcing: Die bessere Art zu entwickeln?
Event Sourcing ist ein alternativer Ansatz fĂĽr das Speichern und Verwalten von Daten. Wie funktioniert Event Sourcing und was sind die Vor- und Nachteile?

(Bild: sabthai/Shutterstock.com)
- Golo Roden
Kennen Sie das? Sie entwickeln eine Software (ganz gleich, ob für einen Kunden oder für die interne Fachabteilung), und kaum ist sie fertig, kommen schon die ersten Änderungs- und Anpassungswünsche: neue Funktionen, komplexere Analysen, mehr Reports und so weiter. Und oft fehlen entweder die richtigen Daten, oder die Code-Anpassungen sind aufwendiger und fehleranfälliger, als sie sein müssten. Und das führt zu Frust: bei Ihnen und auch bei Ihren Anwenderinnen und Anwendern.
Doch was wäre, wenn sich Software so entwickeln ließe, dass solche Änderungen und Erweiterungen deutlich einfacher und flexibler möglich sind? Genau darum geht es heute: Wir schauen uns an, warum viele Systeme für diese Herausforderungen nicht gemacht sind und wie wir das besser lösen können. Und wenn Sie bei der Softwareentwicklung flexibler und effizienter werden möchten, dann sind Sie hier genau richtig.
Wie wir mit Daten arbeiten
Was ist das Problem? Völlig gleich, mit welcher Architektur Sie arbeiten, ob Sie einen Monolithen entwickeln, ein Client-Server-System, eine Peer-to-Peer-Lösung, eine verteilte servicebasierte Anwendung oder etwas anderes – eines bleibt stets gleich, nämlich die Datenhaltung. Vielleicht würden Sie jetzt entgegnen, dass das nicht stimme, denn immerhin gäbe es nicht nur relationale Datenbanken, sondern auch NoSQL-Datenbanken oder File Storage und dieses und jenes, doch eines haben all diese Storage-Ansätze gemeinsam: Sie speichern stets den Status quo.
Empfohlener redaktioneller Inhalt
Mit Ihrer Zustimmung wird hier ein externes YouTube-Video (Google Ireland Limited) geladen.
Ich bin damit einverstanden, dass mir externe Inhalte angezeigt werden. Damit können personenbezogene Daten an Drittplattformen (Google Ireland Limited) übermittelt werden. Mehr dazu in unserer Datenschutzerklärung.
Wenn Sie etwa eine Software für eine Bibliothek schreiben, in der man Bücher ausleihen, verlängern und zurückgeben kann, dann ist es sehr wahrscheinlich, dass für jedes Buch ein Datensatz angelegt wird, wenn das Buch in den Bestand aufgenommen wird, und dass dieser Datensatz jedes Mal aktualisiert wird, wenn das Buch ausgeliehen, verlängert oder zurückgegeben wird, und schließlich gelöscht wird, wenn das Buch irgendwann so zerfleddert ist, dass es aus dem Bestand entfernt wird. Und das erscheint so logisch und naheliegend, dass man in der Regel gar nicht hinterfragt, ob das wirklich sinnvoll ist.
CRUD …
Doch warum wirkt das so logisch und naheliegend? Nun, ganz einfach: Weil wir das alle von klein auf so vermittelt bekommen haben – ganz gleich, ob Sie eine Ausbildung gemacht oder studiert haben, ob Sie an einer Fachhochschule oder an einer Universität waren, oder mit welcher Programmiersprache Sie aufgewachsen sind: Die Wahrscheinlichkeit, dass Sie das Speichern von Daten genau so gelernt haben, nämlich Datensätze anzulegen, bei Bedarf zu ändern und schließlich irgendwann zu löschen, ist nahezu immer gegeben.
Für diese Art, mit Daten umzugehen, gibt es sogar einen Fachbegriff, nämlich "CRUD": Das steht für "Create", "Read", "Update" und "Delete", also die vier Verben, mit denen wir in einer Datenbank auf Daten zugreifen können. Und das findet sich tatsächlich überall, egal, ob Sie eine relationale Datenbank wie beispielsweise PostgreSQL oder Microsoft SQL Server einsetzen oder ob Sie mit einer NoSQL-Datenbank wie etwa MongoDB oder Redis arbeiten. Und genau das meine ich: Die Art und Weise, in der wir Daten speichern und mit ihnen umgehen, ist konzeptionell stets dieselbe.
… und seine Probleme
Das wirkt zunächst auch gar nicht schlimm, denn es funktioniert offensichtlich seit vielen Jahrzehnten problemlos. Und Daten werden nun einmal angelegt, geändert und gelöscht. Das ist quasi ein universelles Prinzip. Aber: Wo Licht ist, ist immer auch Schatten. Und natürlich gibt es Aspekte, die mit diesem CRUD-Ansatz einfach nicht gut funktionieren. Ich bin mir sehr sicher, dass Sie selbst schon mindestens einmal ein solches Szenario erlebt haben, nämlich: Löschen ist meistens keine besonders gute Idee.
Denn wenn etwas gelöscht wird, ist es danach – Überraschung! – weg. Doch das ist oft unerwünscht, denn vielleicht hat sich die Anwenderin oder der Anwender nur verklickt und würde das Löschen gern rückgängig machen. Das Problem ist nur: Wenn die Daten bereits fort sind, lassen sie sich nicht wiederherstellen. Was tun? Nun, man löscht einfach nicht, sondern führt ein IsDeleted
-Flag ein, macht also anstelle eines Delete ein Update und setzt dieses Flag auf true
.
So kann man das Löschen zum einen rückgängig machen, und zum anderen lassen sich in der restlichen Anwendung derart markierte Datensätze einfach ignorieren – es wirkt also, als wären sie tatsächlich gelöscht. Das bedeutet, wir führen technisch ein Update durch, das aus fachlicher Sicht einem Delete entspricht.
Fachliches vs. technisches Denken
Wobei das in Wahrheit nicht ganz richtig ist, denn aus fachlicher Sicht geht es gar nicht um das "Delete" eines Buches, sondern darum, ein Buch aus dem Bestand zu entfernen. Delete ist in der Datenbanksprache lediglich das Wort, das diesem Vorgang inhaltlich am nächsten kommt, doch wenn beispielsweise jemand ein Buch stiehlt, dann muss es aus technischer Sicht ebenfalls gelöscht werden, was also auch ein Delete (oder genauer genommen ein Update) wäre – fachlich gesehen sind das jedoch zwei völlig unterschiedliche Vorgänge.
Das bedeutet, wir haben jetzt schon drei Ebenen: die fachliche, in der ein Buch aus dem Bestand entfernt wird, die technische, in der wir das IsDeleted
-Flag aktualisieren, und eine dritte Ebene, die sich irgendwo dazwischen befindet und eigentlich die technische Intention ausdrĂĽckt, weil wir ursprĂĽnglich ein Delete durchfĂĽhren wollten.
Und? Habe ich es bereits geschafft, Sie damit zu verwirren?
Missverständnisse
Wenn ja: Herzlichen Glückwunsch! Wenn Sie an dieser Stelle denken, dass dies für einen eigentlich trivialen Vorgang ganz schön kompliziert ist, sind Sie in guter Gesellschaft, denn vielen Entwicklerinnen und Entwicklern geht es genauso: Wir haben es geschafft, für ein banales Beispiel drei unterschiedliche sprachliche Ebenen zu erzeugen, sodass wir nun jedes Mal, wenn wir über solche Vorgänge sprechen, im schlimmsten Fall zweimal ersetzen müssen. Missverständnisse sind da natürlich vorprogrammiert.
Stellen Sie sich das nun in großem Maßstab vor, in einer wirklich großen und komplexen Anwendung. Dann kommt jemand aus der Fachabteilung und erklärt, dass ein bestimmter Vorgang erweitert werden müsse, und Sie überlegen angestrengt, was diese Person damit überhaupt meint, weil Ihnen die Fachsprache nicht geläufig ist und denken:
"Ah, bestimmt geht es um die Stelle, an der wir ein Delete ausfĂĽhren!"
Anschließend sprechen Sie darüber mit jemandem, der die Datenbank verwaltet, und werden angesehen, als kämen Sie von einem anderen Stern, während Ihnen gesagt wird:
"Wir machen hier kein Delete, wir fĂĽhren immer nur ein Update durch."
Viel Vergnügen dabei, das alles auseinanderzufieseln und zu klären, wo im Code nun was passiert, mit welcher Intention, wieso und warum, und wie und wo sich das letztlich auswirkt. Missverständnisse sind da geradezu vorprogrammiert, weil zwar alle irgendwie vom Gleichen reden, aber niemand das jeweilige Gegenüber wirklich versteht.