Pourquoi les objets de transfert de données (DTO) sont-ils un anti-pattern?

132

J'ai récemment entendu des gens dire que les objets de transfert de données (DTO) sont un anti-pattern .

Pourquoi? Quelles sont les alternatives?

ntownsend
la source
11
Peut-être parce que les objets métier sont eux-mêmes capables de transporter leurs propres données, merci beaucoup!
Zoidberg le
13
«Anti-pattern» pourrait bien être mon nominé pour «la phrase dont les 15 minutes étaient écoulées il y a longtemps». C'est synonyme de "Je ne me soucie pas de justifier ma pensée" maintenant, comme "C'est bien connu que ..."
Craig Stuntz
6
Zoidberg, envoyer des objets avec des méthodes sur le fil nous a donné CORBA, DCOM et d'autres expériences dont j'essaye d'effacer ma mémoire. Le problème est que, tôt ou tard, les gens veulent appeler ces méthodes.
Craig Stuntz
10
DTO incarnent le principe DRY, qui dans J2EE unfortunatly signifie do vous répétez.
joeforker
Vous voudrez peut-être lire ceci: L'objet de transfert de données est une honte
yegor256

Réponses:

139

Certains projets ont toutes les données deux fois . Une fois en tant qu'objets de domaine, et une fois en tant qu'objets de transfert de données.

Cette duplication a un coût énorme , donc l'architecture doit tirer un énorme avantage de cette séparation pour en valoir la peine.

KLE
la source
5
Veuillez préciser le "coût énorme". Expliquez également pourquoi le coût ne peut pas être éliminé en utilisant des techniques de génération de code pour générer les classes DTO.
John Saunders
70
+1. Deux fois? Seulement si vous avez de la chance :-) Les projets qui dupliquent des entités de domaine en tant que DTO ont également tendance à avoir des beans d'interface utilisateur presque les mêmes mais si subtilement différents pour les compléter. C'est 3. Et si, Dieu nous en préserve, il y a une sorte de communication à distance (services Web / xml-rpc / peu importe) en cours, vous pouvez facilement atteindre 4 ou 5.
ChssPly76
17
Je travaille actuellement avec une architecture de lasagne d'entreprise à 14 couches (PAS KIDDING). Je peux vous assurer que les 11 couches ou plus qui sont principalement destinées au transfert de données ne sont pas gratuites.
KarlP
10
De plus, bien que j'adore les générateurs de code lorsque je travaille avec des conceptions stupides, ils sont a) une chose sûre que vous faites mal au début. b) ils ne viennent pas gratuitement.
KarlP
7
Désolé, mais c'est juste incorrect et la mauvaise réponse a été votée et acceptée. Tout d'abord, vous pouvez utiliser la réflexion pour générer des DTO à la volée. Deuxièmement, vous pouvez utiliser une "définition racine", par exemple dans un système CASE ou dans oAW et générer le (s) BO et DTO. Troisièmement, vous pouvez utiliser un XSD et JAXB pour générer des DTO et utiliser le DTO comme base pour un BO, ou vous pouvez générer les deux à partir du XSD ... de toute façon, si quelqu'un osait transférer un EJB fraîchement extrait de la base de données. fil à un programme client ... dans les environnements où je travaille, sa tête serait bientôt sur une plaque d'argent ...
Angel O'Sphere
128

Les DTO ne sont pas un anti-pattern. Lorsque vous envoyez des données via le câble (par exemple, vers une page Web lors d'un appel Ajax), vous voulez être sûr de conserver la bande passante en envoyant uniquement les données que la destination utilisera. En outre, il est souvent pratique pour la couche de présentation d'avoir les données dans un format légèrement différent de celui d'un objet métier natif.

Je sais que c'est une question orientée Java, mais dans les langages .NET, les types anonymes, la sérialisation et LINQ permettent de construire des DTO à la volée, ce qui réduit la configuration et la surcharge de leur utilisation.

Gabe Moothart
la source
15
@John, c'est incorrect. Je le fais tout le temps. La sérialisation utilise la réflexion, qui fonctionne très bien sur les types anonymes. Passez-le simplement au sérialiseur en tant qu'objet. Et une fois qu'il est sérialisé (en xml ou json, par exemple), vous pouvez bien sûr le renvoyer à partir d'une méthode.
Gabe Moothart
8
Hum, John, ce n'est tout simplement pas vrai. Vous pouvez sérialiser des types anonymes en JSON très bien. Essayez-le dans une application MVC: retournez Json (new {Foo = "Salut!}); Je vous promets que cela fonctionne très bien. Mieux, peut-être, que les types non anonymes, car les types anonymes n'ont généralement pas de cycles dans leurs graphiques d'objets , qui cassent le sérialiseur JSON.
Craig Stuntz
1
La sérialisation Json n'est pas un DTO dans ce sens et ne s'applique donc pas. Ensuite, bien sûr, mes arguments ci-dessus s'appliquent également, à un moment donné, ils cessent tout simplement d'en valoir la peine.
Jim Barrows
1
Gabe a raison, DTO n'est pas un anti-pattern en soi (mais peut être utilisé de manière incorrecte!) Quand il n'y a pas de duplication de données. Par exemple, BO peut agréger des données de différentes sources dans un DTO.
astro
3
+1. En plus de la conservation de la bande passante, il existe de nombreuses autres raisons pour lesquelles vous voudrez des DTO. Êtes-vous même AUTORISÉ (par la politique ou la loi de l'entreprise) à envoyer tous les champs à travers le fil? De plus, dans notre entreprise, notre DAO est très complexe car il doit faire toutes ces optimisations - en travaillant dans la couche service, je suis vraiment heureux qu'ils utilisent un DTO et ne nous inquiètent pas de la relation qu'Object X entretient à une autre table n-à-n.
user64141
25

DTO un AntiPattern dans EJB 3.0 dit:

La nature lourde des Entity Beans dans les spécifications EJB antérieures à EJB 3.0, a entraîné l'utilisation de modèles de conception tels que les objets de transfert de données (DTO). Les DTO sont devenus les objets légers (qui auraient dû être les beans entité eux-mêmes en premier lieu), utilisés pour envoyer les données à travers les niveaux ... maintenant, la spécification EJB 3.0 rend le modèle de bean Entity identique à l'Objet Java Plain old (POJO). Avec ce nouveau modèle POJO, vous n'aurez plus besoin de créer un DTO pour chaque entité ou pour un ensemble d'entités ... Si vous souhaitez envoyer les entités EJB 3.0 à travers le niveau, faites-les simplement implémenter java.io.

aem
la source
6
Vrai lorsque vous transférez des objets entre des méthodes dans la même JVM, en mémoire. Ce n'est pas vrai lorsque vous sérialisez réellement sur le fil et que vous voulez contrôler la profondeur de sérialisation et / ou préserver le chargement différé.
wrschneider
Oui, et même dans la même JVM, vous devez vraiment veiller à rester dans la même situation si vous utilisez la gestion transactionnelle JEE / Spring.
Marc
20

Je ne pense pas que les DTO soient un anti-pattern en soi, mais il y a des antipatterns associés à l'utilisation des DTO. Bill Dudney fait référence à l'explosion du DTO à titre d'exemple:

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

Il y a également un certain nombre d'abus des DTO mentionnés ici:

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

Ils proviennent de systèmes à trois niveaux (utilisant généralement EJB comme technologie) comme moyen de transmettre des données entre les niveaux. La plupart des systèmes Java modernes basés sur des frameworks tels que Spring adoptent une vue simplifiée alternative utilisant les POJO comme objets de domaine (souvent annotés avec JPA, etc.) dans un seul niveau ... L'utilisation de DTO ici est inutile.

Jon
la source
3
Vous avez tout à fait raison de dire que les DTO sont un bon modèle , pas un anti-modèle, lorsqu'ils sont utilisés dans leur contexte approprié. Votre deuxième lien semble mort en ce moment, mais le plus grand abus que j'ai vu est l'endroit où chaque objet de domaine avait un "DTO" correspondant pour l'interaction avec la base de données qui n'ajoutait aucune valeur et n'était pas du tout un DTO!
David
19

Les puristes OO diraient que DTO est anti-pattern parce que les objets deviennent des représentations de table de données au lieu d'objets de domaine réel.

Darin Dimitrov
la source
9

Certains considèrent les DTO comme un anti-pattern en raison de leurs abus possibles. Ils sont souvent utilisés quand ils ne devraient pas être / n'ont pas besoin de l'être.

Cet article décrit vaguement certains abus.

Ben S
la source
1
L'article décrit beaucoup plus précisément les DTO comme un modèle dont on peut abuser.
Craig Stuntz
Cela équivaut à une réponse de lien seulement, il faut vraiment au moins une citation de l'article. Je ne sais pas comment cela a réussi à ne pas être signalé comme Pas de réponse.
Nathan Hughes
7

Si vous construisez un système distribué, les DTO ne sont certainement pas un anti-pattern. Tout le monde ne se développera pas dans ce sens, mais si vous avez (par exemple) une application Open Social fonctionnant entièrement avec JavaScript.

Il publiera une charge de données sur votre API. Celui-ci est ensuite désérialisé en une forme d'objet, généralement un objet DTO / Request. Cela peut ensuite être validé pour s'assurer que les données saisies sont correctes avant d'être converties en objet modèle.

À mon avis, c'est considéré comme un anti-modèle parce qu'il est mal utilisé. Si vous ne construisez pas un système distribué, il est probable que vous n'en ayez pas besoin.

Bealer
la source
4

L'intention d'un objet de transfert de données est de stocker des données provenant de différentes sources, puis de les transférer dans une base de données (ou une façade distante ) à la fois.

Cependant, le modèle DTO viole le principe de responsabilité unique , car le DTO stocke non seulement les données, mais les transfère également depuis ou vers la base de données / façade.

La nécessité de séparer les objets de données des objets métier n'est pas un anti-modèle, car il est probablement nécessaire de séparer de toute façon la couche de base de données .

Au lieu des DTO, vous devez utiliser les modèles d'agrégat et de référentiel, qui séparent la collection d'objets ( agrégat ) et le transfert de données ( référentiel ).

Pour transférer un groupe d'objets, vous pouvez utiliser le modèle Unité de travail , qui contient un ensemble de référentiels et un contexte de transaction; afin de transférer chaque objet dans l'agrégat séparément dans la transaction.

MovGP0
la source
4

Le DTO devient une nécessité et non un ANTI-MOTIF lorsque tous les objets de votre domaine chargent les objets associés EAGERly.

Si vous ne créez pas de DTO, vous aurez des objets transférés inutiles de votre couche de gestion vers votre couche client / Web.

Pour limiter la surcharge dans ce cas, transférez plutôt les DTO.

javadev
la source
1

La question ne devrait pas être «pourquoi», mais « quand ».

En définitive, c'est anti-pattern lorsque seul le résultat de son utilisation est plus coûteux - temps d'exécution ou maintenance. J'ai travaillé sur des projets ayant des centaines de DTO identiques aux classes d'entités de base de données. Chaque fois que vous vouliez ajouter un seul champ, vous ajoutez un identifiant comme quatre fois - à DTO, à entité, à la conversion de DTO en classes ou entités de domaine, la conversion inverse, ... Vous avez oublié certains des lieux et des données obtenus inconsistant.

Ce n'est pas anti-pattern quand vous avez vraiment besoin d'une représentation différente des classes de domaine - plus plate, plus riche, plus étroite, ...

Personnellement, je commence par la classe de domaine et je la fais circuler, avec une vérification appropriée aux bons endroits. Je peux annoter et / ou ajouter des classes "helper" pour faire des mappages, à des bases de données, à des formats de sérialisation comme JSON ou XML ... Je peux toujours diviser une classe en deux si j'en ressens le besoin.

Il s'agit de votre point de vue - je préfère regarder un objet de domaine comme un objet unique jouant différents rôles, au lieu de plusieurs objets créés les uns à partir des autres. Si le seul rôle d'un objet est de transporter des données, c'est DTO.

Rostislav Matl
la source
1

Je pense que les gens pensent que cela pourrait être un anti-modèle si vous implémentez tous les objets distants en tant que DTO. Un DTO n'est qu'un ensemble d'attributs et si vous avez de gros objets, vous transférez toujours tous les attributs même si vous n'en avez pas besoin ou que vous ne les utilisez pas. Dans ce dernier cas, préférez utiliser un modèle Proxy.

jdehaan
la source