Ich beschäftige mich mit den Konzepten für Domain-Driven Design (DDD) und fand einige Prinzipien seltsam, insbesondere in Bezug auf die Isolierung von Domain- und Persistenzmodellen. Hier ist mein Grundverständnis:
- Ein Dienst auf der Anwendungsschicht (der einen Funktionssatz bereitstellt) fordert Domänenobjekte von einem Repository an, das er zur Ausführung seiner Funktion benötigt.
- Die konkrete Implementierung dieses Repositorys ruft Daten aus dem Speicher ab, für den es implementiert wurde
- Der Dienst weist das Domänenobjekt, das die Geschäftslogik kapselt, an, bestimmte Aufgaben auszuführen, die seinen Status ändern.
- Der Dienst weist das Repository an, das geänderte Domänenobjekt beizubehalten.
- Das Repository muss das Domänenobjekt wieder der entsprechenden Darstellung im Speicher zuordnen.
Angesichts der obigen Annahmen erscheint Folgendes unangenehm:
Ad 2.:.
Das Domänenmodell scheint das gesamte Domänenobjekt (einschließlich aller Felder und Referenzen) zu laden, auch wenn sie für die angeforderte Funktion nicht benötigt werden. Das vollständige Laden ist möglicherweise nicht einmal möglich, wenn auf andere Domänenobjekte verwiesen wird, es sei denn, Sie laden auch diese Domänenobjekte und alle Objekte, auf die sie nacheinander verweisen, und so weiter und so fort. Das verzögerte Laden kommt in den Sinn, was jedoch bedeutet, dass Sie anfangen, Ihre Domänenobjekte abzufragen, für die in erster Linie das Repository verantwortlich sein sollte.
Angesichts dieses Problems scheint die "richtige" Art des Ladens von Domänenobjekten eine dedizierte Ladefunktion für jeden Anwendungsfall zu haben. Diese dedizierten Funktionen würden dann nur die Daten laden, die für den Anwendungsfall erforderlich sind, für den sie entwickelt wurden. Hier kommt die Unbeholfenheit ins Spiel: Erstens müsste ich für jede Implementierung des Repositorys eine beträchtliche Anzahl von Ladefunktionen aufrechterhalten, und Domänenobjekte würden in unvollständigen Zuständen enden, die null
in ihren Feldern enthalten sind. Letzteres sollte technisch gesehen kein Problem sein, da ein Wert, der nicht geladen wurde, von der Funktionalität, die ihn ohnehin angefordert hat, nicht benötigt werden sollte. Trotzdem ist es umständlich und eine potenzielle Gefahr.
Ad 3.:.
Wie würde ein Domänenobjekt die Eindeutigkeitsbeschränkungen bei der Erstellung überprüfen, wenn es keine Vorstellung vom Repository hat? Wenn ich beispielsweise eine neue User
mit einer eindeutigen Sozialversicherungsnummer (die angegeben wird) erstellen möchte, tritt der früheste Konflikt auf, wenn das Repository aufgefordert wird, das Objekt zu speichern, nur wenn in der Datenbank eine Eindeutigkeitsbeschränkung definiert ist. Andernfalls könnte ich nach einem User
mit der angegebenen Sozialversicherung suchen und einen Fehler melden, falls vorhanden, bevor ich einen neuen erstelle. Aber dann würden die Einschränkungsprüfungen im Dienst und nicht in dem Domänenobjekt leben, zu dem sie gehören. Ich habe gerade festgestellt, dass die Domänenobjekte sehr gut (injizierte) Repositorys zur Validierung verwenden dürfen.
Ad 5.:
Ich empfinde die Zuordnung von Domänenobjekten zu einem Speicher-Backend als arbeitsintensiven Prozess im Vergleich dazu, dass die Domänenobjekte die zugrunde liegenden Daten direkt ändern. Es ist natürlich eine wesentliche Voraussetzung, die konkrete Speicherimplementierung vom Domänencode zu entkoppeln. Aber ist es tatsächlich so teuer?
Sie haben anscheinend die Möglichkeit, ORM-Tools zu verwenden, um das Mapping für Sie durchzuführen. In diesen Fällen müssen Sie das Domänenmodell jedoch häufig gemäß den Einschränkungen des ORM entwerfen oder sogar eine Abhängigkeit von der Domäne zur Infrastrukturschicht einführen (z. B. mithilfe von ORM-Anmerkungen in den Domänenobjekten). Ich habe auch gelesen, dass ORMs einen erheblichen Rechenaufwand verursachen.
Wie können Sie bei NoSQL-Datenbanken, für die kaum ORM-ähnliche Konzepte existieren, nachverfolgen, welche Eigenschaften sich in den Domänenmodellen geändert haben save()
?
Bearbeiten : Damit ein Repository auf den Status des Domänenobjekts zugreifen kann (dh auf den Wert jedes Felds), muss das Domänenobjekt seinen internen Status anzeigen, der die Kapselung unterbricht.
Im Algemeinen:
- Wohin würde die Transaktionslogik gehen? Dies ist sicherlich persistenzspezifisch. Einige Speicherinfrastrukturen unterstützen möglicherweise überhaupt keine Transaktionen (z. B. In-Memory-Mock-Repositorys).
- Muss ich bei Massenvorgängen, bei denen mehrere Objekte geändert werden, jedes Objekt einzeln laden, ändern und speichern, um die gekapselte Validierungslogik des Objekts zu durchlaufen? Dies steht im Gegensatz zur Ausführung einer einzelnen Abfrage direkt in der Datenbank.
Ich würde mich über eine Klarstellung zu diesem Thema freuen. Sind meine Annahmen richtig? Wenn nicht, wie können diese Probleme richtig angegangen werden?