Wie kann ich bei all diesen Dienstleistungen nicht anämisch sein?

90

Wo ziehen wir die Grenze zwischen Delegation und Kapselung von Geschäftslogik? Mir scheint, je mehr wir delegieren, desto anämischer werden wir. Die Delegation fördert jedoch auch die Wiederverwendung und den DRY-Prinzipal. Was ist also angemessen, um zu delegieren, und was sollte in unseren Domänenmodellen verbleiben?

Nehmen Sie die folgenden Bedenken als Beispiele:

Autorisierung . Soll das Domänenobjekt für die Aufrechterhaltung seiner Zugriffssteuerungsregeln verantwortlich sein (z. B. eine CanEdit-Eigenschaft) oder sollte diese an eine andere Komponente / einen anderen Dienst delegiert werden, die / der ausschließlich für die Zugriffsverwaltung verantwortlich ist, z. B. IAuthorizationService.CanEdit (Objekt)? Oder sollte es eine Kombination aus beidem sein? Hat das Domänenobjekt möglicherweise eine CanEdit-Eigenschaft, die an einen internen IAuthorizationService delegiert wird, um die eigentliche Arbeit auszuführen?

Validierung . Die gleiche Diskussion wie oben bezieht sich auf die Validierung. Wer hält die Regeln ein und wer ist für deren Bewertung verantwortlich? Einerseits sollte der Status des Objekts zu diesem Objekt gehören, und die Gültigkeit ist ein Status, aber wir möchten nicht den Code neu schreiben, der zum Auswerten von Regeln für jedes Domänenobjekt verwendet wird. Wir könnten Vererbung in diesem Fall verwenden ...

Objekterstellung . Factory-Klasse versus Factory-Methoden versus 'Neuanlegen' einer Instanz. Wenn wir eine separate Factory-Klasse verwenden, können wir die Erstellungslogik isolieren und kapseln, allerdings auf Kosten des Öffnens des Status unseres Objekts für die Factory. Dies kann verwaltet werden, wenn sich unsere Domänenschicht in einer separaten Assembly befindet, indem ein interner Konstruktor verfügbar gemacht wird, der von der Factory verwendet wird. Dies wird jedoch zu einem Problem, wenn mehrere Erstellungsmuster vorhanden sind. Und wenn die Fabrik nur den richtigen Konstrukteur anruft, was bringt es dann, die Fabrik zu haben?

Factory-Methoden für die Klasse beseitigen das Problem mit dem Öffnen des internen Zustands des Objekts. Da sie jedoch statisch sind, können wir Abhängigkeiten nicht durch Einfügen einer Factory-Schnittstelle auflösen, wie dies mit einer separaten Factory-Klasse möglich ist.

Ausdauer . Man könnte argumentieren, dass, wenn unser Domain-Objekt CanEdit verfügbar macht und gleichzeitig die Verantwortung für die Berechtigungsprüfung an eine andere Partei delegiert (IAuthorizationService), eine Save-Methode für unser Domain-Objekt vorhanden ist, die dasselbe tut. Auf diese Weise können wir den internen Zustand des Objekts auswerten, um festzustellen, ob die Operation ohne Unterbrechung der Kapselung ausgeführt werden kann. Natürlich müssen wir die Repository-Instanz in unser Domain-Objekt einfügen, was für mich ein wenig riecht. Lösen wir stattdessen ein Domain-Ereignis aus und gestatten einem Handler, die Persistenzoperation auszuführen?

Sehen Sie, wohin ich damit gehe?

Rockford Lhotka hat eine großartige Diskussion über seine Gründe, die Class-in-Charge-Methode für sein CSLA-Framework zu wählen. Ich habe ein wenig Erfahrung mit diesem Framework und kann seine Vorstellung von Geschäftsobjekten in vielerlei Hinsicht als Parallele zu Domänenobjekten sehen. Aber ich frage mich, ob die Zusammenarbeit zu viel wird, wenn ich versuche, mich an gute DDD-Ideale zu halten.

Wenn ich einen IAuthorizationService, einen IValidator, eine IFactory und ein IRepository für mein Gesamtstammverzeichnis habe, was bleibt dann übrig? Hat eine Publish-Methode, die den Status des Objekts von Draft in Published ändert, genug, um die Klasse als nicht anämisches Domänenobjekt zu betrachten?

Ihre Gedanken?

SonOfPirate
quelle
Gute Frage. Ich habe keine Antwort für Sie, da ich fast immer aus genau demselben Grund völlig anämisch im Design ende - indem ich Dienste aus vielen verschiedenen Kontexten oder verschiedenen Anwendungen nutze / verbrauche / verfügbar mache.
hromanko
Tolle Frage, würde gerne Onkel Bob, Martinfowler, Ericevans und andere sehen, um sich darauf einzulassen. Jetzt muss ich nachdenken
Martijn Verburg
Ich finde mich die ganze Zeit zu einem anämischen Modell entwickelt; und so kämpfe ich mit genau der gleichen Sache. Gute Frage!
L-Four
Dies war auch meine Erfahrung mit DDD. Wir machen es dort, wo ich arbeite, und wir sind immer anämisch. Ich benutze früher (und auch heute noch) Csla. Unserem Architekten gefällt es nicht, dass wir anämisch sind, aber er hat mir keine gute Antwort darauf gegeben, was das Objekt tun soll, wenn all die Dinge, auf die Sie hinweisen, nicht innerhalb des Objekts erledigt werden können. Letztendlich scheint der Versuch, puristisch zu sein, mehr Arbeit zu schaffen, als es wert ist. Ich persönlich denke, Csla und DDD vertragen sich (sie scheinen im Prinzip identisch zu sein), wenn Sie bereit sind, das DDD-Dogma hinter sich zu lassen.
Andy
Hier ist ein Beispiel für einige Techniken, die beim Modellieren von Domänen aus verhaltensorientierter (nicht datenzentrierter) Perspektive verwendet werden: medium.com/@wrong.about/…
Zapadlo,

Antworten:

66

Der größte Teil der Verwirrung scheint in der Funktionalität zu liegen, die im Domain-Modell überhaupt nicht vorhanden sein sollte:

  • Die Persistenz sollte niemals im Domänenmodell enthalten sein. Niemals. Aus diesem Grund verlassen Sie sich auf abstrakte Typen, z. B. IRepositorywenn ein Teil des Modells jemals einen anderen Teil des Modells abrufen und die Implementierung mithilfe von Abhängigkeitsinjektion oder einer ähnlichen Technik verkabeln muss. Also streichen Sie das aus der Akte.

  • Die Autorisierung ist im Allgemeinen nicht Teil Ihres Domain-Modells, es sei denn, sie ist tatsächlich Teil der Domain, z. B. wenn Sie Sicherheitssoftware schreiben. Die Mechanismen, wer was in einer Anwendung ausführen darf, werden normalerweise am "Rand" der Geschäfts- / Domänenebene behandelt, die öffentlichen Teile, mit denen die UI- und Integrationsteile tatsächlich kommunizieren dürfen - der Controller in MVC, die Services oder das Messaging-System selbst in einer SOA ... Sie bekommen das Bild.

  • Fabriken (und ich nehme an, Sie meinen hier abstrakte Fabriken) sind in einem Domain-Modell nicht gerade schlecht , aber sie sind fast immer unnötig. Normalerweise gibt es nur eine Fabrik, in der sich die inneren Mechanismen der Objekterstellung ändern können. Sie haben jedoch nur eine Implementierung des Domänenmodells, was bedeutet, dass es immer nur eine Art von Factory geben wird, die immer dieselben Konstruktoren und anderen Initialisierungscode aufruft.

    Sie können "Convenience" -Factorys haben, wenn Sie möchten - Klassen, die allgemeine Kombinationen von Konstruktorparametern usw. kapseln -, aber ehrlich gesagt, im Allgemeinen verschwenden Sie nur Zeilen, wenn Sie viele Factorys in Ihrem Domain-Modell haben von Code.

Sobald Sie also alle diese Produkte ausgemustert haben, bleibt nur noch die Bestätigung. Das ist der einzige, der etwas knifflig ist.

Die Validierung ist Teil Ihres Domain-Modells, aber auch Teil jeder anderen Komponente der Anwendung. Ihre Benutzeroberfläche und Datenbank haben ihre eigenen, ähnlichen und doch unterschiedlichen Validierungsregeln, die auf einem ähnlichen und doch unterschiedlichen konzeptionellen Modell basieren. Es ist nicht wirklich festgelegt, ob Objekte eine ValidateMethode benötigen oder nicht , aber selbst wenn dies der Fall ist, delegieren sie diese normalerweise an eine Validator-Klasse (keine Schnittstelle - die Validierung ist im Domänenmodell nicht abstrakt, sondern von grundlegender Bedeutung).

Denken Sie daran, dass der Validator technisch immer noch Teil des Modells ist. Es muss nicht an ein aggregiertes Stammverzeichnis angehängt werden, da es keine Daten oder keinen Status enthält. Domänenmodelle sind konzeptionelle Dinge, die normalerweise physisch in eine Assembly oder eine Auflistung von Assemblys übersetzt werden. Machen Sie sich keine Sorgen über das Problem der "Blutarmut", wenn sich Ihr Delegierungscode in unmittelbarer Nähe des Objektmodells befindet. es zählt immer noch.

Was das alles wirklich bedeutet ist, dass man, wenn man DDD machen will, verstehen muss, was die Domain ist . Wenn Sie immer noch über Dinge wie Persistenz und Autorisierung sprechen, sind Sie auf dem falschen Weg. Die Domäne repräsentiert den Betriebszustand eines Systems - die physischen und konzeptionellen Objekte und Attribute. Alles, was nicht direkt für die Objekte und Beziehungen selbst relevant ist, gehört nicht zum Domänenmodell, Punkt.

Wenn Sie überlegen, ob etwas zum Domain-Modell gehört oder nicht, stellen Sie sich als Faustregel die folgende Frage:

"Kann sich diese Funktionalität jemals aus rein technischen Gründen ändern?" Mit anderen Worten, nicht aufgrund einer beobachtbaren Änderung des Geschäfts oder der Domäne der realen Welt?

Wenn die Antwort "Ja" lautet, gehört sie nicht zum Domänenmodell. Es ist nicht Teil der Domain.

Es ist sehr wahrscheinlich, dass Sie eines Tages Ihre Persistenz- und Autorisierungsinfrastrukturen ändern werden. Daher sind sie nicht Teil der Domäne, sondern Teil der Anwendung. Dies gilt auch für Algorithmen wie Sortieren und Suchen. Sie sollten keine Implementierung eines binären Suchcodes in Ihr Domain-Modell einbinden, da sich Ihre Domain nur mit dem abstrakten Konzept einer Suche befasst, nicht mit der Funktionsweise.

Wenn Sie nach dem Entfernen aller unwichtigen Elemente feststellen, dass das Domänenmodell wirklich anämisch ist, sollte dies als ziemlich guter Hinweis darauf dienen, dass DDD einfach das falsche Paradigma für Ihr Projekt ist.

Einige Domains wirklich sind anämisch. Social-Bookmarking-Apps haben nicht wirklich viel von einer "Domain" zu erzählen. Alle Ihre Objekte sind im Grunde nur Daten ohne Funktionalität. Ein Verkaufs- und CRM-System hat andererseits eine ziemlich schwere Domäne; Wenn Sie eine RateEntität laden, besteht die begründete Erwartung, dass Sie mit diesem Tarif tatsächlich etwas anfangen können , z. B. eine Bestellmenge zuweisen und die Mengenrabatte und Promocodes sowie all diese lustigen Dinge herausfinden lassen.

Domain-Objekte, die nur Daten enthalten, bedeuten normalerweise , dass Sie ein anämisches Domain-Modell haben, aber das bedeutet nicht unbedingt , dass Sie ein schlechtes Design erstellt haben - es könnte nur bedeuten, dass die Domain selbst anämisch ist und Sie ein verwenden sollten andere Methodik.

Aaronaught
quelle
2
Darüber hinaus ist es nicht ganz unwahrscheinlich, dass Sie Ihr gesamtes Sicherheitsmodell irgendwann ändern möchten, @SonOfPirate. Rollenbasierte Sicherheit wird häufig zugunsten von anspruchs- oder rechtsbasierter Sicherheit abgelöst, oder Sie möchten sogar Sicherheit auf Feldebene. Stellen Sie sich vor, Sie versuchen in diesem Fall, Ihr gesamtes Domain-Modell zu überarbeiten.
Aaronaught
1
@SonOfPirate: Es hört sich fast so an, als ob Sie immer noch ein wenig im alten "Business Tier" -Modell stecken, bei dem es ein "Middle Tier" gab, das im Grunde ein dünnes Furnier über der Datenschicht war und verschiedene Geschäftsregeln und normalerweise auch Sicherheitsregeln implementierte . Das ist nicht die Domain-Schicht. Alles andere hängt von der Domäne ab. Sie repräsentiert die realen Objekte und Beziehungen, die das System verwalten soll.
Aaronaught
1
@ LaurentBourgault-Roy: Entschuldigung, ich glaube dir nicht. Jedes Unternehmen könnte das zu jeder Anwendung sagen; nach allem, eine Datenbank zu ändern ist hart. Das macht es nicht zu einem Teil Ihrer Domäne, und Geschäftslogik, die an die Persistenzschicht gekoppelt ist, bedeutet nur schlechte Abstraktion. Ein Domänenmodell konzentriert sich auf das Verhalten, was bei der Persistenz nicht der Fall ist . Dies ist kein Thema, zu dem Menschen ihre eigenen Definitionen erfinden können. es ist ziemlich klar in DDD geschrieben. Sie benötigen häufig kein Domain-Modell für CRUD- oder Berichts-Apps, sollten aber auch nicht behaupten, dass Sie eines haben, wenn Sie dies nicht tun.
Aaronaught
1
Die Autorisierung gehört absolut in die Domain-Schicht. Wer entscheidet, welche Berechtigungen vorhanden sind? Das Geschäft macht. Wer entscheidet, wer was kann? Das Geschäft macht. Wir hatten gerade vor einigen Wochen eine Funktionsanfrage, um die Berechtigung zu ändern, die zum Bearbeiten eines bestimmten Objekts in unserem System erforderlich ist. Wenn eine Vorlage auf einer Master-Vorlage basierte, waren höhere Berechtigungen erforderlich, um die Vorlage zu bearbeiten (die Werte vom Master zu überschreiben), als Sie normalerweise benötigen würden. Wohin gehört diese Logik, wenn sie nicht in der Domäne liegt?
Andy
1
Eine andere Art der Autorisierung könnte ein Kundenkontolimit sein. Normale Kundenbetreuer können es bis zu einem bestimmten Punkt anheben, aber möglicherweise müssen höhere Grenzwerte vom Management genehmigt werden. Das ist die Berechtigungslogik.
Andy
6

Genehmigung. Sollte das Domänenobjekt für die Aufrechterhaltung seiner Zugriffssteuerungsregeln verantwortlich sein?

Die Autorisierung ist ein Anliegen für sich. Befehle, die aufgrund fehlender Berechtigungen nicht gültig sind, sollten so früh wie möglich vor der Domain abgelehnt werden. Dies bedeutet, dass wir häufig sogar die Berechtigung eines potenziellen Befehls prüfen möchten , um die Benutzeroberfläche zu erstellen (um dies nicht zu tun) Zeigen Sie dem Benutzer sogar die Bearbeitungsmöglichkeit.

Das Teilen von Autorisierungsstrategien über Ebenen hinweg (in der Benutzeroberfläche und weiter oben in einem Dienst oder Befehlshandler) ist einfacher, wenn die Autorisierung getrennt vom Domänenmodell komponiert wird.

Ein schwieriger Teil, auf den man stoßen kann, ist die kontextbezogene Autorisierung, bei der ein Befehl möglicherweise nicht nur basierend auf Benutzerrollen, sondern auch auf Geschäftsdaten / -regeln zulässig ist oder nicht.

Validierung. Die gleiche Diskussion wie oben bezieht sich auf die Validierung.

Ich würde auch nein sagen, nicht in der Domäne (meistens). Die Validierung erfolgt in verschiedenen Kontexten, und die Validierungsregeln unterscheiden sich häufig zwischen den Kontexten. Es gibt selten ein einfaches, absolutes Gefühl von Gültigkeit oder Ungültigkeit, wenn die von einem Aggregat gekapselten Daten betrachtet werden.

Ebenso wie bei der Autorisierung verwenden wir die Validierungslogik über mehrere Ebenen hinweg - in der Benutzeroberfläche, im Service- oder Befehlshandler usw. Auch hier ist es einfacher, DRY mit der Validierung zu verwenden, wenn es sich um eine separate Komponente handelt. Aus praktischer Sicht erfordert die Validierung (insbesondere bei der Verwendung von Frameworks) die Bereitstellung von Daten, die ansonsten gekapselt werden sollten, und es müssen häufig benutzerdefinierte Attribute an Felder und Eigenschaften angehängt werden. Ich bevorzuge es sehr, dass diese in anderen Klassen als meine Domain-Modelle sind.

Ich würde lieber einige Eigenschaften in ein paar ähnlichen Klassen duplizieren, als zu versuchen, die Anforderungen für ein Validierungsframework in meinen Entitäten zu erzwingen. Das führt unweigerlich dazu, dass die Entitätsklassen durcheinander geraten.

Objekterstellung. Factory-Klasse versus Factory-Methoden versus 'Neuanlegen' einer Instanz.

Ich benutze eine Indirektionsebene. In meinen neueren Projekten ist dies ein Befehl + Handler zum Erstellen von etwas, dh CreateNewAccountCommand. Eine Alternative könnte darin bestehen, immer eine Factory zu verwenden (obwohl dies umständlich sein kann, wenn der Rest einer Entity-Operation von einer Service-Klasse verfügbar gemacht wird, die von der Factory-Klasse getrennt ist).

Im Allgemeinen versuche ich jedoch, die Entwurfsoptionen für die Objekterstellung flexibler zu gestalten. newist einfach und vertraut, aber nicht immer ausreichend. Ich halte es für wichtig, hier ein Urteil zu fällen und es verschiedenen Teilen eines Systems zu ermöglichen, je nach Bedarf unterschiedliche Strategien anzuwenden.

Beharrlichkeit. ... warum nicht eine Save-Methode für unser Domain-Objekt haben

Dies ist selten eine gute Idee; Ich denke, es gibt viele gemeinsame Erfahrungen, um das zu unterstützen.

Wenn ich einen IAuthorizationService, einen IValidator, eine IFactory und ein IRepository für mein Gesamtstammverzeichnis habe, was bleibt dann übrig? Verfügt die Publish-Methode über eine Methode, die den Status des Objekts von Draft in Published ändert, um die Klasse als nicht anämisches Domänenobjekt zu betrachten?

Möglicherweise ist ein Domain-Modell nicht die richtige Wahl für diesen Teil Ihrer Anwendung.

Quentin-Starin
quelle
2
"Ein schwieriger Teil, auf den man stoßen kann, ist die kontextbezogene Autorisierung, bei der ein Befehl möglicherweise nicht nur basierend auf Benutzerrollen, sondern auch auf Geschäftsdaten / -regeln zulässig ist." - Und wie gehen Sie damit um? Zumindest für mich sind unsere Berechtigungsregeln mehrmals eine Kombination aus Rolle und aktuellem Status.
SonOfPirate
@SonOfPirate: Ereignishandler, die Domänenereignisse überwachen und Tabellen aktualisieren, die sehr speziell auf die Anforderungen der Abfragen abgestimmt sind, die die Autorisierung überprüfen. Eine Logik, die den Status überprüft und feststellt, ob eine Rolle oder eine Person autorisiert ist oder nicht, befindet sich im Ereignishandler (die Tabellen sind also fast immer ein einfaches Ja / Nein, sodass die Authentifizierungsprüfung eine einfache Suche ist). Sobald eine dieser Logik an mehreren Stellen verwendet wird, wird sie aus dem Handler in einen gemeinsam genutzten Dienst umgewandelt.
Quentin-Starin
1
Im Allgemeinen habe ich mich in den letzten Jahren immer weiter von dem Versuch entfernt, alles in einer Domäne oder einem Geschäftsobjekt zu konsolidieren. Meine Erfahrung scheint zu sein, dass es ein langfristiger Gewinn ist, die Dinge granularer und weniger gekoppelt zu machen. Während diese Methode aus einer Perspektive die Geschäftslogik (bis zu einem gewissen Grad) außerhalb der Domäne platziert, unterstützt sie später auch agile Änderungen. Es geht darum, ein Gleichgewicht zu finden.
Quentin-Starin
4
Die Antwort selbst hier referenzieren: Ich fand das Statusmuster sehr nützlich, wenn es um Überprüfungen geht, die sowohl von Berechtigungen als auch von Geschäftsregeln abhängig sind. Erstellen Sie einen abstrakten Status, der in das Domänenmodell eingefügt wird und Methoden verfügbar macht, die das Domänenobjekt als Parameter verwenden und domänenspezifische Aktionen validieren. Auf diese Weise müssen Sie nie mit dem Modell herumspielen, wenn sich Ihre Berechtigungsregeln ändern (wie dies fast immer der Fall ist), da sich die Statusimplementierungen in Ihrer Sicherheitskomponente befinden.
Aaronaught
1
Lassen Sie mich ein konkretes Beispiel auf den Tisch werfen, um zu sehen, wie Sie (beide) damit umgehen würden. Ich habe einen Veröffentlichungsvorgang für mein Domänenobjekt, bei dem der Benutzer in der Publisher-Rolle sein muss UND das Objekt sich in einem bestimmten Zustand befindet. Ich möchte die Schaltfläche "Veröffentlichen" in der Benutzeroberfläche ausblenden oder deaktivieren. Wie würden Sie das erreichen?
SonOfPirate
4

OK, hier geht für mich. Ich werde das vorwegnehmen, indem ich sage:

  • Vorzeitige Optimierung (und dies schließt auch das Design ein) kann häufig Probleme verursachen.

  • IANMF (ich bin nicht Martin Fowler);)

  • Ein schmutziges kleines Geheimnis ist, dass es bei kleinen Projekten (auch mittelgroßen) auf die Beständigkeit Ihres Ansatzes ankommt.

Genehmigung

Für mich ist Authentifizierung und Autorisierung immer ein Querschnittsthema. In meiner glücklichen kleinen Java-Welt wird das an Spring Security oder das Apache Shiro-Framework delegiert.

Validierung Für mich ist die Validierung Teil des Objekts, da ich darin sehe, was das Objekt ist.

zB Ein Auto-Objekt hat 4 Räder (OK, es gibt einige seltsame Ausnahmen, aber lassen Sie uns das seltsame dreirädrige Auto jetzt ignorieren). Ein Auto ist einfach nur gültig, wenn es (in meiner Welt) 4 hat, sodass die Validierung Teil der Definition eines Autos ist. Das bedeutet nicht, dass Sie keine Helfer-Validierungsklassen haben können.

In meiner glücklichen Java-Welt verwende ich Bean-Validierungs-Frameworks und verwende einfache Annotationen für die meisten meiner Bean-Felder. Es ist dann einfach, Ihr Objekt unabhängig von der Ebene, in der Sie sich befinden, zu validieren.

Objekterstellung

Ich sehe Factory-Kurse mit Vorsicht an. Zu oft habe ich die xyxFactoryFactoryKlasse gesehen;)

Ich erstelle in der Regel nur ein newObjekt nach Bedarf, bis ich auf einen Fall stoße, in dem die Abhängigkeitsinjektion gerechtfertigt ist (und da ich versuche, einen TDD-Ansatz zu verfolgen, tritt dieser häufig auf).

In meiner fröhlichen Java-Welt ist das zunehmend Guice, aber der Frühling ist immer noch der König hier.

Beharrlichkeit

Das ist also eine Debatte, die in Kreisen und Kreisverkehren geführt wird und bei der ich immer zwei Meinungen habe.

Manche sagen, wenn man ein Objekt auf "reine" Weise betrachtet, ist Beharrlichkeit keine zentrale Eigenschaft, sondern nur ein äußeres Anliegen.

Andere sind der Ansicht, dass Ihre Domain-Objekte implizit eine "persistable" Schnittstelle implementieren (ja, ich weiß, ich dehne mich hier aus). Daher ist es in Ordnung , die verschiedenen haben save, deleteetc Methoden auf sich. Dies wird als pragmatischer Ansatz angesehen und viele ORM-Technologien (JPA in meiner glücklichen Java-Welt) behandeln Objekte auf diese Weise.

Aus Sicherheitsgründen stelle ich sicher, dass die Berechtigungen zum Bearbeiten / Löschen / Hinzufügen / Löschen für den Dienst, der die Methode zum Speichern / Aktualisieren / Löschen für das Objekt aufruft, korrekt festgelegt sind. Wenn ich wirklich paranoid bin, kann ich sogar die Berechtigungen für das Domänenobjekt selbst festlegen.

HTH!

Martijn Verburg
quelle
2

Jimmy Nilsson geht in seinem Buch über DDD auf dieses Thema ein. Er begann mit einem anämischen Modell, wechselte in einem späteren Projekt zu nicht anämischen Modellen und entschied sich schließlich für anämische Modelle. Sein Argument war, dass die anämischen Modelle in mehreren Diensten mit unterschiedlicher Geschäftslogik wiederverwendet werden könnten.

Der Nachteil ist der Mangel an Entdeckungsfähigkeit. Die Methoden, mit denen Sie an Ihren anämischen Modellen arbeiten können, sind auf eine Reihe von Diensten verteilt, die sich an anderer Stelle befinden.

Todd Smith
quelle
Klingt nach einer bestimmten Anforderung - Wiederverwendung der Datenstruktur (Stress 'Daten') -, die dazu führt, dass der gemeinsame Teil auf einfache DTOs reduziert wird.
Victor Sergienko
Anämische Modelle ermöglichen eine bessere Wiederverwendung? Klingt eher nach einem DTO, und ich persönlich mache mir nichts daraus, Eigenschaftsdefinitionen wiederzuverwenden. Ich würde Verhaltensweisen viel lieber wiederverwenden.
Andy
@Andy - Ich stimme jedoch zu, wenn sich Ihr Verhalten in Domain Services befindet und anämische Objekte bearbeitet werden (okay, DTOs, wenn Sie dies wünschen). Steigert dies dann nicht die Wiederverwendung dieses Verhaltens? Ich spiele nur den Anwalt des Teufels.
Jpierson
@jpierson Ich habe jedoch festgestellt, dass das Verhalten in der Regel für einen bestimmten Anwendungsfall spezifisch ist. Wenn es eine Wiederverwendung gibt, die zu einer anderen Klasse gehört, der Verbraucher diese Klassen jedoch nicht verwendet, verwendet er die Klassen, die für den jeweiligen Anwendungsfall spezifisch sind. Jede Wiederverwendung erfolgt also sozusagen "hinter den Kulissen". Darüber hinaus erschwert der Versuch, Modelle wiederzuverwenden, in der Regel die Verwendung für den Konsumenten, sodass Sie letztendlich Ansichts- / Bearbeitungsmodelle auf der Benutzeroberflächenebene erstellen. In vielen Fällen wird DRY verletzt, um die Benutzererfahrung zu verbessern (z. B. DataAnnotations von Bearbeitungsmodellen).
Andy
1
Ich würde lieber Domain-Modelle verwenden, die für den Anwendungsfall erstellt wurden und dort wiederverwendet werden, wo es sinnvoll ist (dh, die Wiederverwendung kann durchgeführt werden, ohne das Verhalten wesentlich oder überhaupt zu ändern). Anstelle eines anämischen Domänenmodells, einer Serviceklasse und eines Bearbeitungsmodells haben Sie ein einziges intelligentes bearbeitbares Domänenmodell. Viel einfacher zu bedienen und zu warten, habe ich gefunden.
Andy
2

Diese Frage wurde vor langer Zeit gestellt, ist aber mit Domain Driven Design getaggt. Ich denke, die Frage selbst enthält ein grundlegendes Missverständnis der gesamten Praxis, und die Antworten, einschließlich der akzeptierten Antwort, begründen ein grundlegendes Missverständnis.

In einer DDD-Architektur gibt es kein "Domänenmodell".

Nehmen wir als Beispiel die Autorisierung. Lassen Sie mich über eine Frage nachdenken: Stellen Sie sich vor, zwei verschiedene Benutzer authentifizieren sich bei Ihrem System. Ein Benutzer hat die Berechtigung, eine bestimmte Entität zu ändern, der andere nicht. Warum nicht?

Ich hasse einfache und erfundene Beispiele, weil sie oft mehr verwirren als aufklären. Aber tun wir mal so, als hätten wir zwei verschiedene Domänen. Erstens ist eine CMS-Plattform für eine Marketingagentur. Diese Agentur hat viele Kunden, die alle über Online-Inhalte verfügen, die von Textern und Grafikern verwaltet werden müssen. Der Inhalt umfasst Blogposts sowie Landingpages für verschiedene Kunden.

Die andere Domäne ist die Bestandsverwaltung für ein Schuhunternehmen. Das System verwaltet den Lagerbestand von der Ankunft des Herstellers in Frankreich über Distributionszentren in den kontinentalen USA bis hin zu Einzelhandelsgeschäften auf lokalen Märkten und schließlich bis zum Kunden, der die Schuhe im Einzelhandel kauft.

Wenn Sie der Meinung sind, dass die Autorisierungsregeln für beide Unternehmen gleich sind, ist dies ein guter Kandidat für einen Service außerhalb der Domain. Ich bezweifle jedoch, dass die Autorisierungsregeln dieselben sind. Auch die Konzepte hinter den Nutzern wären unterschiedlich. Sicher wäre die Sprache anders. Die Marketingagentur hat wahrscheinlich Rollen wie Postautor und Asset-Eigentümer, während die Schuhfirma wahrscheinlich Rollen wie Versandkaufmann oder Lagerverwalter oder Filialleiter hat.

Diesen Konzepten sind wahrscheinlich alle Arten von Berechtigungsregeln zugeordnet, die in der Domäne modelliert werden müssen. Das bedeutet jedoch nicht, dass sie alle Teil desselben Modells sind, auch innerhalb derselben App. Denn denken Sie daran, dass es unterschiedliche begrenzte Kontexte gibt.

Vielleicht kann man ein nicht anämisches Domain-Modell im Kontext der Autorisierung als etwas anderes ansehen, als Schuhsendungen an Geschäfte mit geringem Inventar weiterzuleiten oder Website-Besucher auf die entsprechende Zielseite weiterzuleiten, je nachdem, auf welche Anzeige sie geklickt haben.

Wenn Sie mit anämischen Domänenmodellen konfrontiert sind, müssen Sie möglicherweise mehr Zeit mit der Kontextzuordnung verbringen, bevor Sie mit dem Schreiben von Code beginnen.

RibaldEddie
quelle