it-swarm.com.de

Sollten Dienste immer DTOs zurückgeben, oder können sie auch Domänenmodelle zurückgeben?

Ich entwerfe eine groß angelegte Anwendung (neu), wir verwenden eine auf DDD basierende Mehrschichtarchitektur.

Wir haben MVC mit Datenschicht (Implementierung von Repositorys), Domänenschicht (Definition des Domänenmodells und der Schnittstellen - Repositorys, Dienste, Arbeitseinheit), Serviceschicht (Implementierung von Diensten). Bisher verwenden wir Domänenmodelle (meistens Entitäten) für alle Ebenen und DTOs nur als Ansichtsmodelle (in Controller geben Service Domänenmodelle zurück und Controller erstellt Ansichtsmodelle, die an die Ansicht übergeben werden).

Ich habe unzählige Artikel über die Verwendung, Nichtverwendung, Zuordnung und Weitergabe von DTOs gelesen. Ich verstehe, dass es keine endgültige Antwort gibt, bin mir aber nicht sicher, ob dies in Ordnung ist oder ob Domänenmodelle nicht von Diensten an Controller zurückgegeben werden. Wenn ich ein Domänenmodell zurückgebe, wird es immer noch nicht an die Ansicht übergeben, da der Controller immer ein ansichtsspezifisches Ansichtsmodell erstellt - in diesem Fall scheint es legitim zu sein. Andererseits fühlt es sich nicht richtig an, wenn das Domain-Modell die Business-Schicht (Service-Schicht) verlässt. Manchmal muss der Dienst ein Datenobjekt zurückgeben, das nicht in der Domäne definiert wurde, und dann müssen wir der nicht zugeordneten Domäne entweder ein neues Objekt hinzufügen oder ein POCO-Objekt erstellen (dies ist hässlich, da einige Dienste Domänenmodelle zurückgeben, andere effektiv DTOs zurückgeben).

Die Frage ist: Wenn wir ausschließlich Ansichtsmodelle verwenden, ist es in Ordnung, Domänenmodelle bis zu den Controllern zurückzugeben, oder sollten wir immer DTOs für die Kommunikation mit der Serviceebene verwenden? Wenn ja, ist es in Ordnung, Domänenmodelle basierend auf den benötigten Diensten anzupassen? (Ehrlich gesagt glaube ich nicht, da Dienste welche Domain verbrauchen sollten.) Wenn wir uns strikt an DTOs halten sollten, sollten sie in der Service-Schicht definiert werden? (Ich denke schon.) Manchmal ist es klar, dass wir DTOs verwenden sollten (z. B. wenn der Dienst viel Geschäftslogik ausführt und neue Objekte erstellt), manchmal ist es klar, dass wir nur Domänenmodelle verwenden sollten (z. B. wenn der Mitgliedschaftsdienst anämische Benutzer zurückgibt). s) - Es scheint nicht sinnvoll zu sein, ein DTO zu erstellen, das mit dem Domänenmodell identisch ist. Ich bevorzuge jedoch Konsistenz und bewährte Methoden.

Article Domain vs DTO vs ViewModel - Wie und wann man sie benutzt? (und auch einige andere Artikel) ist meinem Problem sehr ähnlich, aber es beantwortet diese Frage (n) nicht. Article Soll ich DTOs mit EF im Repository-Muster implementieren? ist ebenfalls ähnlich, befasst sich jedoch nicht mit DDD.

Haftungsausschluss: Ich habe nicht die Absicht, ein Designmuster nur zu verwenden, weil es vorhanden ist, und möchte andererseits gute Designmuster und -praktiken verwenden, da dies beim Entwerfen der Anwendung als Ganzes und beim Trennen hilft von Bedenken, selbst wenn man ein bestimmtes Muster verwendet, ist es zumindest im Moment nicht "notwendig".

Wie immer danke.

129
Robert Goldwein

es fühlt sich nicht richtig an, wenn das Domain-Modell die Business-Schicht (Service-Schicht) verlässt

Fühlen Sie sich wie Sie die Eingeweide herausziehen, oder? Laut Martin Fowler: Der Service Layer definiert die Grenzen der Anwendung, er kapselt die Domäne. Mit anderen Worten, es schützt die Domain.

Manchmal muss der Dienst ein Datenobjekt zurückgeben, das nicht in der Domäne definiert wurde

Können Sie ein Beispiel für dieses Datenobjekt angeben?

Sollten wir uns strikt an DTOs halten, sollten sie in der Serviceebene definiert werden?

Ja, da die Antwort Teil Ihrer Serviceebene ist. Wenn "irgendwo anders" definiert ist, muss die Serviceebene auf "irgendwo anders" verweisen und Ihrer Lasagne eine neue Ebene hinzufügen.

Ist es in Ordnung, Domänenmodelle bis zu den Controllern zurückzugeben, oder sollten wir immer DTOs für die Kommunikation mit der Serviceebene verwenden?

Ein DTO ist ein Antwort-/Anforderungsobjekt. Es ist sinnvoll, wenn Sie es für die Kommunikation verwenden. Wenn Sie Domänenmodelle in Ihrer Präsentationsschicht (MVC-Controller/View, WebForms, ConsoleApp) verwenden, ist die Präsentationsschicht eng mit Ihrer Domäne verbunden. Bei Änderungen in der Domäne müssen Sie Ihre Controller ändern.

Es scheint, dass es wenig Sinn macht, ein DTO zu erstellen, das mit dem Domain-Modell identisch ist)

Dies ist einer der Nachteile von DTO für neue Augen. Im Moment denken Sie an eine Vervielfältigung von Code , aber wenn Ihr Projekt erweitert wird, ist dies viel sinnvoller, insbesondere in einer Teamumgebung, in der sich verschiedene Teams befinden verschiedenen Ebenen zugeordnet.

DTO kann Ihrer Anwendung zusätzliche Komplexität verleihen, aber auch Ihren Ebenen. DTO ist eine teure Funktion Ihres Systems. Sie werden nicht kostenlos angeboten.

Warum ein DTO verwenden?

Dieser Artikel bietet sowohl Vorteile als auch Nachteile bei der Verwendung eines DTO. http://guntherpopp.blogspot.com/2010/09/to-dto-or-not-to-dto.html

Zusammenfassung wie folgt:

Verwendungszweck

  • Für große Projekte.
  • Die Projektlaufzeit beträgt 10 Jahre und mehr.
  • Strategische, geschäftskritische Anwendung.
  • Große Teams (mehr als 5)
  • Entwickler sind geografisch verteilt.
  • Die Domain und Präsentation sind unterschiedlich.
  • Reduzierung des Overhead-Datenaustauschs (ursprünglicher Zweck von DTO)

Wann nicht verwenden

  • Kleines bis mittleres Projekt (max. 5 Mitglieder)
  • Die Projektlaufzeit beträgt ca. 2 Jahre.
  • Kein separates Team für GUI, Backend usw.

Argumente gegen DTO

Argumente mit DTO

  • Ohne DTO sind Präsentation und Domain eng miteinander verbunden. (Dies ist in Ordnung für kleine Projekte.)
  • Schnittstellen-/API-Stabilität
  • Kann die Darstellungsebene optimieren, indem ein DTO zurückgegeben wird, das nur die Attribute enthält, die unbedingt erforderlich sind. Mit Linq-Projektion müssen Sie nicht eine ganze Entität ziehen.
  • Verwenden Sie Tools zur Codegenerierung, um die Entwicklungskosten zu senken
133
Yorro

Nach meiner Erfahrung sollten Sie das Praktische tun. "Das beste Design ist das einfachste Design, das funktioniert" - Einstein. Mit dem ist Geist ...

wenn wir ausschließlich Ansichtsmodelle verwenden, ist es in Ordnung, Domänenmodelle bis zu den Controllern zurückzugeben, oder sollten wir immer DTOs für die Kommunikation mit der Serviceebene verwenden?

Absolut in Ordnung! Wenn Sie über Domain Entities, DTO's und View Models verfügen und anschließend Datenbanktabellen einschließen, werden alle Felder in der Anwendung an vier Stellen wiederholt. Ich habe an großen Projekten gearbeitet, bei denen Domain Entities und View Models einwandfrei funktionierten. Die einzige Ausnahme besteht darin, dass die Anwendung verteilt ist und sich die Service-Schicht auf einem anderen Server befindet. In diesem Fall müssen DTOs aus Serialisierungsgründen über das Kabel gesendet werden.

Wenn ja, ist es in Ordnung, Domänenmodelle basierend auf den benötigten Diensten anzupassen? (Ehrlich gesagt glaube ich nicht, da Dienste verbrauchen sollten, was Domain hat.)

Im Allgemeinen stimme ich zu und sage Nein, da das Domain-Modell in der Regel die Geschäftslogik widerspiegelt und in der Regel nicht vom Verbraucher dieser Logik beeinflusst wird.

Wenn wir uns strikt an DTOs halten sollten, sollten sie in der Serviceebene definiert werden? (Ich glaube schon.)

Wenn Sie sich entscheiden, sie zu verwenden, würde ich zustimmen und sagen, dass die Service-Schicht der perfekte Ort ist, da sie die DTOs am ​​Ende des Tages zurückgibt.

Viel Glück!

9
Justin Ricketts

Ihre Anwendung scheint groß und komplex genug zu sein, da Sie sich für einen DDD-Ansatz entschieden haben. Geben Sie keine Poco-Entities oder so genannten Domain-Entities und Value-Objekte in Ihrer Service-Schicht zurück. Wenn Sie dies tun möchten, löschen Sie Ihre Service-Schicht, weil Sie sie nicht mehr benötigen! View Model- oder Datenübertragungsobjekte sollten sich in der Service-Ebene befinden, da sie Domänenmodellmitgliedern zugeordnet werden sollten und umgekehrt. Warum brauchen Sie DTO? In einer komplexen Anwendung mit vielen Szenarien sollten Sie die Anliegen der Domäne und Ihre Präsentationsansichten trennen. Ein Domänenmodell kann in mehrere DTOs unterteilt werden, und mehrere Domänenmodelle können in einem DTO zusammengefasst werden. Daher ist es besser, Ihr DTO in einer Ebenenarchitektur zu erstellen, auch wenn es mit Ihrem Modell identisch ist.

Sollten wir für die Kommunikation mit der Service-Schicht immer DTOs verwenden? Ja, Sie müssen DTO von Ihrer Service-Schicht zurückgeben, während Sie mit Ihrem Repository in der Service-Schicht sprechen mit Domänenmodellmitgliedern, ordnen Sie sie DTO zu und kehren Sie zum MVC-Controller zurück und umgekehrt.

Ist es in Ordnung, Domänenmodelle basierend auf den benötigten Diensten anzupassen? Ein Dienst kommuniziert nur mit Repository- und Domänenmethoden sowie mit Domänendiensten, in denen Sie das Geschäft lösen sollten Ihre Domain basiert auf Ihren Anforderungen und es ist nicht die Serviceaufgabe, der Domain mitzuteilen, was benötigt wird.

Sollten wir uns strikt an DTOs halten, sollten sie in der Serviceebene definiert werden? Ja, versuchen Sie, DTO oder ViewModel erst später im Dienst zu haben, da sie zugeordnet werden sollten Domain-Mitgliedern in der Service-Schicht und es ist keine gute Idee, DTO in Controllern Ihrer Anwendung zu platzieren (versuchen Sie, Request Response Muster in Ihrer Service-Schicht zu verwenden), Prost!

7
Ehsan

Bisher verwenden wir Domänenmodelle (meistens Entitäten) auf allen Ebenen und DTOs nur als Ansichtsmodelle (in Controller geben Service Domänenmodelle zurück und Controller erstellt Ansichtsmodelle, die an die Ansicht übergeben werden).

Da Domain Model Terminologie ( biquitous Language ) für Ihre gesamte Anwendung bereitstellt, ist es besser, Domain Model in großem Umfang zu verwenden.

Der einzige Grund für die Verwendung von ViewModels/DTOs ist die Implementierung von MVC-Muster in Ihrer Anwendung, um View (jede Art von Präsentationsebene) und Model (Domänenmodell) zu trennen. . In diesem Fall sind Ihre Präsentation und Ihr Domain-Modell lose miteinander verbunden.

Manchmal muss der Dienst ein Datenobjekt zurückgeben, das nicht in der Domäne definiert wurde, und dann müssen wir der nicht zugeordneten Domäne entweder ein neues Objekt hinzufügen oder ein POCO-Objekt erstellen (dies ist hässlich, da einige Dienste Domänenmodelle zurückgeben, andere effektiv DTOs zurückgeben).

Ich gehe davon aus, dass Sie über Application/Business/Domain Logic-Dienste sprechen.

Ich schlage vor, dass Sie Domain-Entitäten zurückgeben, wenn Sie können. Wenn zusätzliche Informationen zurückgegeben werden müssen, kann DTO mit mehreren Domänenentitäten zurückgegeben werden.

Manchmal haben Benutzer von Frameworks des dritten Teils, die Proxys über Domain-Entitäten generieren, Probleme, Domain-Entitäten aus ihren Diensten freizulegen, dies ist jedoch nur eine Frage der falschen Verwendung.

Die Frage ist: Wenn wir ausschließlich Ansichtsmodelle verwenden, ist es in Ordnung, Domänenmodelle bis zu den Controllern zurückzugeben, oder sollten wir immer DTOs für die Kommunikation mit der Serviceebene verwenden?

Ich würde sagen, dass es ausreicht, Domain-Entitäten in 99,9% der Fälle zurückzugeben.

Um die Erstellung von DTOs und die Zuordnung Ihrer Domain-Entitäten zu vereinfachen, können Sie AutoMapper verwenden.

3
Ilya Palkin

Ich würde vorschlagen, diese beiden Fragen zu analysieren:

  1. Verbrauchen Ihre oberen Schichten (d. H. View & View-Modelle/Controller) die Daten auf andere Weise als die Domänenschicht? Wenn viel Mapping durchgeführt wird oder sogar Logik erforderlich ist, empfehle ich Ihnen, Ihr Design zu überdenken: Es sollte wahrscheinlich näher an der tatsächlichen Verwendung der Daten liegen.

  2. Wie wahrscheinlich ist es, dass Sie Ihre oberen Schichten tief verändern? (z. B. ASP.NET gegen WPF tauschen). Wenn dies nicht der Fall ist und Ihre Architektur nicht sehr komplex ist, sollten Sie möglicherweise so viele Domänenentitäten wie möglich verfügbar machen.

Ich fürchte, es ist ein ziemlich umfassendes Thema, und es kommt wirklich darauf an, wie komplex Ihr System ist und welche Anforderungen es stellt.

2
jnovo

Ich komme zu spät zu dieser Party, aber dies ist eine so häufige und wichtige Frage, dass ich mich gezwungen fühlte, darauf zu antworten.

Mit "Services" meinen Sie die "Application Layer", die von Evan's im Blue Book beschrieben wurde? Ich gehe davon aus, dass Sie dies tun. In diesem Fall lautet die Antwort, dass sie keine DTOs zurückgeben sollen . Ich schlage vor, Kapitel 4 im blauen Buch mit dem Titel "Isolating the Domain" zu lesen.

In diesem Kapitel sagt Evans Folgendes zu den Ebenen:

Partitionieren Sie ein komplexes Programm in Ebenen. Entwickeln Sie in jeder Ebene ein zusammenhängendes Design, das nur von den darunter liegenden Ebenen abhängt.

Dafür gibt es gute Gründe. Wenn Sie das Konzept Teilreihenfolge als Maß für die Komplexität der Software verwenden, wird die Komplexität erhöht, wenn eine Schicht von einer darüber liegenden Schicht abhängt, was die Wartbarkeit verringert.

Wenn Sie dies auf Ihre Frage anwenden, sind DTOs wirklich ein Adapter, der ein Problem der Benutzeroberfläche/Präsentationsebene darstellt. Denken Sie daran, dass Remote-/prozessübergreifende Kommunikation genau das Ziel eines DTO ist (es ist erwähnenswert, dass Fowler in diesem Beitrag auch dagegen spricht, dass DTOs Teil einer Service-Schicht sind, obwohl er nicht unbedingt über DDD spricht Sprache).

Wenn Ihre Anwendungsebene von diesen DTOs abhängt, hängt sie von einer übergeordneten Ebene ab und Ihre Komplexität nimmt zu. Ich kann garantieren, dass dies die Wartung Ihrer Software erschwert.

Was ist zum Beispiel, wenn Ihr System mit mehreren anderen Systemen oder Client-Typen verbunden ist, für die jeweils ein DTO erforderlich ist? Woher wissen Sie, welches DTO eine Methode Ihres Anwendungsdienstes zurückgeben soll? Wie würden Sie dieses Problem sogar lösen, wenn Ihre bevorzugte Sprache das Überladen einer Methode (in diesem Fall der Dienstmethode) basierend auf dem Rückgabetyp nicht zulässt? Und selbst wenn Sie einen Weg finden, warum verletzen Sie Ihre Anwendungsebene, um ein Anliegen der Präsentationsebene zu unterstützen?

In der Praxis ist dies ein Schritt auf einem Weg, der in einer Spaghetti-Architektur enden wird. Ich habe diese Art der Verschiebung und ihre Ergebnisse in meiner eigenen Erfahrung gesehen.

Wo ich zurzeit arbeite, geben Dienste in unserer Anwendungsebene Domänenobjekte zurück. Wir betrachten dies nicht als ein Problem, da die Schnittstellenschicht (d. H. Benutzeroberfläche/Präsentation) von der Domänenschicht abhängt, die darunter liegt. Außerdem wird diese Abhängigkeit auf einen Abhängigkeitstyp "Nur Referenz" minimiert, weil:

a) Die Schnittstellenschicht kann nur als schreibgeschützte Rückgabewerte auf diese Domänenobjekte zugreifen, die durch Aufrufe der Anwendungsschicht abgerufen werden

b) Methoden für Dienste in der Anwendungsschicht akzeptieren als Eingabe nur "Roh" -Eingaben (Datenwerte) oder Objektparameter (um die Anzahl der Parameter zu verringern, falls erforderlich), die in dieser Schicht definiert sind. Insbesondere akzeptieren Anwendungsdienste niemals Domänenobjekte als Eingabe.

Die Schnittstellenebene verwendet Zuordnungstechniken, die in der Schnittstellenebene selbst definiert sind, um Domänenobjekte DTOs zuzuordnen. Auch dies hält DTOs darauf konzentriert, Adapter zu sein, die von der Schnittstellenschicht gesteuert werden.

2
BitMask777

Meiner Erfahrung nach ist es eine schlechte Idee, die Domänenobjekte der Benutzeroberfläche auszusetzen, es sei denn, Sie verwenden ein OO= UI-Muster (wie nackte Objekte) Die Benutzeroberfläche ändert sich und zwingt Ihre Objekte, sich diesen Änderungen anzupassen. Am Ende bedienen Sie zwei Master: UI und DOMAIN, was eine sehr schmerzhafte Erfahrung ist. Glauben Sie mir, Sie möchten nicht dabei sein Benutzer, das DOMAIN-Modell zum Speichern der Geschäftsregeln und das Persistenzmodell zum effektiven Speichern von Daten, die alle unterschiedliche Anforderungen der Anwendung erfüllen. Ich bin gerade dabei, einen Blog-Beitrag darüber zu schreiben, und werde ihn hinzufügen, wenn er fertig ist.

1
max_cervantes