Wie Add / Create * -Befehle in der CQRS + Event Sourcing-Architektur behandelt werden sollen

11

Ich möchte meine erste Anwendung mithilfe des CQRS-Musters zusammen mit Event Sourcing implementieren. Ich frage mich, wie die Erstellung aggregierter Wurzeln richtig gehandhabt werden sollte. Angenommen, jemand sendet den Befehl CreateItem. Wie soll damit umgegangen werden? Wo soll das Ereignis ItemCreated gespeichert werden? Als erstes Ereignis eines neuen Artikels? Oder sollte ich eine Art ItemList-Entität haben, die alle Elemente aggregiert und deren Ereignisliste nur aus ItemCreated-Ereignissen besteht?

Udi Dahan schlägt vor, keine aggregierten Wurzeln zu erstellen und stattdessen immer eine Art Abrufmethode zu verwenden. Aber wie kann ich etwas abrufen, das neu ist und dem sicherlich keine ID zugewiesen wurde? Ich verstehe die Idee dahinter und es ist ziemlich vernünftig zu glauben, dass ein neues Objekt ein Objekt ist, dessen Status aus null Ereignissen besteht, auf die geantwortet wurde. Aber wie soll ich es benutzen? Sollte ich eine bestimmte Methode in meinem Repository haben getNewItem()oder meine get(id)Methode Optional<ItemId>stattdessen akzeptieren lassen ?

Bearbeiten: Nach einiger Zeit des Grabens fand ich eine wirklich interessante Implementierung der oben genannten Muster unter Verwendung von Schauspielern. Anstatt das Aggregat zu erstellen, ruft der Autor es aus einem Repository mit neu erstellter UUID ab. Der Nachteil dieses Ansatzes besteht darin, dass er einen vorübergehenden Inkonsistenzzustand zulässt. Ich frage mich auch, wie ich deletemit einem solchen Ansatz eine Methode implementieren kann . Einfach Gelöschtes Ereignis zur Ereignisliste des Aggregats hinzufügen?

Mequrel
quelle
1
Ich vermute, dass Udis Post-Titel irreführend ist. Meiner Meinung nach scheint sein eigentliches Ziel zu sein, dass frisch hergestellte ARs immer von einem anderen Ort aus erreichbar sein sollten, so dass der Kontext erfasst wird, warum / wie / wer entschieden hat, dass der neue AR erstellt werden muss. Alles andere dreht sich darum, wie eine bestimmte Implementierung (NHibernate?) Die Verwaltung vereinfachen könnte.
Darien
2
Beachten Sie, dass der Artikel von Udi Dahan, auf den Sie verweisen, ausdrücklich darauf hinweist, dass sein Rat möglicherweise nicht für die Beschaffung von Ereignissen gilt: udidahan.com/2009/06/29/dont-create-aggregate-roots/…
EZ Hart

Antworten:

13

Die Idee in Udis Post ist, wie ich erfahre, dass keine Art von Gegenstand aus dem Nichts erscheint. Es gibt (fast) immer etwas oder genauer gesagt eine Domänenoperation, die dazu geführt hat, dass das Element erstellt wurde. Genau wie Udis Beispiel eines Benutzers, der tatsächlich aus einem Besucher geboren wurde, der sich auf der Website registriert. An diesem Punkt und in diesem begrenzten Kontext ist Besucher der aggregierte Stamm, der von seiner IP-Adresse abgerufen wird. Dieser Besucher erstellt dann das neue "Element", einen Benutzer zu diesem Zeitpunkt, über eine Domänenoperation namens Registrieren . Gleiches gilt für den vorherigen Schritt, bei dem es sich um einen weiteren begrenzten Kontext handelt: Referrer ist der AR, der von der URL abgerufen wird und über eine Domänenoperation namens BroughtVisitorWithIp verfügt , in der der Besucher geboren wird.

Udi schreibt auch sehr gut über das Löschen: http://www.udidahan.com/2009/09/01/dont-delete-just-dont/ . Die Hauptidee ist, dass Sie niemals etwas löschen. Dahinter steckt immer eine Domain-Operation, die wir erfassen möchten. Wie eine Bestellung, die storniert und nicht gelöscht wird. Lies es, es ist ein sehr guter Beitrag.

Der Hauptpunkt hier auf beiden Konten, DDD und insbesondere Event Sourcing, ist, dass Sie niemals reine CRUD-Operationen durchführen sollten. Wenn Sie sich in einer Situation befinden, in der Sie wirklich nur einige Daten einfügen, aktualisieren oder löschen müssen und wirklich keine Domänenoperation dahinter steckt, ist DDD und Event Sourcing möglicherweise nicht für diesen begrenzten Kontext geeignet . Sie können diese beiden nach Belieben kombinieren, solange ein einziger begrenzter Kontext einem Prinzip entspricht. Auf diese Weise kann der begrenzte Kontext im CRUD-Stil eine Zeile in der Datenbank erstellen, die zu einer Entität und einem Aggregatstamm in einem anderen begrenzten Kontext wird, in dem Sie jetzt den AR abrufen können und ihn nicht erstellen müssen.

Tuukka Haapaniemi
quelle
2
"Vielleicht passt DDD und Event Sourcing nicht in diesen begrenzten Kontext." Sie verstehen den Punkt von DDD richtig. Es sollte nicht in jedem Fall nur zu Satans Ruhm implementiert werden, sondern nur dann, wenn man sich mit einer komplexen Domäne voller unsicherer Regeln befassen muss. Persönlich habe ich es für legale Software gemacht, bei der Anforderungen nicht durch Logik gesteuert werden.
Jegor Chumakov
2
+1 für diesen Satz allein "für diesen begrenzten Kontext". :)
Songo
2
+1 Die Verwendung der Verben 'Hinzufügen' und 'Erstellen' deutet stark darauf hin, dass Sie immer noch über Ihre Domain im Hinblick auf die Interaktion mit einer guten alten tabellarischen Datenbank nachdenken. Ohne Ihre Domain / Ihren begrenzten Kontext zu kennen, kann ich nicht sagen, ob dies angemessen ist oder nicht. Ignorieren Sie die Persistenz, konzentrieren Sie sich zuerst auf die BEFEHLE und EREIGNISSE (auch bekannt als die ABSICHTEN und ERGEBNISSE), die für Ihre Domain einzigartig sind, und machen Sie sich dann Gedanken darüber, wie Sie den Status beibehalten können, ein Problem, das hunderttausend Mal zuvor gelöst wurde.
Matt
"Die Verwendung der Verben 'Hinzufügen' und 'Erstellen' deutet stark darauf hin, dass Sie immer noch über Ihre Domain nachdenken, um mit einer guten alten tabellarischen Datenbank zu interagieren." Hmmm. Wenn Sie ein UI-Design haben, das eine große Schaltfläche "Etwas hinzufügen" enthält, ist dies leider die Absicht. buchstäblich etwas Neues hinzuzufügen. Ich stimme Ihnen im Allgemeinen zu, aber wir sprechen hier nicht von Datenbankebene. Manchmal sind Hinzufügen oder Erstellen tatsächlich die richtigen Wörter.
Designermonkey
1
@designermonkey Wenn Sie diese Schaltflächen in der Benutzeroberfläche haben, haben Sie wirklich eine Domain-Operation dahinter? Vielleicht, aber 9 von 10 Mal ist in diesem begrenzten Kontext wirklich keine komplexe Domänenoperation erforderlich. Und eine reine CRUD-Operation ist genau das, eine reine CRUD-Operation, und sollte als solche behandelt werden. Nur wenn die Komplexität des Domänenmodells erforderlich ist, sollte es verwendet werden. Also die unterschiedlich begrenzten Kontexte mit unterschiedlichen Gestaltungsprinzipien.
Tuukka Haapaniemi