Ich habe meinen ersten Versuch mit DDD und stoße auf ein Problem mit dem Gesamtdesign.
Meine Anwendung enthält 3 Entitäten; Grafik, Knoten, Link. Jede dieser Entitäten hat eine Namenseigenschaft, die vom Benutzer geändert werden kann (was meiner Meinung nach den Namen als Entity-ID nicht geeignet macht). Ein Graph enthält eine Sammlung von Knoten und ein Knoten hat eine Sammlung von ausgehenden Links (für den Zweck dieses Problems ist es sicher, eingehende Links zu ignorieren). Jeder Knoten kann immer nur einem Graphen zugeordnet sein (kann aber zwischen Graphen verschoben werden), und gleichermaßen kann jeder Link zu einem bestimmten Zeitpunkt nur mit einem Knoten verknüpft sein (kann aber verschoben werden).
Die Invariante (n), die ich durchzusetzen versuche, besteht darin, dass alle Entitätsnamen in ihrer übergeordneten Auflistung eindeutig sind. Mit der oben beschriebenen Architektur befindet sich die Invariante in den tatsächlichen Sammlungen, so dass ich entschied, dass die Auflistungsbesitzer (Graph und Knoten) beide Aggregatwurzeln sein sollten.
Das Problem, das ich habe, ist, wie erzwinge ich jetzt die Namensinvariante auf Knoten? Bei Link ist es einfach, da es innerhalb des Node AR versteckt ist und als solcher kann Node bestätigen, dass alle Link-Umbenennungen / Umzüge diese Invariante nicht brechen. Aber soweit ich sehen kann, gibt es nichts, was eine direkte Umbenennung von Node verhindern könnte, die die Invariante brechen könnte. Eventuelle Konsistenz ist hier keine akzeptable Option, dies muss eine echte Systeminvariante sein.
Der Ansatz, den ich in Erwägung ziehe, besteht darin, dass Node.Rename () die Invariante tatsächlich erzwingt, aber meine Sorge ist, dass dazu gehört, in das übergeordnete Diagramm zu schauen, um zu überprüfen, ob das Umbenennen gültig ist. Das fühlt sich nicht richtig an - es fühlt sich so an, als ob der Graph diese Namespacing-Einschränkung erzwingen sollte und dieser Knoten überhaupt nichts darüber wissen sollte.
Ich hoffe, das macht Sinn, und ich freue mich darauf, die Gedanken der Menschen zu hören.
Bearbeiten: Das oben dargestellte Domänenmodell ist eine vereinfachte Teilmenge der gesamten Domäne. Zu komplex für alle Entitäten, die in einem einzigen AR gehalten werden müssen .......
Die Lösung, die ich für dieses Problem gefunden habe, kam von einem CQRS-Ansatz. Ich fand eine ausgezeichnete CQRS-Einführung hier .
In meinem "Schreib" -Modell; Graph, Node und Link sind alle Aggregatwurzeln, aber die Namen werden vollständig von der übergeordneten Sammlung verwaltet. So hat ein Node im Write-Modell keine Vorstellung davon, was sein eigener Name ist (dh Namensaktualisierungen müssen über das besitzende Graphen gehen). Im entsprechenden 'read'-Modell wird der Name direkt mit dem Knoten verknüpft (da dies für die Anzeige nützlich ist).
Der Vorteil dieser Lösung ist, dass ich meine ARs klein halten kann, aber da die 'Name' -Info in der übergeordneten Sammlung enthalten ist, habe ich keine Probleme mit der Pflege von Aggregationsinvarianten.
Wie Sie bereits in Ihrem Kommentar gefolgert haben, sollte das einzige aggregierte Wurzelverzeichnis Graph sein.
Es gibt einen Unterschied zwischen Aggregaten und aggregierten Wurzeln . In Ihrem Beispiel sind sowohl Graph als auch Knoten Aggregate, aber das Objekt, das für die Verwaltung des gesamten Aggregats zuständig ist, ist Graph. Das ist also die Wurzel.
Der einfachste Weg, um eine Idee zu bekommen, ob ein Objekt eine aggregierte Wurzel ist, ist die Frage:
Macht es Sinn, gerade dieses Objekt losgelöst von seinem Elternteil zu haben?
Wenn die Antworten nein sind, dann ist es wahrscheinlich kein aggregierter Stamm. Zum Beispiel ist ein einzelner Knoten wahrscheinlich wenig hilfreich, wenn er nicht Teil eines übergeordneten Graphen ist. Aus diesem Grund haben Sie normalerweise nur Repositories für Aggregatwurzeln. um zu verhindern, dass Sie Zugriff auf Objekte haben, die nicht Teil ihres entsprechenden Gesamtverzeichnisses sind.
Nun zu den Invarianten. Du hast das gesagt (Betonung meiner):
Alle [Node] -Namen sind innerhalb ihres übergeordneten [Graph]
eindeutig
Du hast deine Frage im Grunde genau beantwortet. Im Kontext eines einzelnen Knotens macht es keinen Sinn zu sagen, dass sein Name einzigartig ist. Aber im Zusammenhang mit einem Graph tut es das, weil es eine Invariante des Graphen ist, nicht der Node. Daher ist das Diagramm für verantwortlich, das diese Invariante schützt .
Wie bei der "good aggregate root" ist es nicht unüblich, eine einzelne aggregierte Wurzel aus einer globalen Geschäftsperspektive zu haben. Ein wichtiger Aspekt von DDD ist jedoch die Identifizierung der verschiedenen Kontexte innerhalb des Systems. Ihr System verfügt möglicherweise über eine High-Level-Wurzel, die viele Graph-Objekte enthält. In diesem übergeordneten Kontext der Verwaltung Ihrer Diagramme sind Sie wahrscheinlich nicht einmal an den Low-Level-Link-Objekten im Diagramm interessiert.
Es ist wichtig, dass Sie Ihre Domänenobjekte entsprechend dem Kontext modellieren. Dies war eines der wichtigsten Dinge, die ich in den letzten Monaten realisiert habe. Die meisten Leute kennen DDD wegen Repositories oder vielleicht wegen Entitäten und Wertobjekten, aber diese sind nicht annähernd so wichtig wie beschränkte Kontexte.
Obwohl es nur ein Geschäftskonzept von Etwas gibt, ist es vollkommen in Ordnung mehrere Modelle zu haben, die dieses Konzept von Etwas repräsentieren, eine einzelne Implementierung pro Kontext. Eine Implementierung kann ein aggregierter Stamm sein, während die andere Implementierung nur Teil eines größeren Aggregats ist, alles abhängig vom Kontext.
Gewöhnliche Software-Mantras befassen sich mit der Wiederverwendung von Code, DRY und Ähnlichem, daher erschien es zunächst falsch, mehrere Klassen zu haben, die dasselbe Geschäftskonzept repräsentieren. Aber sobald ich dieses Gefühl loslassen konnte und erkannte, dass jede Implementierung ihre eigenen Verantwortlichkeiten hatte, machte es die Dinge so viel einfacher:)
Tags und Links domain-driven-design aggregateroot invariants