Befehlshandler und DDD

10

Ich habe eine ASP.NET MVC-Anwendung, die einen Abfragedienst zum Abrufen von Daten und einen Befehlsdienst zum Senden von Befehlen verwendet. Meine Frage betrifft den Befehlsteil.

Wenn eine Anforderung eingeht, verwendet der Befehlsdienst einen Befehls-Dispatcher, der den Befehl an den angegebenen Befehlshandler weiterleitet. Dieser Befehlshandler überprüft zuerst den Befehl und führt den Befehl aus, wenn alles akzeptabel ist.

Konkretes Beispiel: Der AddCommentToArticleCommandHandler empfängt einen AddCommentToArticleCommand mit einer ArticleId, einem CommentText und einer EmailAddress.

Zuerst; Die Validierung muss erfolgen, z. B.: - Überprüfen Sie, ob der Artikel vorhanden ist. - Überprüfen Sie, ob der Artikel nicht geschlossen ist. - Überprüfen Sie, ob der Kommentartext ausgefüllt ist und zwischen 20 und 500 Zeichen. - Überprüfen Sie, ob die E-Mail-Adresse ausgefüllt ist und ein gültiges Format hat.

Ich frage mich, wo ich diese Validierung platzieren soll.

1 / im Befehlshandler selbst. Aber dann kann es nicht in anderen Befehlshandlern wiederverwendet werden.

2 / in der Domänenentität. Da eine Domänenentität jedoch nichts über Repositorys oder Dienste weiß, kann sie die erforderliche Validierung nicht durchführen (kann nicht überprüfen, ob ein Artikel vorhanden ist). Wenn die Entität jedoch keine Logik enthält, wird sie zu einem einfachen Datencontainer, der nicht den DDD-Prinzipien folgt.

3 / Der Befehlshandler verwendet Validatoren, damit die Validierung in anderen Befehlshandlern wiederverwendet werden kann.

4 / Andere Mechanismen?

Ich suche nach der Verantwortungskette für dieses spezielle Beispiel und welche Objekte (Entitäten, Repositorys, ...) darin eine Rolle spielen.

Haben Sie Ideen, wie Sie dies implementieren würden, angefangen vom Befehlshandler bis hin zu den Repositorys?

L-Vier
quelle
"Da eine Domänenentität jedoch nichts über Repositorys oder Dienste weiß, kann sie die erforderliche Validierung nicht durchführen." Warum nicht? Welches DDD-Prinzip erfordert dies?
S.Lott
Ich habe überall gelesen, dass eine Entität nichts über Repositorys oder irgendetwas anderes wissen sollte.
L-Four
Können Sie ein Zitat, einen Link oder ein Beispiel dafür angeben, was Sie speziell gelesen haben? Wir wissen nicht, welche Beschreibungen von DDD Sie lesen.
S.Lott
Jimmy Bogard teilte einige Ansichten zu diesem Thema ... lostechies.com/jimmybogard/2009/02/15/validation-in-a-ddd-world
Mayo

Antworten:

4

Ich denke, Sie müssen in diesem Fall zwei Arten der Validierung trennen. Domänenvalidierung und Anwendungsvalidierung .

Die Anwendungsüberprüfung ist das, was Sie haben, wenn Sie überprüfen, ob die Befehlseigenschaft 'text' zwischen 20 und 200 Zeichen enthält. Sie validieren dies also mit der GUI und mit einem View-Model-Validator, der auch nach einem POST auf dem Server ausgeführt wird. Gleiches gilt für E-Mails (übrigens hoffe ich, dass Sie feststellen, dass eine E-Mail wie `32.d +" Hello World .42 "@ mindomän.local" laut RFC gültig ist).

Dann haben Sie eine weitere Validierung; Überprüfen Sie, ob der Artikel vorhanden ist. Sie müssen sich die Frage stellen, warum der Artikel nicht vorhanden sein sollte, wenn tatsächlich ein Befehl von der GUI gesendet wird, mit dem ein Kommentar angehängt werden soll. War Ihre GUI schließlich konsistent und Sie haben einen aggregierten Stamm, den Artikel, der physisch aus dem Datenspeicher gelöscht werden kann? In diesem Fall verschieben Sie den Befehl einfach in die Fehlerwarteschlange, da der Befehlshandler den aggregierten Stamm nicht laden kann.

In dem oben genannten Fall hätten Sie eine Infrastruktur, die Giftnachrichten verarbeitet. Sie würden beispielsweise die Nachricht 1-5 Mal wiederholen und sie dann in eine Poision-Warteschlange verschieben, in der Sie die Sammlung von Nachrichten manuell überprüfen und die relevanten Nachrichten erneut versenden könnten. Es ist eine gute Sache zu überwachen.

Jetzt haben wir also Folgendes besprochen:

  • Anwendungsvalidierung

    • Mit Javascript in der GUI
    • Mit MVC-Validierung auf dem Webserver
  • Fehlende Gesamtwurzel + Giftwarteschlangen

Was ist mit Befehlen, die nicht mit der Domäne synchron sind? Vielleicht haben Sie eine Regel in Ihrer Domain-Logik, die besagt, dass nach 5 Kommentaren zu einem Artikel nur Kommentare mit weniger als 400 Zeichen zulässig sind, aber ein Typ war mit dem 5. Kommentar zu spät und musste der 6. sein - die GUI hat es nicht verstanden, weil Es stimmte nicht mit der Domäne überein, als er seinen Befehl sendete. In diesem Fall haben Sie einen 'Validierungsfehler' als Teil Ihrer Domänenlogik und würden das entsprechende Fehlerereignis zurückgeben.

Das Ereignis kann in Form einer Nachricht an einen Nachrichtenbroker oder Ihren benutzerdefinierten Dispatcher erfolgen. Wenn die Anwendung monolithisch ist, kann der Webserver synchron sowohl auf ein Erfolgsereignis als auch auf das erwähnte Fehlerereignis warten und die entsprechende Ansicht / den entsprechenden Teil anzeigen.

Oft haben Sie ein benutzerdefiniertes Ereignis, das für viele Befehlstypen einen Fehler bedeutet, und dieses Ereignis abonnieren Sie aus Sicht des Webservers.

In dem System, an dem wir arbeiten, führen wir eine Anfrage-Antwort mit Befehlen / Ereignissen über einen MassTransit + RabbitMQ-Nachrichtenbus + Broker durch, und wir haben ein Ereignis in dieser bestimmten Domäne (teilweise Modellierung eines Workflows), das benannt ist InvalidStateTransitionError. Die meisten Befehle, die versuchen, sich entlang einer Kante im Zustandsdiagramm zu bewegen, können dieses Ereignis verursachen. In unserem Fall modellieren wir die GUI nach einem schließlich konsistenten Paradigma. Daher senden wir den Benutzer an eine Seite mit dem Befehl "Akzeptiert" und lassen die Ansichten des Webservers anschließend passiv über Ereignisabonnements aktualisieren. Es sollte erwähnt werden, dass wir Event-Sourcing auch in den aggregierten Wurzeln durchführen (und dies auch für Sagen tun werden).

Sie sehen also, viele der Validierungen, über die Sie sprechen, sind tatsächlich Validierungen vom Anwendungstyp, keine tatsächliche Domänenlogik. Es ist kein Problem, ein einfaches Domain-Modell zu haben, wenn Ihre Domain einfach ist, Sie aber DDD ausführen. Wenn Sie jedoch mit der Modellierung Ihrer Domain fortfahren, werden Sie feststellen, dass die Domain möglicherweise nicht so einfach ist, wie es sich zunächst herausstellte. In vielen Fällen akzeptiert der aggregierte Stamm / die aggregierte Entität möglicherweise nur einen durch einen Befehl verursachten Methodenaufruf und ändert einen Teil seines Status, ohne eine Validierung durchzuführen - insbesondere, wenn Sie Ihren Befehlen vertrauen, wie Sie es tun würden, wenn Sie sie auf dem Webserver validieren Sie kontrollieren.

Ich kann empfehlen, die beiden Präsentationen zu DDD von der norwegischen Entwicklerkonferenz 2011 und auch Gregs Präsentation auf der Öredev 2010 anzusehen .

Prost, Henke

Henrik
quelle
Vielen Dank! Eine Sache zur Validierung: Derzeit wird diese Validierung von der Benutzeroberfläche ausgelöst (indem eine Validierungsanforderung (Befehlsanforderung) an den Dienst gesendet wird), die Validate () der Comment-Entität selbst verwendet. Wenn der Befehl gültig ist, gibt der Client einen Execute-Befehl aus, der erneut Validate () ausführt, um sicherzugehen, und wenn er gültig ist, wird der tatsächliche Befehl ausgeführt. Die Hauptvalidierung wird also von der Entität "Kommentar" durchgeführt, da die Validierung in jedem Kontext gleich ist (E-Mail muss immer gültig sein, Kommentartext nicht zu lang usw.). Ist dies ein guter Ansatz?
L-Four
Die Validierung, die Sie zu beschreiben scheinen, scheint mir keine Rechtfertigung für die Modellierung mit einem 2-Phasen-Validierungsprotokoll zu sein. Überprüfen Sie die Parameter des Methodenaufrufs auf der Entität wie in einem Komponententest, aber abgesehen davon. Die Anwendungsschicht / GUI kann die von Ihnen beschriebenen Regeln leicht überprüfen, ohne Befehle an die Domäne zu senden. Imo. Sofern der Client nicht böswillig ist, sollte der Befehl funktionieren. Wenn der Client böswillig ist, schlägt der Befehl fehl und Ihr Lesemodell erhält nie ein entsprechendes Ereignis. Sie können den problematischen Befehl in der Fehlerwarteschlange überprüfen.
Henrik
In der Benutzeroberfläche (ASP.NET MVC) verwende ich Validierungsattribute, um die gesamte Validierung durchzuführen. Wenn diese Validierung erfolgreich ist, muss ich sie dann nicht erneut in der Domäne validieren, sondern nur den Befehl ausführen.
L-Four
1
Ja, Sie führen den Befehl aus, stellen jedoch sicher, dass der Befehl sowohl in der Anwendungsschicht als auch in der Domäne nicht ungültig ist.
Henrik
0

BEARBEITEN: WaybackMachine-Link: http://devlicio.us/blogs/billy_mccafferty/archive/2009/02/17/a-response-to-validation-in-a-ddd-world.aspx

Es gibt keine Antwort.

Es gibt zwei klare Projektszenarien, die mir einfallen, wenn ich versuche zu beantworten, wo die Validierung leben soll. Die erste besteht darin, dass eine DTO-Schicht verwendet wird, um Informationen zwischen der Ansichts- und der Domänenschicht zu übertragen. Beispielsweise haben Sie möglicherweise ein Kundenobjekt in Ihrer Domänenebene und ein zugeordnetes Kunden-DTO in einer anderen Ebene, der Sie die Kundeninformationen zuordnen, um sie dann der Ansicht zum Präsentieren von Kundeninformationen für den Benutzer zu geben.

Das zweite Szenario ist ein Projekt, bei dem die Entitäten innerhalb der Domänenschicht direkt mit der Ansicht geteilt werden, um die Daten dem Benutzer zu präsentieren. Anstatt beispielsweise eine separate DTO-Schicht zu verwalten und ein Domänenobjekt den DTOs zuzuordnen, die der Ansicht zugewiesen werden sollen, könnte der Ansicht das Kundenobjekt direkt zugewiesen werden. Anstatt über ein separat verwaltetes DTO zu sprechen, um den Namen eines Kunden anzuzeigen, fragt die Ansicht einfach das Kundenobjekt selbst nach den Informationen.

S.Lott
quelle