Wie arbeite ich mit großen aggregierten Wurzeln?

11

Ich lerne DDD und habe dennoch mehr Fragen als Antworten.

Betrachten wir ein Modell eines Verzeichnisses mit einer enormen Anzahl von Dateien.
So sehe ich das:

Das Verzeichnis ist eine aggregierte Wurzel.
Diese Entität sollte über die Validierungslogik verfügen, die Eindeutigkeit des Dateinamens zu überprüfen, wenn sie hinzugefügt oder nur umbenannt wird. Die Dateientität enthält die Logik 'SetName', mit der Directory über Domain Event über Namensänderungen informiert wird.
Aber wie soll Directory dann funktionieren?
Es ist nicht immer möglich, alle Dateien in den Speicher zu laden. Sollte das Datei-Repository in diesem Fall über eine Ad-hoc-Logik zur Überprüfung der Eindeutigkeit von Namen verfügen? Ich nehme an, es ist eine tragfähige Entscheidung.
Was ist jedoch, wenn einige Dateien bereits mit der aktuellen, noch nicht festgeschriebenen Transaktion hinzugefügt oder umbenannt wurden? (Nichts verbietet dies. Transaktionsgrenzen werden extern in Bezug auf die Geschäftslogik festgelegt.) Wahrscheinlich sollte das Repository sowohl speicherinterne als auch persistierte Zustände berücksichtigen (das Zusammenführen dieser Zustände kann eine nicht triviale Aufgabe sein.)

Wenn also die Gesamtwurzel mit all ihren Kindern in die Erinnerung passt, ist alles in Ordnung. Und sobald Sie nicht alle Entitäten materialisieren können, gibt es Probleme.

Ich würde gerne wissen, wie die Ansätze für solche Situationen aussehen. Vielleicht gibt es überhaupt kein Problem und es liegt nur an meinem Missverständnis des Themas.

Pavel Voronin
quelle
1
Was lässt Sie denken, dass Sie alle Dateien und deren Inhalt laden müssen und nicht nur "FileInfo"?
Euphoric
@Euphorisch. Nun, manchmal ist sogar das nicht möglich. Auf jeden Fall gibt es ein anderes Problem. Wie kann die Konsistenz von FileInfo und den entsprechenden Dateientitäten sichergestellt werden, die innerhalb der aktuellen Transaktion geändert wurden? Wahrscheinlich geht CQRS auf diese Frage ein ... habe sie noch nicht angeschaut.
Pavel Voronin
1
Es ist nützlich zu verstehen, dass DDD keine Programmiertechnik, sondern eine Designtechnik ist. Zu viele Leute behandeln es wie eine Codierungsmethode. Begriffe wie "Aggregatwurzel" verschlimmern das Problem, weil sie den Eindruck von technischem Gewicht erwecken, obwohl sie tatsächlich nicht viel mit Programmiertechniken zu tun haben. Die Programmiertechniken ändern sich in DDD nicht wesentlich. Während DDD Ihren Code und Ihre Architektur informiert, sind Code und Architektur von Ihnen getrennt.
Robert Harvey
@ RobertHarvey Es scheint mir, dass DDD komplexere Programmiertechniken erfordert. Zumindest wenn es um Eckfälle geht. Ich betrachte DDD hauptsächlich als eine Möglichkeit, Geschäftslogik von unvermeidlichem Infrastrukturcode zu trennen (und zu lokalisieren), der implizit hinter den Kulissen funktioniert. Für mich DDD = gute OOD + implizite Infrastruktur. Die meisten Fragen, die ich zu DDD habe, beziehen sich auf den letzten Teil.
Pavel Voronin
2
Warum sagen Sie: "Transaktionsgrenzen werden extern in Bezug auf die Geschäftslogik festgelegt"? Die Pflicht der aggregierten Wurzel besteht darin, eine Transaktionsgrenze aufrechtzuerhalten. Außerdem müssen Sie den Inhalt der Dateien nicht laden. Sie können einfach Metadaten laden.
Esben Skov Pedersen

Antworten:

20

Meine Antwort ist voreingenommen mit Vaughn Vernons großartigem Buch "Implementing Domain Driven Design" (ein Muss)

1. Bevorzugen Sie kleine Aggregate.

Wenn ich Ihre Domain modellieren möchte, würde ich eine Directoryals Aggregat und Fileals ein anderes Aggregat modellieren .

2. Referenzaggregate nach IDs.

Daher Directorywird eine Sammlung von FileIdWertobjekten haben.

3. Verwenden Sie Fabriken, um Aggregate zu erstellen.

Für einen einfachen Fall kann eine Factory-Methode ausreichen Directory.addFile(FileName fileName). Für komplexere Fälle würde ich jedoch eine Domain Factory verwenden.
Die Domänenfactory kann fileNamemithilfe eines FileRepositoryund eines UniquefileNameValidatorInfrastrukturdienstes überprüfen, ob dies eindeutig ist .

Warum Fileals separates Aggregat modellieren ?

Weil Directoriesnicht gemacht sind Files. a Fileist mit einem bestimmten verbunden Directory. Stellen Sie sich auch ein Verzeichnis mit Tausenden von Dateien vor. Das Laden all dieser Objekte in den Speicher jedes Mal, wenn ein Verzeichnis abgerufen wird, ist ein Leistungskiller.

Modellieren Sie Ihre Aggregate gemäß Ihren Anwendungsfällen. Wenn Sie wissen, dass ein Verzeichnis niemals mehr als 2-3 Dateien enthält, können Sie sie alle als ein einziges Aggregat modellieren. Nach meiner Erfahrung ändern sich die Geschäftsregeln jedoch ständig und es lohnt sich, wenn Ihr Modell flexibel genug war, um die Anforderungen zu erfüllen Änderungen.

Obligatorische Lektüre Effective Aggregate Design von Vaughn Vernon

Songo
quelle
2
Beachten Sie, dass echte Verzeichnisimplementierungen normalerweise so implementiert werden (separate Aggregate, auf die durch ihre IDs verwiesen wird). Beispielsweise werden "Dateien" von ihren inodeUnix-Systemen einfach aus ihrem Verzeichnis referenziert .
Alexander Langer
1
Ich habe endlich das empfohlene Buch gelesen. Tolles Buch, danke. Trotzdem ist es noch nicht ganz klar. Es kann nur eine Filemit einem bestimmten Namen in existieren Directory, dh sie Directoryhat die Invariante: Name Eindeutigkeit. Zumindest ist es wichtig für die Directory, aber nicht für die File. Eigentlich ist @AlexanderLanger richtig: 'Datei' kann von vielen 'Ordnern' referenziert werden. Und der Name ist wahrscheinlich eher Eigentum dieser Referenz als des FileSelbst. OK. Dann gehört das Umbenennen von Funktionen zu Directory, aber auch hier ist es keine gute Idee, Tausende von referenzierten Identitäten zu speichern.
Pavel Voronin
Und selbst wenn wir das tun würden, müssten wir eine Überprüfung gegen Namen durchführen. Von hier aus erscheint es sinnvoll, eine Methode im Ordner-Repository zu erstellen : bool ContainsFileOfName(int folderId, string fileName). Danach kann die Signatur der 'Umbenennen'-Methode wie folgt lauten: void Rename(int fileId, string newName)In einigen IFolderService(die das Repository umschließen) wird aufgelöst und gefragt, ob ein solcher Name vorhanden ist.
Pavel Voronin
1

Dies ist per se keine DDD-Frage. Die Hauptfrage hier ist über den Synchronisationskontext (der hier eine aggregierte Wurzel ist).

Zurück zum Thema: Das Verzeichnis soll ein Synchronisationsobjekt mit Dateinamen blockieren und prüfen, ob der angegebene Dateiname zulässig ist, der im schlimmsten Fall O (n) ist.

Stute Infinitus
quelle
1

Obwohl einige sagen mögen, dass Sie versuchen, Ihr Design zu ändern, besteht immer ein Bedarf, wenn ein AR eine große Liste einfacher Objekte enthält. Und das Speichern im Speicher ist aus Sicht der Leistung nicht das Beste. In solchen Fällen müssen Sie jedoch nur die Transaktionsgrenzen beibehalten. Eine einfache Lösung ist die folgende:

  1. Halten Sie den AR des Ordners einfach und fügen Sie eine Versionsspalte ein.
  2. Lassen Sie jede Datei (sagen wir Zeile) auf das aggregierte Stammverzeichnis verweisen, mit anderen Worten, um die ID des Ordners beizubehalten.
  3. Führen Sie die Änderungen der Dateien, z. B. Umbenennen, Hinzufügen, Entfernen, immer über den AR durch. Mit anderen Worten, wenn Sie eine Datei hinzufügen möchten, laden Sie den AR und verwenden Sie eine Methode in AR, um die Änderung vorzunehmen. Angenommen, Sie verwenden ein Repository-Muster, erstellt addFile () eine neue Datei und ändert die Version des Ordners. Speichern Sie diese als UoW. Wenn jemand anderes den AR geändert hat, wird aufgrund der Versionsspalte (der AR-Version) ein Fehler angezeigt.
  4. Jede Änderung an der Datei selbst, wie das Bearbeiten oder Umbenennen der Datei, sollte über den AR erfolgen. Die Version bleibt also im AR. Dies bedeutet im Wesentlichen, dass es in Ihrem Code keine anderen Ausführungspfade gibt, die die Datei ändern, außer dem besitzenden AR.

Einige Einschränkungen:

  1. Die Datei sollte nur zu einem AR gehören. Ist dies nicht der Fall, modellieren Sie die Beziehung von Ordner -> Datei als Containment und nicht die Datei selbst.
  2. Sie können eine Datei nicht von einem Ordner in den anderen verschieben, es sei denn, Sie nehmen diese Änderung in einer UoW ​​vor, dh in derselben Transaktion. Dies ist ein Sonderfall, da Sie eine Anfrage senden sollten, die in zwei Befehlen endet, sodass beide ARs geändert werden, daher jeweils zwei neue Versionen und wahrscheinlich zwei Ereignisse (Datei entfernt, Datei hinzugefügt), und dies ist ein bisschen schwierig, weil Sie die Ereignisreihenfolgen für die beiden ARs pflegen sollten, was manchmal nicht einfach ist.
ligu
quelle