web-dev-qa-db-fra.com

Les services doivent-ils toujours renvoyer les DTO ou peuvent-ils également renvoyer des modèles de domaine?

Je (re) conçois une application à grande échelle, nous utilisons une architecture multicouche basée sur DDD.

Nous avons MVC avec couche de données (implémentation de référentiels), couche de domaine (définition du modèle de domaine et des interfaces - référentiels, services, unité de travail), couche de service (implémentation de services). Jusqu'à présent, nous utilisons des modèles de domaine (principalement des entités) sur toutes les couches et nous utilisons les DTO uniquement comme modèles de vue (dans le contrôleur, le ou les modèles de domaine renvoyés par le service et le contrôleur crée le modèle de vue, qui est transmis à la vue).

J'ai lu d'innombrables articles sur l'utilisation, la non-utilisation, la cartographie et la transmission de DTO. Je comprends qu’il n’ya pas de réponse définitive, mais je ne suis pas sûr que ce soit acceptable ou non de renvoyer des modèles de domaine à partir de services aux contrôleurs. Si je renvoie le modèle de domaine, il n'est toujours pas transmis à la vue, car le contrôleur crée toujours un modèle de vue spécifique à la vue - dans ce cas, il semble légitime. D'un autre côté, le modèle de domaine qui quitte la couche de gestion (couche de service) ne se sent pas bien. Parfois, le service doit renvoyer un objet de données non défini dans le domaine, puis nous devons soit ajouter un nouvel objet au domaine non mappé, soit créer un objet POCO (ce qui est moche, car certains services renvoient des modèles de domaine, certains restituer efficacement les DTO).

La question est la suivante: si nous utilisons strictement les modèles de vue, est-il possible de renvoyer les modèles de domaine jusqu'aux contrôleurs, ou devrions-nous toujours utiliser les DTO pour la communication avec la couche service? Si oui, est-il possible d'ajuster les modèles de domaine en fonction des besoins en services? (Franchement, je ne le pense pas, car les services devraient consommer quel domaine a.) Si nous devons nous en tenir strictement aux DTO, devraient-ils être définis dans la couche service? (Je pense que oui.) Parfois, il est clair que nous devons utiliser des DTO (par exemple, lorsque le service exécute une grande partie de la logique métier et crée de nouveaux objets), il est parfois clair que nous devons utiliser uniquement des modèles de domaine (par exemple, lorsque le service d'appartenance renvoie un utilisateur anémique ( s) - il semble peu logique de créer un DTO identique à un modèle de domaine) - mais je préfère la cohérence et les bonnes pratiques.

Article Domaine vs DTO vs ViewModel - Comment et quand les utiliser? (ainsi que d'autres articles) est très similaire à mon problème, mais il ne répond pas à cette (ces) question (s). Article Devrais-je implémenter des DTO dans un modèle de référentiel avec EF? est également similaire, mais ne traite pas de DDD.

Clause de non-responsabilité: je n'ai pas l'intention d'utiliser un modèle de conception uniquement parce qu'il existe et qu'il est sophistiqué. Par contre, j'aimerais utiliser de bons modèles et pratiques de conception, également parce que cela permet de concevoir l'application dans son ensemble, aide à la séparation des préoccupations, même utiliser un modèle particulier n'est pas "nécessaire", du moins pour le moment.

Comme toujours, merci.

129
Robert Goldwein

cela ne semble pas correct lorsque le modèle de domaine quitte la couche de gestion (couche de service)

Vous fait sentir que vous tirez les tripes, non? Selon Martin Fowler: la couche de service définit la frontière de l'application, elle encapsule le domaine. En d'autres termes, il protège le domaine.

Parfois, le service doit renvoyer un objet de données qui n'a pas été défini dans le domaine

Pouvez-vous donner un exemple de cet objet de données?

Si nous devons nous en tenir strictement aux DTO, devraient-ils être définis dans la couche service?

Oui, car la réponse fait partie de votre couche de service. S'il est défini "ailleurs", la couche de service doit faire référence à "ailleurs", en ajoutant une nouvelle couche à votre lasagne.

est-il correct de renvoyer les modèles de domaine jusqu'aux contrôleurs, ou devrions-nous toujours utiliser les DTO pour la communication avec la couche service?

Un DTO est un objet de réponse/demande, cela a du sens si vous l'utilisez pour la communication. Si vous utilisez des modèles de domaine dans votre couche de présentation (Contrôleurs MVC/View, WebForms, ConsoleApp), la couche de présentation est étroitement liée à votre domaine. Toute modification dans le domaine nécessite que vous modifiiez vos contrôleurs.

il semble que créer un DTO identique au modèle de domaine n'aurait pas de sens.)

C'est l'un des inconvénients du DTO pour les nouveaux yeux. Pour le moment, vous envisagez la duplication du code , mais au fur et à mesure de l'expansion de votre projet, cela aurait beaucoup plus de sens, en particulier dans un environnement d'équipe où différentes équipes sont assigné à différentes couches.

DTO peut ajouter de la complexité à votre application, mais vos couches le sont aussi. DTO est une fonctionnalité coûteuse de votre système, ils ne sont pas gratuits.

Pourquoi utiliser un DTO

Cet article présente à la fois l’avantage et l’inconvénient d’utiliser un DTO, http://guntherpopp.blogspot.com/2010/09/to-dto-or-not-to-dto.html

Résumé comme suit:

Quand utiliser

  • Pour les grands projets.
  • La durée de vie du projet est de 10 ans et plus.
  • Application stratégique et critique.
  • Grandes équipes (plus de 5)
  • Les développeurs sont répartis géographiquement.
  • Le domaine et la présentation sont différents.
  • Réduire les échanges de données en surcharge (l’objet original de DTO)

Quand ne pas utiliser

  • Projet de taille petite à moyenne (5 membres maximum)
  • La durée de vie du projet est d'environ 2 ans.
  • Aucune équipe séparée pour l'interface graphique, le backend, etc.

Arguments contre DTO

Arguments avec DTO

  • Sans DTO, la présentation et le domaine sont étroitement couplés. (C'est ok pour les petits projets.)
  • Stabilité de l'interface/API
  • Peut fournir une optimisation pour la couche de présentation en renvoyant un DTO contenant uniquement les attributs absolument nécessaires. Avec linq-projection , vous n’avez pas à tirer une entité entière.
  • Pour réduire les coûts de développement, utilisez des outils générateurs de code.
133
Yorro

D'après mon expérience, vous devriez faire ce qui est pratique. "Le meilleur design est le design le plus simple qui fonctionne" - Einstein. Avec ça, c'est l'esprit ...

si nous utilisons strictement les modèles de vue, est-il possible de renvoyer les modèles de domaine jusqu'aux contrôleurs, ou devrions-nous toujours utiliser les DTO pour la communication avec la couche service?

Absolument c'est ok! Si vous avez des entités de domaine, des DTO et des modèles de vue, tous les champs de l'application sont répétés à 4 endroits, y compris les tables de base de données. J'ai travaillé sur de grands projets où les entités de domaine et les modèles de vue fonctionnaient parfaitement. La seule exception à cette règle est que l'application est distribuée et que la couche service réside sur un autre serveur. Dans ce cas, les DTO doivent envoyer des données de bout en bout pour des raisons de sérialisation.

Si oui, est-il possible d'ajuster les modèles de domaine en fonction des besoins en services? (Franchement, je ne le pense pas, car les services devraient consommer quel domaine a.)

En général, je suis d’accord pour dire non, car le modèle de domaine est généralement le reflet de la logique commerciale et n’est généralement pas façonné par le consommateur de cette logique.

Si nous devons nous en tenir strictement aux DTO, devraient-ils être définis dans la couche service? (Je le pense.)

Si vous décidez de les utiliser, je dirais que la couche Service est l’endroit idéal pour renvoyer les DTO à la fin de la journée.

Bonne chance!

9
Justin Ricketts

Il semble que votre application soit assez grosse et complexe, car vous avez décidé de passer par la méthode DDD. Ne renvoyez pas vos entités poco ou appelées entités de domaine et objets de valeur dans votre couche de service. Si vous souhaitez le faire, supprimez votre couche de service car vous n'en avez plus besoin! Les objets de modèle de vue ou de transfert de données doivent vivre dans la couche Service, car ils doivent être mappés sur les membres du modèle de domaine et inversement. Alors, pourquoi avez-vous besoin de DTO? Dans une application complexe comportant de nombreux scénarios, vous devez séparer les problèmes de vue de domaine et de présentation, un modèle de domaine peut être divisé en plusieurs DTO et plusieurs modèles de domaine peuvent également être regroupés en un DTO. Il est donc préférable de créer votre DTO dans une architecture en couches, même si ce serait la même chose que votre modèle.

Devons-nous toujours utiliser les DTO pour la communication avec la couche service? Oui, vous devez renvoyer DTO par votre couche service car vous avez parlé à votre référentiel dans la couche service. avec les membres du modèle de domaine et mappez-les vers DTO et revenez au contrôleur MVC et inversement.

Puis-je ajuster les modèles de domaine en fonction des besoins en services? Un service ne fait que parler à un référentiel, ainsi que des méthodes et des services de domaine, vous devez résoudre le problème en votre domaine en fonction de vos besoins et ce n’est pas la tâche du service de dire au domaine ce dont il a besoin.

Si nous devons nous en tenir strictement aux DTO, doivent-ils être définis dans la couche service? Oui, essayez de mettre DTO ou ViewModel en service plus tard, car ils doivent être mappés. aux membres du domaine dans la couche service et ce n'est pas une bonne idée de placer DTO dans les contrôleurs de votre application (essayez d'utiliser demande de réponse motif dans votre couche service), à ​​la vôtre!

7
Ehsan

Jusqu'à présent, nous utilisons des modèles de domaine (principalement des entités) sur toutes les couches, et nous utilisons les DTO uniquement comme modèles de vue (dans le contrôleur, le ou les modèles de domaine renvoyés par le service et le contrôleur crée le modèle de vue, qui est transmis à la vue).

Étant donné que Domain Model fournit la terminologie ( biquitous Language ) pour l'ensemble de votre application, il est préférable d'utiliser largement Domain Model.

La seule raison d'utiliser ViewModels/DTO est une implémentation de modèle MVC dans votre application pour séparer View (tout type de couche de présentation) et Model (modèle de domaine). . Dans ce cas, votre présentation et votre modèle de domaine sont faiblement couplés.

Parfois, le service doit renvoyer un objet de données non défini dans le domaine, puis nous devons soit ajouter un nouvel objet au domaine non mappé, soit créer un objet POCO (ce qui est moche, car certains services renvoient des modèles de domaine, certains restituer efficacement les DTO).

Je suppose que vous parlez des services de logique applicative/métier/de domaine.

Je vous suggère de renvoyer des entités de domaine lorsque vous le pouvez. S'il est nécessaire de renvoyer des informations supplémentaires, il est acceptable de renvoyer un DTO contenant plusieurs entités de domaine.

Parfois, les personnes qui utilisent des frameworks tiers, qui génèrent des mandataires sur des entités de domaine, rencontrent des difficultés pour exposer les entités de domaine de leurs services, mais il ne s'agit que d'un mauvais usage.

La question est la suivante: si nous utilisons strictement les modèles de vue, est-il possible de renvoyer les modèles de domaine jusqu'aux contrôleurs, ou devrions-nous toujours utiliser les DTO pour la communication avec la couche service?

Je dirais qu'il suffit de renvoyer des entités de domaine dans 99,9% des cas.

Pour simplifier la création de DTO et y mapper vos entités de domaine, vous pouvez utiliser AutoMapper .

3
Ilya Palkin

Je suggérerais d'analyser ces deux questions:

  1. Vos couches supérieures (c'est-à-dire, voir et voir les modèles/contrôleurs) consomment-elles les données d'une manière différente de celle exposée par la couche de domaine? Si beaucoup de mappages sont en cours ou même si la logique est impliquée, je vous suggérerai de revoir votre conception: cela devrait probablement être plus proche de la façon dont les données sont réellement utilisées.

  2. Quelle est la probabilité que vous changiez profondément vos couches supérieures? (par exemple, permutation d'ASP.NET pour WPF). Si cela est très différent et que votre architecture n’est pas très complexe, il vaudrait peut-être mieux exposer autant d’entités de domaine que vous le pourrez.

Je crains que ce soit un sujet assez vaste et qu’il s’agisse vraiment de la complexité de votre système et de ses exigences.

2
jnovo

Je suis en retard pour ce parti, mais c'est une question tellement commune et importante que je me suis senti obligé de répondre.

Par "services", voulez-vous dire la "couche d'application" décrite par Evan dans le livre ble ? Je suppose que c'est le cas, auquel cas la réponse est qu'ils ne devraient pas renvoyer des objets DTO. Je suggère de lire le chapitre 4 du livre bleu intitulé "Isolating the Domain".

Dans ce chapitre, Evans dit ce qui suit à propos des couches:

Partitionnez un programme complexe en couches. Développez un design cohérent dans chaque couche et ne dépend que des couches situées en dessous.

Il y a de bonnes raisons pour cela. Si vous utilisez le concept de ordre partiel en tant que mesure de la complexité du logiciel , le fait d'avoir une couche dépendant d'une couche supérieure augmente la complexité, ce qui diminue la maintenabilité.

En appliquant cela à votre question, les DTO sont en réalité un adaptateur qui concerne la couche interface utilisateur/présentation. Rappelez-vous que la communication à distance/entre processus est exactement le objectif d'un DTO (il convient de noter que, dans cet article, Fowler s'oppose également à ce que les DTO fassent partie d'une couche de service, bien qu'il ne parle pas nécessairement de DDD la langue).

Si votre couche d'application dépend de ces DTO, cela dépend d'une couche au-dessus d'elle-même et votre complexité augmente. Je peux vous garantir que cela augmentera la difficulté de maintenance de votre logiciel.

Par exemple, que se passe-t-il si votre système s'interface avec plusieurs autres systèmes ou types de clients, chacun nécessitant son propre DTO? Comment savoir quelle méthode DTO de votre service d’application doit renvoyer? Comment pourriez-vous résoudre ce problème si votre langue de choix ne permet pas de surcharger une méthode (méthode de service, dans ce cas) basée sur le type de retour? Et même si vous trouvez un moyen, pourquoi violer votre couche d'application pour prendre en charge un problème de couche de présentation?

Concrètement, il s’agit d’une étape dans l’architecture des spaghettis. J'ai vu ce genre de décentralisation et ses résultats dans ma propre expérience.

Là où je travaille actuellement, les services de notre couche Application renvoient des objets de domaine. Nous ne considérons pas cela comme un problème car la couche Interface (c'est-à-dire UI/Presentation) dépend de la couche Domain, qui est inférieure à . En outre, cette dépendance est réduite à un type de dépendance "référence uniquement" pour les raisons suivantes:

a) la couche d'interface peut uniquement accéder à ces objets de domaine en tant que valeurs de retour en lecture seule obtenues par des appels à la couche d'application

b) les méthodes sur les services de la couche application acceptent en entrée uniquement l'entrée "brute" (valeurs de données) ou les paramètres d'objet (pour réduire le nombre de paramètres si nécessaire) définis dans cette couche. Plus précisément, les services d'application n'acceptent jamais les objets de domaine en tant qu'entrée.

La couche d'interface utilise des techniques de mappage définies dans la couche d'interface elle-même pour mapper des objets de domaine vers des DTO. Là encore, les DTO restent concentrés sur le fait d’être des adaptateurs contrôlés par la couche d’interface.

2
BitMask777

D'après mon expérience, à moins d'utiliser un modèle OO UI (comme des objets nus), exposer les objets de domaine à l'interface utilisateur est une mauvaise idée. En effet, à mesure que l'application grandit, les besoins de l'interface utilisateur changent et obligent vos objets à s'adapter à ces modifications. Vous finissez par servir 2 maîtres: UI et DOMAIN, ce qui est une expérience très pénible. Croyez-moi, vous ne voulez pas être là. Le modèle d'interface utilisateur a pour fonction de communiquer avec l'utilisateur, le modèle DOMAIN contenant les règles commerciales et les modèles de persistance traitant du stockage efficace des données. Ils répondent tous à des besoins différents de l'application. Je suis en train d'écrire un article sur ce blog, je l'ajouterai quand ce sera fait.

1
max_cervantes