it-swarm.com.de

Verwenden Sie das DTO-Muster oder serialisieren Sie Domänenobjekte

Ein Kollege von mir ist gegen die Verwendung von DTOs und meint eher, wir sollten nur Entity/Domain-Objekte zurückgeben, die für eine REST api. Serialisiert. Er ist der Meinung, dass DTO ein Anti-Pattern ist, und hat diesen Artikel Data Transfer Object ist eine Schande . Obwohl der Artikel einen anderen Ansatz zur Lösung des "DTO-Problems" hat, als mein Kollege vorschlägt. Persönlich habe ich es aus drei Gründen immer vorgezogen, DTO zu verwenden.

  1. Meine API ist nicht an meine Domänenschicht gebunden, daher habe ich Flexibilität. Die Domänenschicht kann sich ändern, ohne die API zu beeinträchtigen, und umgekehrt.
  2. Wenn ich ORMs wie JPA/Hibernate verwende, stelle ich nicht versehentlich Unmengen von Abfragen aus, um das zu serialisierende Objektdiagramm zu erstellen, oder muss Logik/Anmerkungen in meine Entitätsebene einfügen, um die Serialisierung zu steuern.
  3. Ich kann leicht steuern, was und wie viele Informationen über die Leitung gesendet werden. IE Senden Sie die Handvoll Felder, die der Client möchte, anstatt 30 Felder.

Punkt 2 ist keine große Sache, wenn kein ORM verwendet wird. Ich kann immer noch sehen, ob es Probleme gibt, wenn Sie so etwas wie das Folgende hatten

class Order {

    private Long orderId;

    // additional fields go here

    private List<LineItem> lineItems;
}

class LineItem {

    private Long id;
    private BigDecimal amount;
    private int qty;
}

Nehmen wir an, der Kunde wollte nur eine Liste mit Bestellungen und kümmerte sich nicht um die Werbebuchungen. Wenn kein DTO beteiligt wäre, könnten Sie das Order-Objekt füllen und die lineItems als leere Liste belassen. In einigen Fällen wäre es jedoch umständlich und verwirrend, sie zu füllen, in anderen nicht. Oder alle Daten könnten geladen und übertragen werden, aber das scheint verschwenderisch zu sein und potenzielle Auswirkungen auf die Leistung zu haben.

Gibt es eine angemessene Zeit, um DTOs zu überspringen und nur das Domänenobjekt zurückzugeben? Oder denke ich falsch und DTO ist kein Muster, das verwendet werden sollte. Gibt es einen anderen Ansatz?

7
greyfox

Erstens ist das bloße Zitieren eines Artikels im Internet keine ausreichende Rechtfertigung für eine Änderung einer Praxis. Sie müssen die Vor- und Nachteile abwägen und sich selbst entscheiden.

Beachten Sie, dass der Autor des von Ihnen zitierten Artikels hasst ORMs . Er folgt einem strengen Prinzip der Kapselung von Code mit seinen Daten, das eine Art Grundprinzip der Objektorientierung darstellt. Er mag ORM nicht, weil es Klassen ihrer Intelligenz beraubt, und er irrt sich nicht.

In seinem ORM-Hassartikel schreibt er (mehr oder weniger), dass Klassen dafür verantwortlich sein sollten, sich in der Datenbank zu speichern, eine Praxis, die gegen ein Prinzip verstößt, das als "Persistenz-Ignoranz" bezeichnet wird. Persistenz-Ignoranz bedeutet einfach, dass Klassen nichts über ihren Datenbank-Overlord wissen sollten, und es ist mit ORMs auf realistische Weise schwer zu erreichen . Er umgeht das Problem der Persistenz-Ignoranz mithilfe von Schnittstellen, sodass seine Daten die zugrunde liegende Implementierung nicht kennen.

Um fair zu sein, schreibe ich Code, der seinem unter der Haube sehr ähnlich sieht, wenn auch etwas schlanker als sein (Java hat den Ruf, sehr ausführlich zu sein, und ich kümmere mich nicht um die DTO-Schnittstellen). Nachdem ich eine Weile mit Entity Framework gerungen hatte, begann ich Dapper zu verwenden und stattdessen SQL-Abfragen zu schreiben. Ich erhalte eine bessere Leistung, weniger Komplexität und eine feinere Ausrichtung der Datenbank.

Die Klasse, die Ihr sogenanntes "Datenübertragungsobjekt" implementiert, ist ein guter Ort, um diesen Code einzufügen. Alles, was Sie tun müssen, ist, ihm ein IdbConnection -Objekt zu übergeben, und die Klasse verfügt über alles, was sie zum Lesen und Fortbestehen in der Datenbank benötigt.

Ich denke meine Frage ist, warum dies eine Entweder-Oder-Wahl sein muss. Wenn Sie etwas aus der Datenbank benötigen, für das ein DTO erforderlich ist, verwenden Sie ein DTO. Wenn Sie möchten, was Sie als "Domänenobjekt" bezeichnen, verwenden Sie dies stattdessen.

9
Robert Harvey

Ich denke, Data Domain Objects (DTOs) sollten von den Objekten der Präsentationsschicht getrennt werden.

In Bezug auf "Datenübertragungsobjekte sind schade" lese ich solche Artikel über Anti-Pattern und so weiter. Ich denke, die Leute sind nur faul, dies zu sagen, weil sie weniger Codes schreiben wollen und möglicherweise nicht wirklich verstehen, warum das Design-Pattern darin enthalten ist der erste Ort.

Erstens aus Sicherheitsgründen, dh Sie möchten Ihre innere Datenstruktur nicht der Außenwelt aussetzen und sollten dies auch nicht. Das Objekt der Präsentationsschicht bietet Ihnen die Möglichkeit, die Antwortdaten auf das zu beschränken, was NUR ERFORDERLICH ist.

Abgesehen von der Sicherheit ist die Trennung von Verantwortung und Datenobjekten sinnvoller, wenn Sie sich in einer Welt von Microservices oder verteilten Diensten befinden oder Ihre Anwendung modular aufgebaut ist.

Stellen Sie sich Folgendes vor: Sie haben 3 Bibliotheken für erholsame,

  • A. Benutzer-API (die Serviceschnittstelle) - hängt von B ab
  • B. Benutzerdatenobjekte
  • C. Benutzeranbieter (die tatsächliche Implementierung) - hängt von A & B ab

und 3 Bibliotheken für die Datenspeicherschicht (es sollte eine Geschäftsschicht vorhanden sein, aber ich überspringe dies der Einfachheit halber)

  • D. Benutzerdatendienst (Schnittstelle) - abhängig von E.
  • E. Benutzerdatenobjekte (DTOs)
  • F. Benutzerdatendienstanbieter (Implementierung) - hängt von D & E ab

Stellen Sie sich vor, Sie haben ein anderes Datendienstmodul, das nur Benutzerdatenobjekte verwenden möchte. Es sollte nur von der Bibliothek E abhängen. Wenn es dann einen anderen erholsamen Dienst gibt, der Benutzerdatenobjekte ausleihen möchte, können sie sich nur auf B verlassen. Und so weiter sollten die Dinge transparent und so atomar wie möglich sein, und das fördert die Wiederverwendbarkeit von Code.

Sogar einige mögen sagen, dass meine Anwendung klein ist, und ich möchte sie nur schnell ohne alle Boilerplates herausbringen. Nun, das können Sie, aber ich rate nicht, das ist die Erfahrung, die mir sagt, dass ich das nicht tun soll. Wir haben in der Vergangenheit viele dieser Beispiele gesehen, RoR, NodeJS, ... Sie haben es genannt.

Die Sache ist, sie werden Sie sehr schnell irgendwohin bringen, aber nur einfache Dinge auf einfache Weise lösen, aber komplexe Dinge werden unpraktisch komplex gemacht.

Für mich werde ich also lieber von Anfang an die Best Practices befolgen und mich weniger später Sorgen machen, als das Ganze zu verschrotten und zu wiederholen, und mir vertrauen, dass Sie die gleiche (wenn nicht mehr) Zeit dafür aufwenden werden es gleich später.

0
NG CHEE WEI