Warum sind Datenübertragungsobjekte (DTOs) ein Anti-Pattern?

132

Ich habe kürzlich gehört, dass Leute sagen, dass Datenübertragungsobjekte (DTOs) ein Anti-Pattern sind .

Warum? Was sind die Alternativen?

ntownsend
quelle
11
Vielleicht, weil Geschäftsobjekte selbst in der Lage sind, ihre eigenen Daten zu transportieren. Vielen Dank!
Zoidberg
13
"Anti-Pattern" könnte mein Kandidat für "Phrase sein, deren 15 Minuten vor langer Zeit abgelaufen sind". Es ist gleichbedeutend mit "Ich möchte mein Denken nicht rechtfertigen", wie "Es ist bekannt, dass ..."
Craig Stuntz,
6
Zoidberg, der Objekte mit Methoden über den Draht schickte, gab uns CORBA, DCOM und andere Erfahrungen, an die ich meine Erinnerung löschen wollte. Das Problem ist, dass die Leute früher oder später diese Methoden aufrufen wollen .
Craig Stuntz
10
DTOs verkörpern das DRY - Prinzip, das unfortunatly in J2EE steht für do wiederholen sich.
Joeforker
Vielleicht möchten Sie dies lesen: Datenübertragungsobjekt ist eine Schande
yegor256

Antworten:

139

Einige Projekte haben alle Daten zweimal . Einmal als Domänenobjekte und einmal als Datenübertragungsobjekte.

Diese Vervielfältigung ist mit enormen Kosten verbunden , daher muss die Architektur einen großen Nutzen aus dieser Trennung ziehen, um sich zu lohnen.

KLE
quelle
5
Bitte erläutern Sie die "enormen Kosten". Sagen Sie auch, warum die Kosten nicht durch Codegenerierungstechniken zum Generieren der DTO-Klassen beseitigt werden können.
John Saunders
70
+1. Zweimal? Nur wenn Sie Glück haben :-) Projekte, die Domain-Entitäten als DTO duplizieren, haben in der Regel auch fast die gleichen, aber ach so subtil unterschiedlichen UI-Beans, um sie zu ergänzen. Das ist 3. Und wenn, Gott bewahre, eine Art Remoting (Webdienste / xml-rpc / was auch immer) stattfindet, können Sie leicht zu 4 oder 5 gelangen.
ChssPly76
17
Ich arbeite derzeit mit einer unternehmerischen 14-Schicht-Lasagne-Architektur (NOT KIDDING). Ich kann Ihnen versichern, dass die etwa 11 Schichten, die hauptsächlich für Datentransfer bestimmt sind, nicht kostenlos sind.
KarlP
10
Auch wenn ich Codegeneratoren bei der Arbeit mit dummen Designs absolut liebe, sind sie a) sicher, dass Sie es von Anfang an falsch machen. b) Sie kommen nicht kostenlos.
KarlP
7
Sorry, aber das ist einfach falsch und die falsche Antwort wurde hoch gewählt und akzeptiert. Zunächst können Sie mithilfe der Reflexion DTOs im laufenden Betrieb generieren. Zweitens können Sie eine "Root-Definition" verwenden, z. B. in einem CASE-System oder in oAW, und die BO und DTO (s) generieren. Drittens können Sie eine XSD und eine JAXB verwenden, um DTOs zu generieren und die DTO als Basis für eine BO zu verwenden, oder Sie können beide aus der XSD generieren ... jedenfalls, wenn jemand es wagen würde, eine frisch aus der DB abgerufene EJB zu übertragen Draht zu einem Kundenprogramm ... in den Umgebungen, in denen ich arbeite, würde sein Kopf ziemlich bald auf einem silbernen Teller sein ...
Angel O'Sphere
128

DTOs sind kein Anti-Pattern. Wenn Sie einige Daten über das Kabel senden (z. B. an eine Webseite in einem Ajax-Aufruf), möchten Sie sicherstellen, dass Sie Bandbreite sparen, indem Sie nur Daten senden, die vom Ziel verwendet werden. Außerdem ist es für die Präsentationsschicht häufig praktisch, die Daten in einem etwas anderen Format als ein natives Geschäftsobjekt zu haben.

Ich weiß, dass dies eine Java-orientierte Frage ist, aber in .NET-Sprachen ermöglichen anonyme Typen, Serialisierung und LINQ die Erstellung von DTOs im laufenden Betrieb, wodurch die Einrichtung und der Aufwand für deren Verwendung verringert werden.

Gabe Moothart
quelle
15
@ John, das ist falsch. Das mache ich die ganze Zeit. Bei der Serialisierung wird die Reflektion verwendet, die bei anonymen Typen problemlos funktioniert. Übergeben Sie es einfach als Objekt an den Serializer. Und sobald es serialisiert ist (zum Beispiel in XML oder JSON), können Sie es natürlich von einer Methode zurückgeben.
Gabe Moothart
8
Ähm, John, das stimmt einfach nicht. Sie können anonyme Typen problemlos in JSON serialisieren. Versuchen Sie es in einer MVC-App: return Json (new {Foo = "Hi there!}); Ich verspreche Ihnen, dass es einwandfrei funktioniert. Vielleicht besser als nicht anonyme Typen, da anonyme Typen im Allgemeinen keine Zyklen in ihren Objektgraphen haben , die den JSON-Serializer brechen.
Craig Stuntz
1
Die Json-Serialisierung ist in diesem Sinne kein DTO und gilt daher nicht. Dann gelten natürlich auch meine obigen Argumente, irgendwann hören sie einfach auf, es wert zu sein.
Jim Barrows
1
Gabe hat recht, DTO ist an sich kein Anti-Pattern (kann aber bei falscher Verwendung verwendet werden!), Wenn keine Daten dupliziert werden. Beispielsweise kann BO Daten aus verschiedenen Quellen zu einem DTO zusammenfassen.
Astro
3
+1. Neben der Erhaltung der Bandbreite gibt es noch viele andere Gründe, warum Sie DTOs wünschen. Dürfen Sie (nach Unternehmensrichtlinien oder Gesetzen) sogar jedes Feld über das Kabel senden? Außerdem ist unser DAO in unserem Unternehmen sehr komplex, da es all diese Optimierungen vornehmen muss. Wenn ich in der Service-Schicht arbeite, bin ich wirklich froh, dass sie ein DTO verwenden und uns keine Sorgen über die Beziehung machen, die Object X hat zu einer anderen n-zu-n-Tabelle.
user64141
25

DTO ein AntiPattern in EJB 3.0 sagt:

Das hohe Gewicht von Entity Beans in EJB-Spezifikationen vor EJB 3.0 führte zur Verwendung von Entwurfsmustern wie Data Transfer Objects (DTO). DTOs wurden zu den leichtgewichtigen Objekten (die eigentlich die Entity-Beans selbst sein sollten), die zum Senden der Daten über die Ebenen verwendet wurden. Mit der EJB 3.0-Spezifikation wird das Entity-Bean-Modell jetzt mit dem einfachen alten Java-Objekt (POJO) identisch. Mit diesem neuen POJO-Modell müssen Sie nicht mehr für jede Entität oder für eine Reihe von Entitäten ein DTO erstellen. Wenn Sie die EJB 3.0-Entitäten über die Ebene senden möchten, implementieren Sie sie einfach java.io.Serialiazable

aem
quelle
6
True, wenn Sie Objekte zwischen Methoden in derselben JVM im Speicher übertragen. Nicht wahr, wenn Sie tatsächlich über das Kabel serialisieren und steuern möchten, wie tief die Serialisierung erfolgen soll, und / oder das verzögerte Laden beibehalten sollen.
Wrschneider
Ja, und selbst in derselben JVM sollten Sie wirklich darauf achten, im selben Bereich zu bleiben, wenn Sie das JEE / Spring-Transaktionsmanagement verwenden.
Marc
20

Ich denke nicht, dass DTOs per se ein Anti-Pattern sind, aber es gibt Antimuster, die mit der Verwendung von DTOs verbunden sind. Bill Dudney nennt die DTO-Explosion als Beispiel:

http://www.softwaresummit.com/2003/speakers/DudneyJ2EEAntiPatterns.pdf

Es gibt auch eine Reihe von Missbräuchen von DTOs, die hier erwähnt werden:

http://anirudhvyas.com/root/2008/04/19/abuses-of-dto-pattern-in-java-world/

Sie entstanden aufgrund dreistufiger Systeme (normalerweise unter Verwendung von EJB als Technologie) als Mittel zum Übertragen von Daten zwischen Ebenen. Die meisten modernen Java-Systeme, die auf Frameworks wie Spring basieren, verwenden eine alternative vereinfachte Ansicht, bei der POJOs als Domänenobjekte (häufig mit JPA usw. versehen) in einer einzigen Ebene verwendet werden. Die Verwendung von DTOs ist hier nicht erforderlich.

Jon
quelle
3
Sie haben völlig Recht, dass DTOs ein gutes Muster sind , kein Anti-Muster, wenn sie in ihrem richtigen Kontext verwendet werden. Ihr zweiter Link scheint momentan tot zu sein, aber der größte Missbrauch, den ich gesehen habe, ist, dass jedes Domain-Objekt ein entsprechendes "DTO" für die Datenbankinteraktion hatte, das keinen Wert hinzufügte und überhaupt kein DTO war!
David
19

OO-Puristen würden sagen, dass DTO ein Anti-Pattern ist, da Objekte zu Datentabellendarstellungen anstelle von realen Domänenobjekten werden.

Darin Dimitrov
quelle
9

Einige betrachten DTOs aufgrund ihres möglichen Missbrauchs als Anti-Muster. Sie werden oft verwendet, wenn sie nicht sein sollten / müssen.

Dieser Artikel beschreibt vage einige Missbräuche.

Ben S.
quelle
1
Der Artikel beschreibt DTOs viel genauer als ein Muster, das missbraucht werden kann.
Craig Stuntz
Dies ist eine Antwort nur mit Link, es braucht wirklich mindestens ein Zitat aus dem Artikel. Ich weiß nicht, wie es gelungen ist, nicht als Nicht eine Antwort gekennzeichnet zu werden.
Nathan Hughes
Link ist tot, versuchen Sie es mit web.archive.org/web/20110707143818/https://anirudhvyas.com/root/…
Davi Lima
7

Wenn Sie ein verteiltes System erstellen, sind DTOs sicherlich kein Anti-Pattern. Nicht jeder wird sich in diesem Sinne entwickeln, aber wenn Sie eine (zum Beispiel) Open Social-App haben, auf der JavaScript ausgeführt wird.

Es wird eine Menge Daten an Ihre API senden. Dies wird dann in eine Form von Objekt deserialisiert, typischerweise ein DTO / Request-Objekt. Dies kann dann überprüft werden, um sicherzustellen, dass die eingegebenen Daten korrekt sind, bevor sie in ein Modellobjekt konvertiert werden.

Meiner Meinung nach wird es als Anti-Muster angesehen, weil es missbraucht wird. Wenn Sie kein verteiltes System erstellen, benötigen Sie diese wahrscheinlich nicht.

Bealer
quelle
4

Die Absicht eines Datenübertragungsobjekts besteht darin, Daten aus verschiedenen Quellen zu speichern und sie dann sofort in eine Datenbank (oder Remote Facade ) zu übertragen.

Das DTO-Muster verstößt jedoch gegen das Prinzip der Einzelverantwortung , da das DTO Daten nicht nur speichert, sondern auch von oder zur Datenbank / Fassade überträgt.

Die Notwendigkeit, Datenobjekte von Geschäftsobjekten zu trennen, ist kein Gegenmuster, da es wahrscheinlich sowieso erforderlich ist, die Datenbankschicht zu trennen .

Anstelle von DTOs sollten Sie die Aggregat- und Repository-Muster verwenden, die die Sammlung von Objekten ( Aggregat ) und die Datenübertragung ( Repository ) trennen ) .

Um eine Gruppe von Objekten zu übertragen, können Sie das Muster " Arbeitseinheit" verwenden , das eine Reihe von Repositorys und einen Transaktionskontext enthält. um jedes Objekt im Aggregat separat innerhalb der Transaktion zu übertragen.

MovGP0
quelle
4

DTO wird zu einer Notwendigkeit und nicht zu einem ANTI-MUSTER, wenn alle Domänenobjekte die zugehörigen Objekte EAGERly laden.

Wenn Sie keine DTOs erstellen, werden unnötige Objekte von Ihrer Geschäftsschicht auf Ihre Client- / Webschicht übertragen.

Um den Overhead für diesen Fall zu begrenzen, übertragen Sie lieber DTOs.

javadev
quelle
1

Die Frage sollte nicht "warum" sein, sondern " wann ".

Auf jeden Fall ist es ein Anti-Muster, wenn nur das Ergebnis der Verwendung höhere Kosten verursacht - Laufzeit oder Wartung. Ich habe an Projekten mit Hunderten von DTOs gearbeitet, die mit Datenbankentitätsklassen identisch sind. Jedes Mal, wenn Sie ein einzelnes Feld hinzufügen möchten, fügen Sie eine ID hinzu, um sie viermal hinzuzufügen - zu DTO, zu Entität, zur Konvertierung von DTO zu Domänenklassen oder Entitäten, zur inversen Konvertierung, ... Sie haben einige der erhaltenen Stellen und Daten vergessen inkonsistent.

Es ist kein Anti-Pattern, wenn Sie wirklich eine andere Darstellung von Domänenklassen benötigen - flacher, reicher, enger, ...

Persönlich beginne ich mit der Domain-Klasse und gebe sie weiter, mit der richtigen Überprüfung an den richtigen Stellen. Ich kann einige "Hilfs" -Klassen mit Anmerkungen versehen und / oder hinzufügen, um Zuordnungen, Datenbanken, Serialisierungsformate wie JSON oder XML vorzunehmen. Ich kann eine Klasse jederzeit in zwei Klassen aufteilen, wenn ich dies für erforderlich halte.

Es geht um Ihre Sichtweise - ich betrachte ein Domänenobjekt lieber als ein einzelnes Objekt, das verschiedene Rollen spielt, anstatt als mehrere Objekte, die voneinander erstellt wurden. Wenn ein Objekt nur Daten transportiert, ist es DTO.

Rostislav Matl
quelle
1

Ich denke, die Leute meinen, es könnte ein Anti-Pattern sein, wenn Sie alle Remote-Objekte als DTOs implementieren. Ein DTO ist nur eine Reihe von Attributen. Wenn Sie große Objekte haben, übertragen Sie immer alle Attribute, auch wenn Sie sie nicht benötigen oder verwenden. Im letzteren Fall bevorzugen Sie die Verwendung eines Proxy-Musters.

jdehaan
quelle