User Tools

Site Tools


technology:cqrs

CQRS

Command and Query Responsibility Segregation ist ein Konzept das auf CQS1) von Bertrand Mayer2) basiert, und von Greg Young entwickelt wurde. CQS trennt die Aufgaben eines Objektes in zweierlei. Entweder setzt eine Methode eines Objektes einen Befehl um, oder sie beantwortet eine Frage. Wenn sie einen Befehl umsetzt hat die Methode keinen Rückgabewert. Wenn sie eine Frage beantwortet bleibt das Objekt unverändert, so dass die Antwort auf die Frage 3) immer dieselbe bleibt.

CQRS geht einen Schritt weiter indem es die Aufgaben auf zwei Objekte aufteilt. Ein Objekt führt Befehle aus, das andere beantwortet Fragen. So kann jedes Objekt für die eigenen Aufgaben optimiert werden.

Implementierung

Command


Um eine Aktion in der Domäne durchzuführen werden folgende Schritte durchgeführt

  • UI baut einen Command
  • UI schickt diesen Command an die Remote Facade
  • die Remote Facade ruft in der Applikationsschicht den entsprechenden Command Handler auf
  • der Command Handler sammelt alle notwendigen Informationen um den Befehl durchzuführen, führt eigene Prüfungen durch4), lädt das Aggregate über das dafür vorgesehene Repository und ruft die entsprechende Methode in dem Aggregate auf, wobei alle notwendigen Daten dafür mit übergeben werden
  • Das Aggregate prüft alle Invariants und führt die Methode dann durch indem es Domain Events veröffentlicht
  • Der Command Handler speichert das geänderte Aggregate zurück über das Repository5)

Abweichende Implementierung


Die Regel lautet, dass man Commands einzeln ausführt, welche auf natürliche Weise in einer Transaktion geschachtelt werden. Will man zwei oder mehr Commands ausführen, werden dafür auch zwei oder mehr Transaktionen gestartet. Dabei kann es passieren, dass der erste erfolgreich ausgeführt wird, der zweite nicht.

Das ist i.d.R. kein Problem. Die Domäne ist per Definition nach Ausführung eines Befehls immer in einem konsistenten Zustand, weil jeder Befehl durch die Domäne läuft, mit Aggregaten, die alle Business Regeln prüfen bevor der Befehl ausgeführt wird. Es ist für den Anwender aber u.U. etwas irritierend, wenn er in einem Dialog Änderungen vornimmt, den Dialog mit OK bestätigt, und nur ein Teil von den Änderungen gespeichert werden. Das wäre keine zufriedenstellende Benutzererfahrung, der Benutzer erwartet von Natur aus, dass alle Änderungen entweder gemeinsam gespeichert werden oder gemeinsam abgelehnt werden.

Was kann man machen? Man könnte einen Domain Service bauen, der alle Befehle des Dialogs in einen großen Befehl packt, und diesen dann ausführt. Das wäre nicht sehr sinnvoll, weil der Domain Service dieselben Aufgaben übernimmt wie andere veröffentlichte Methoden des Aggregates, und es pro Command-Kombination einen Domain Service geben müsste. Ein Domain Service ist dafür da, Regeln zu prüfen, die nicht in ein einzelnes Aggregate gepackt werden können, würde also in diesem Fall für UI-Zwecke missbraucht werden und würde somit eine Abhängigkeit zum UI erhalten, die absolut nicht vorhanden sein darf.

Man könnte das UI entsprechend bauen, so wie es Greg Young vorschlägt - behavior driven UI. In dem Fall würden die Dialog die Befehle wiederspiegeln, kleiner sein und sicherlich auch übersichtlicher. Das ist sicherlich die am erstrebenswerteste Lösung.

Man könnte Compensating Actions umsetzen, die den ersten Befehl negieren, wenn der zweite fehl schlägt. Das ist völlig übertrieben, erhöht den Programmieraufwand um ein Vielfaches wenn man das an diversen Stellen umsetzen möchte.

Der für mich beste Kompromiss ist Multiple Command Handling, der es erlaubt, dass mehrere Befehle in einer Transaktion durchgeführt werden, unter ganz bestimmten Bedingungen6).

3) und alle anderen
4) so wenig wie möglich, die Logik soll in der Domäne bleiben
5) welches die veröffentlichten Domain Events aus dem Aggregate abfragt und speichert
6) im Grunde nur die eine, dass alle Befehle für ein und dasselbe Aggregate sind
technology/cqrs.txt · Last modified: 2012/12/19 16:00 by rtavassoli