Wer ein System bauen möchte, das Event Sourcing nutzt – etwa für eine Finanzanwendung mit vollständiger Nachvollziehbarkeit, ein E-Commerce-System mit detaillierter Bestellhistorie oder ein anderes fachlich komplexes System, in dem die Historie zentral für die Business-Logik ist – und dabei auf der JVM arbeitet (Java, Kotlin oder Scala), steht vor einer Herausforderung. Die Recherche zeigt schnell: Es gibt Ansätze und Frameworks, aber nichts passt richtig zusammen.
Golo Roden ist Gründer und CTO von the native web GmbH. Er beschäftigt sich mit der Konzeption und Entwicklung von Web- und Cloud-Anwendungen sowie -APIs, mit einem Schwerpunkt auf Event-getriebenen und Service-basierten verteilten Architekturen. Sein Leitsatz lautet, dass Softwareentwicklung kein Selbstzweck ist, sondern immer einer zugrundeliegenden Fachlichkeit folgen muss.
Die einen setzen auf relationale Datenbanken, die anderen auf Message-Broker. Wieder andere sind generisch gehalten und kümmern sich nicht um die speziellen Anforderungen von Event Sourcing. Am Ende bleibt oft nur der Weg, selbst etwas zusammenzubauen – aus verschiedenen Bibliotheken, unterschiedlichen Konzepten und viel Glue-Code. Und das ist ein Problem.
Event Sourcing hat eigene Anforderungen:
- Events müssen unveränderlich gespeichert werden.
- Sie müssen in der richtigen Reihenfolge wieder abspielbar sein.
- Commands müssen eine konsistente Sicht auf die Events haben, auch wenn mehrere Commands gleichzeitig eintreffen.
- Projektionen – also Read Models, die Events in eine für Queries geeignete Form bringen – müssen aufgebaut und aktuell gehalten werden.
- Das Ganze muss testbar sein, was bei Event Sourcing nicht trivial ist. Es reicht nicht, zu prüfen, ob der State korrekt ist. Es muss geprüft werden, ob die richtigen Events in der richtigen Reihenfolge erzeugt wurden und daraus der richtige State abgeleitet wurde.
Wer versucht, das mit generischen Tools zu lösen, merkt schnell: Das ist aufwendig. Das Team verbringt unter Umständen deutlich mehr Zeit damit, Infrastruktur zu bauen, als sich um fachliche Probleme zu kümmern. Replay-Mechanismen werden selbst gebaut. Konsistenzprobleme müssen gelöst werden. Tests prüfen die Datenbank statt die Business-Logik. Am Ende wurde zwar theoretisch Event Sourcing gemacht, aber praktisch wurde vor allem viel Zeit investiert, um Probleme zu lösen, die längst gelöst sein sollten.
Empfohlener redaktioneller Inhalt
Mit Ihrer Zustimmung wird hier ein externes YouTube-Video (Google Ireland Limited) geladen.
YouTube-Video immer laden
Das ist nicht nur mühsam, sondern riskant. Falsch implementierte Konsistenzgrenzen führen zu Race Conditions. Fehlerhaftes Event-Replay führt zu inkonsistenten States. Ohne vernünftige Teststrategie bleibt unklar, ob das System überhaupt korrekt funktioniert. Der Preis wird in Zeit, Qualität und Sicherheit bezahlt.
Dann eben kein Event Sourcing
Man könnte sagen: dann eben kein Event Sourcing, sondern klassisch eine relationale Datenbank. Doch das wäre schade. Denn Event Sourcing bietet echte Vorteile: einen kompletten Audit-Trail, die Möglichkeit, den State zu jedem beliebigen Zeitpunkt in der Vergangenheit zu rekonstruieren, neue Projektionen aus historischen Events zu bauen, ohne Daten erneut sammeln zu müssen, und eine klare Trennung zwischen Commands und Queries, was die Architektur sauberer macht.
Deshalb ist die Situation frustrierend. Das Pattern ist gut, die Idee richtig, aber die Umsetzung auf der JVM ist zu kompliziert. Viele Teams sagen: "Der Aufwand ist zu hoch."
Oder sie fangen an, bauen etwas zusammen, und nach sechs Monaten wird es zu aufwendig – und sie verwerfen ihren (eigentlich vielversprechenden) Ansatz wieder.
Dieses Problem wird zunehmend relevanter. Doch warum? Tatsächlich ganz einfach deshalb, weil sich mehrere Dinge gleichzeitig verändert haben, die das Thema immer drängender machen.
- Event Sourcing ist kein Experiment mehr. Das Konzept wird inzwischen in großen produktiven Systemen eingesetzt – in Finanzanwendungen, im E-Commerce, in der Logistik, in der Energiebranche. Die Anforderungen sind gestiegen. Es reicht nicht mehr, dass Event Sourcing irgendwie funktioniert. Es muss produktionsreif, skalierbar, wartbar und testbar sein.
- Die Anforderungen an Nachvollziehbarkeit und Compliance sind massiv gestiegen. In immer mehr Branchen muss nachgewiesen werden, wie eine Entscheidung zustande gekommen ist. Welche Daten haben zu diesem Ergebnis geführt? Wer hat wann was gemacht? Event Sourcing ist dafür ideal geeignet, weil definitionsgemäß eine komplette Historie vorliegt. Aber nur, wenn es richtig gemacht wird – mit konsistenten Events, korrekten Projektionen und Testbarkeit.
- Die JVM-Community wird reifer. Vor zehn Jahren war Event Sourcing ein Randthema. Heute gibt es Konferenzen, Bücher und Trainings dazu. Immer mehr Teams möchten das Pattern einsetzen. Sie brauchen Werkzeuge, die sich natürlich anfühlen, sich in bestehende Stacks integrieren lassen und nicht verlangen, alles über Bord zu werfen.
- Die Technologie ist bereit. Vor zehn Jahren war es schwierig, einen dedizierten Event Store zu finden. Heute gibt es Lösungen, wie beispielsweise die von meinem Unternehmen entwickelte EventSourcingDB, die speziell für diesen Anwendungsfall entworfen wurden. Die Grundlage ist da. Was fehlt, ist die Schicht darüber – das Framework, das diese Grundlage nutzbar macht.
Das Problem ist also real und aktuell. Deshalb lohnt es sich zu fragen: Wie würde die perfekte Lösung aussehen?
Die perfekte Lösung
Wenn Event Sourcing auf der JVM so funktionieren könnte, wie es sein sollte, wie würde das aussehen?
Commands würden einfach als Records definiert werden – normale Java Records oder Kotlin Data Classes. Zum Beispiel: PurchaseBookCommand mit ISBN, Autor, Titel und Seitenzahl. Dieses Command implementiert ein Interface und definiert ein Subject – also, zu welchem Stream es gehört. Zum Beispiel /book/ und die ISBN. Klar und strukturiert.
Ein CommandHandler hätte eine Annotation – vielleicht CommandHandlerConfiguration für die Klasse und CommandHandling für die Methode. Diese Methode erhält das Command als Parameter und einen Event-Publisher. Dort wird die Business-Logik implementiert: validieren, prüfen, entscheiden. Wenn alles passt, wird ein Event publiziert:
publisher.publish(new BookPurchasedEvent(...));
Das Framework kümmert sich um den Rest – um das Speichern, die Konsistenz und alles Weitere.
Das würde sich für alle, die mit Spring arbeiten, sofort vertraut anfühlen. Bekannte Patterns, bekannte Annotationen. Keine neue Programmiersprache, kein neues Paradigma. Einfach, was bereits beherrscht wird, auf Event Sourcing angewendet.
State Rebuilding: Bei Event Sourcing wird nicht der aktuelle State gespeichert, sondern die Events. Um den aktuellen State zu erhalten, müssen die Events abgespielt werden. In der perfekten Welt wäre das einfach. Eine Methode, annotiert mit StateRebuilding, erhält ein Event und gibt den neuen State zurück. Zum Beispiel: BookPurchasedEvent hinein, Book-Record heraus. Das Framework ruft diese Methode für jedes Event auf und baut den State Schritt für Schritt wieder auf. Deklarativ: nicht wie, sondern was.
Projektionen: CQRS bedeutet "Command Query Responsibility Segregation" – also getrennte Modelle für Schreiben und Lesen. Für die Read-Seite werden Projektionen benötigt. In der perfekten Welt wäre das einfach. Eine Component mit einer Methode, annotiert mit EventHandling, erhält einen Namen, zum Beispiel catalog. Diese Methode erhält dann asynchron jedes Event, sobald es geschieht. Eine Datenbank kann aktualisiert, ein Cache befüllt werden. Der Clou: Das läuft asynchron und blockiert nicht die Command-Verarbeitung.
Testing: Event-Sourcing-Systeme zu testen, ist nicht trivial. In der perfekten Welt gäbe es Test-Fixtures. Ein Test, annotiert mit CommandHandlingTest, erhält ein Fixture injected. Mit diesem Fixture lässt sich ausdrucksstark testen: "Given nothing" (keine vorherigen Events), "when" (dieses Command ausführen), "expect successful execution", "expect single event" (das erwartete Event). Fast wie Specification-by-Example. Lesbar und klar.
Konsistenzgrenzen: ein kniffliger Punkt bei Event Sourcing. Wenn zwei Commands gleichzeitig eintreffen, die denselben Stream betreffen, darf es keine Race Conditions geben. In der perfekten Welt ließe sich das feingranular definieren: Innerhalb dieses Scopes wird eine konsistente Sicht benötigt. Das Framework garantiert, dass das eingehalten wird – ohne Locks, ohne optimistische Concurrency Control.
Integration: Die gesamte Infrastruktur soll nicht über Bord geworfen werden müssen. Spring Boot, Monitoring-Tools und Operational Patterns sind bereits vorhanden. In der perfekten Welt würde sich Event Sourcing einfügen. Eine Dependency hinzufügen, Konfiguration ergänzen, fertig. Keine komplizierte Setup-Prozedur, keine zwanzig verschiedenen Module.
Das wäre die perfekte Welt: Commands, Events, State Rebuilding, Projektionen, Testing, Konsistenzgrenzen, Integration. Alles klar, idiomatisch und auf eine Weise, die sich für JVM-Entwicklerinnen und -Entwickler richtig anfühlt.
Die Hindernisse
Doch warum ist es nicht so? Warum gibt es das nicht längst? Was sind die Hindernisse?
- Event Sourcing ist komplex. Es ist nicht einfach ein anderes Datenbank-Schema, sondern ein fundamental anderer Ansatz, Zustand zu modellieren. Eine relationale Datenbank kann Event Sourcing – irgendwie. Aber sie ist nicht dafür optimiert. Es gibt keine optimierten Replay-Mechanismen, keine eingebauten Konsistenzgrenzen. Man muss Event Sourcing manuell bauen, so gut es eben geht. Und das geht nicht übermäßig gut, weil es ein komplett anderes Paradigma ist.
- Integration ist schwierig. Das Framework soll sich nicht fremd anfühlen, sondern in den Stack einfügen. Das bedeutet: Das Framework muss verstehen, wie Spring funktioniert, wie Annotationen funktionieren, wie Dependency Injection funktioniert. Das ist nicht trivial. Da kann viel falsch gemacht werden.
- Testing ist komplex. Es wird nicht nur getestet, ob eine Methode das Richtige zurückgibt, sondern ob die richtigen Events erzeugt werden, ob der State korrekt rekonstruiert wird, ob Projektionen richtig aktualisiert werden. Das erfordert Testinfrastruktur. Die muss erst gebaut und gut designt werden, damit sie nützlich ist.
- Konsistenzgrenzen sind knifflig. Auf Event-Store-Ebene muss garantiert werden, dass innerhalb eines Scopes keine Race Conditions auftreten. Das ist nicht einfach mit einem optimistischen Lock getan, sondern erfordert ein durchdachtes Design auf Datenbank-Ebene und eine enge Zusammenarbeit zwischen Framework und Datenbank.
- Alles muss zusammenpassen. Fünf Bibliotheken lassen sich nicht einfach in der Hoffnung auswählen, dass sie gut zusammenarbeiten. Das Ganze muss als kohärentes System designt sein. Das erfordert Zeit, Expertise und die Bereitschaft, Dinge auch mal wegzuwerfen und neu zu machen, wenn sie nicht funktionieren.
All diese Hindernisse sind real. Deshalb ist es nicht trivial, das einfach zu bauen. Deshalb gibt es das nicht längst. Deshalb ist die Landschaft so fragmentiert.
Die Auflösung
Doch vor zwei Wochen gab es Neuigkeiten: Digital Frontiers, ein IT-Beratungsunternehmen auf der Schwäbischen Alb, hat OpenCQRS 1.0 veröffentlicht. OpenCQRS ist ein CQRS- und Event-Sourcing-Framework für die JVM mit nativer Unterstützung für EventSourcingDB. Es macht genau das, was beschrieben wurde: Commands als Records, Annotation-basierte Handler, State Rebuilding, asynchrone Projektionen, Test-Fixtures, dynamische Konsistenzgrenzen, Spring-Boot-Integration.
Das Besondere: OpenCQRS ist nicht einfach ein Framework, das in ein paar Wochen zusammengehackt wurde, sondern es ist das Ergebnis monatelanger intensiver Zusammenarbeit zwischen Digital Frontiers und unserem Team hinter EventSourcingDB. Mit EventSourcingDB wollten wir nicht nur eine Datenbank entwickeln, sondern ein Fundament schaffen, auf dem andere aufbauen können. OpenCQRS ist das erste große Framework, das auf diesem Fundament aufbaut. Mit anderen Worten: Das Ökosystem entsteht.
Für JVM-Teams bedeutet das: Sie müssen Infrastruktur nicht mehr selbst bauen und nicht mehr verschiedene Bibliotheken zusammenstöpseln. Sie können OpenCQRS verwenden – eine Dependency hinzufügen, Konfiguration ergänzen, loslegen. Das senkt die Einstiegshürden massiv.
Es zeigt auch: Event Sourcing ist kein Experiment mehr. Die Tatsache, dass unabhängige Unternehmen wie Digital Frontiers massiv investieren, um produktionsreife Frameworks zu schaffen, zeigt, dass das ein Mainstream-Ansatz wird – für Systeme, die Traceability, Skalierbarkeit und klare Domain-Boundaries brauchen.
Alle Informationen zu OpenCQRS 1.0 finden sich unter www.opencqrs.com. Dort gibt es Dokumentation, Beispielanwendungen und den Quellcode. Wer Event Sourcing und CQRS für die JVM einsetzen möchte, findet dort einen klaren, modernen Weg in eventgetriebene Systeme.
Dieses Release ist ein Meilenstein. Er zeigt, dass die Vision, ein starkes Fundament zu schaffen und ein reiches Ökosystem zu ermöglichen, Realität wird. Entwicklerinnen und Entwickler auf der JVM haben jetzt einen produktionsreifen Weg in die eventbasierte Welt.
In diesem Sinne: Herzlichen Glückwunsch an Digital Frontiers zum Launch von OpenCQRS 1.0!
(rme)












English (US) ·