Pourquoi devrais-je isoler mes entités de domaine de ma couche de présentation?


85

Une partie de la conception axée sur le domaine sur laquelle il ne semble pas y avoir beaucoup de détails est de savoir comment et pourquoi vous devriez isoler votre modèle de domaine de votre interface. J'essaie de convaincre mes collègues que c'est une bonne pratique, mais je ne semble pas faire beaucoup de progrès ...

Ils utilisent des entités de domaine où bon leur semble dans les couches de présentation et d'interface. Quand je leur dis qu'ils devraient utiliser des modèles d'affichage ou des DTO pour isoler la couche de domaine de la couche d'interface, ils rétorquent qu'ils ne voient pas la valeur commerciale en faisant quelque chose comme ça, car maintenant vous avez un objet d'interface utilisateur à maintenir ainsi que l'objet de domaine d'origine.

Je cherche donc des raisons concrètes que je peux utiliser pour étayer cela. Plus précisément:

  1. Pourquoi ne devrions-nous pas utiliser des objets de domaine dans notre couche de présentation?
    (si la réponse est évidente, `` découplage '', veuillez expliquer pourquoi c'est important dans ce contexte)
  2. Devrions-nous utiliser des objets ou des constructions supplémentaires pour isoler nos objets de domaine de l'interface?

cette question devrait être dans le wiki.
Syed Tayyab Ali

@ m4bwav - Ce devrait être un wiki car il est formulé de manière à inviter à la discussion plutôt qu'à une seule bonne réponse.
Rob Allen

1
@ m4bwav: Je pense que votre question est apparue plus comme un article d'opinion qu'une vraie question ... J'ai essayé de corriger cela (vous voudrez peut-être la modifier davantage), mais sachez que sans soin approprié, cela pourrait sembler être à la traîne.
Shog9

5
Ok, sauvegarde, je pose une question légitime, en quoi cela offenserait-il quelqu'un? Qui suis-je cible?
Mark Rogers

@ m4bwav: vous ciblez votre homme de paille. Le "grand nombre de personnes" avec qui vous en parlez dans votre question.
Shog9

Réponses:


48

Tout simplement, la raison en est une de mise en œuvre et de dérive. Oui, votre couche de présentation doit connaître vos objets métier pour pouvoir les représenter correctement. Oui, au départ, il semble qu'il y ait beaucoup de chevauchement entre la mise en œuvre des deux types d'objets. Le problème est que, avec le temps, les choses s’ajoutent des deux côtés. Les changements de présentation et les besoins de la couche de présentation évoluent pour inclure des éléments totalement indépendants de votre couche de gestion (la couleur, par exemple). Pendant ce temps, les objets de votre domaine changent au fil du temps, et si vous ne disposez pas d'un découplage approprié de votre interface, vous courez le risque de gâcher votre couche d'interface en apportant des modifications apparemment bénignes à vos objets métier.

Personnellement, je pense que la meilleure façon d'aborder les choses est d'utiliser le paradigme d'interface strictement appliqué; autrement dit, votre couche d'objet métier expose une interface qui est le seul moyen avec lequel elle peut être communiquée; aucun détail d'implémentation (c'est-à-dire les objets de domaine) concernant l'interface n'est exposé. Oui, cela signifie que vous devez implémenter vos objets de domaine dans deux emplacements; votre couche d'interface et dans votre couche BO. Mais cette réimplémentation, bien qu'elle puisse sembler au départ un travail supplémentaire, aide à appliquer le découplage qui permettra d'économiser des tonnes de travail à un moment donné dans le futur.


2
Qu'entendez-vous par «implémenter vos objets de domaine à deux endroits»?
jlembke le

10
Cela me semble ridicule. Pourquoi le travail supplémentaire maintenant qui PEUT sauver du travail à l'avenir? 9 fois sur 10, vous n'aurez jamais besoin de faire le changement qui permettrait d'économiser "des tonnes" de travail.
Bip bip

13
@LuckyLindy: 99 fois sur 100 (en fait plus), le port de ma ceinture de sécurité n'est pas nécessaire pour m'empêcher de me blesser. Cependant, dans le seul cas où j'en ai vraiment besoin, cela m'empêchera (probablement) d'être tué ou gravement blessé. Une once de prévention vaut une livre de guérison. Je soupçonne que votre opinion à ce sujet changera une fois que vous aurez plus d'expérience.
Paul Sonier

19

J'ai lutté avec cela moi-même. Il y a des cas où un DTO a du sens à utiliser dans la présentation. Disons que je veux afficher une liste déroulante d'entreprises dans mon système et que j'ai besoin de leur identifiant pour lier la valeur.

Eh bien, au lieu de charger un CompanyObject qui pourrait avoir des références à des abonnements ou qui sait quoi d'autre, je pourrais renvoyer un DTO avec le nom et l'identifiant. Ceci est une bonne utilisation à mon humble avis.

Prenons maintenant un autre exemple. J'ai un objet qui représente une estimation, cette estimation peut être composée de main-d'œuvre, d'équipement, etc. des calculs). Pourquoi devrais-je modéliser cet objet deux fois? Pourquoi ne puis-je pas simplement faire énumérer mon interface utilisateur sur les calculs et les afficher?

Je n'utilise généralement pas de DTO pour isoler ma couche de domaine de mon interface utilisateur. Je les utilise pour isoler ma couche de domaine d'une limite qui est hors de mon contrôle. L'idée que quelqu'un mettrait des informations de navigation dans son objet métier est ridicule, ne contaminez pas votre objet métier.

L'idée que quelqu'un mettrait la validation dans son objet métier? Eh bien, je dis que c'est une bonne chose. Votre interface utilisateur ne devrait pas avoir la responsabilité exclusive de valider vos objets métier. Votre couche métier DOIT faire sa propre validation.

Pourquoi mettriez-vous du code de génération d'interface utilisateur dans un objet busienss? Dans mon cas, j'ai des objets séparés qui génèrent le code de l'interface utilisateur séparément de l'interface utilisateur. J'ai des objets sperate qui rendent mes objets métier en Xml, l'idée que vous devez séparer vos couches pour éviter ce type de contamination m'est si étrangère car pourquoi mettriez-vous même du code de génération HTML dans un objet métier ...

Edit Comme je pense un peu plus, il y a des cas où les informations de l'interface utilisateur peuvent appartenir à la couche de domaine. Et cela pourrait brouiller ce que vous appelez une couche de domaine, mais j'ai travaillé sur une application multi-locataire, qui avait un comportement très différent à la fois l'apparence de l'interface utilisateur et le flux de travail fonctionnel. En fonction de divers facteurs. Dans ce cas, nous avions un modèle de domaine qui représentait les locataires et leur configuration. Leur configuration comprenait des informations d'interface utilisateur (des étiquettes pour les champs génériques par exemple).

Si je devais concevoir mes objets pour les rendre persistants, devrais-je également dupliquer les objets? Gardez à l'esprit que si vous souhaitez ajouter un nouveau champ maintenant, vous avez deux emplacements pour l'ajouter. Cela soulève peut-être une autre question si vous utilisez DDD, toutes les entités persistantes sont-elles des objets de domaine? Je sais dans mon exemple qu'ils l'étaient.


Les étiquettes étant différentes pour différents locataires n'indiqueraient-elles pas une langue omniprésente différente pour chaque locataire? Je pense qu'il doit y avoir le concept d'un méta-modèle où un domaine est partagé entre les locataires avec une couche de traduction pour leur interprétation du méta-modèle.
Kell le

16

Vous le faites pour la même raison que vous gardez SQL hors de vos pages ASP / JSP.

Si vous ne conservez qu'un seul objet de domaine, pour une utilisation dans la couche de présentation ET de domaine, cet objet devient rapidement monolithique. Il commence à inclure le code de validation de l'interface utilisateur, le code de navigation de l'interface utilisateur et le code de génération de l'interface utilisateur. Ensuite, vous ajoutez bientôt toutes les méthodes de la couche de gestion en plus de cela. Maintenant, votre couche métier et votre interface utilisateur sont toutes mélangées, et elles sont toutes dérangées au niveau de la couche d'entité de domaine.

Vous souhaitez réutiliser ce widget UI astucieux dans une autre application? Eh bien, vous devez créer une base de données avec ce nom, ces deux schémas et ces 18 tables. Vous devez également configurer Hibernate et Spring (ou vos frameworks de choix) pour effectuer la validation métier. Oh, vous devez également inclure ces 85 autres classes non liées, car elles sont référencées dans la couche de gestion, qui se trouve être dans le même fichier.


13

Je ne suis pas d'accord.

Je pense que la meilleure façon de procéder est de commencer par des objets de domaine dans votre couche de présentation JUSQU'À CE QUE CELA FAIT AUTREMENT.

Contrairement à la croyance populaire, les «objets de domaine» et les «objets de valeur» peuvent coexister avec bonheur dans la couche de présentation. Et c'est la meilleure façon de le faire - vous bénéficiez des deux mondes, d'une duplication réduite (et d'un code standard) avec les objets de domaine; et l'adaptation et la simplification conceptuelle de l'utilisation des objets de valeur à travers les demandes.


Merci pour votre contribution, je vois d'où vous venez. Bien que je ne dise pas que ce n'est pas une autre des façons infinies de créer un projet réussi, cela semble aller à l'encontre du style "Domain-Driven Design", qui est pour les projets plus grands et plus complexes qui sont plus difficiles à maintenir à long terme.
Mark Rogers

Non, c'est faux, et c'est exactement pourquoi tant de sites deviennent vulnérables à l'injection SQL.
Remi

7

La réponse dépend de l'échelle de votre application.


Application CRUD simple (créer, lire, mettre à jour, supprimer)

Pour les applications crud de base, vous ne disposez d'aucune fonctionnalité. Ajouter DTO au-dessus des entités serait une perte de temps. Cela augmenterait la complexité sans augmenter l'évolutivité.

entrez la description de l'image ici


Application non-CRUD moyennement compliquée

Dans cette taille d'application, vous aurez peu d'entités associées à un véritable cycle de vie et à une logique métier.

L'ajout de DTO sur ce cas est une bonne idée pour plusieurs raisons:

  • La couche de présentation ne peut voir que le sous-ensemble de champs de l'entité. Vous encapsulez des entités
  • Pas de couplage entre le backend et le frontent
  • Si vous avez des méthodes commerciales à l'intérieur des entités, mais pas dans DTO, l'ajout de DTO signifie que le code extérieur ne peut pas ruiner l'état de votre entité.

entrez la description de l'image ici


Application d'entreprise compliquée

Une seule entité peut avoir besoin de plusieurs modes de présentation. Chacun d'eux aura besoin d'un ensemble de champs différent. Dans ce cas, vous rencontrez les mêmes problèmes que dans l'exemple précédent et vous devez contrôler la quantité de champs visibles pour chaque client. Le fait d'avoir un DTO distinct pour chaque client vous aidera à choisir ce qui doit être visible.

entrez la description de l'image ici


4

Nous utilisons le même modèle sur le serveur et sur l'interface utilisateur. Et c'est une douleur. Nous devons le refactoriser un jour.

Les problèmes sont principalement dus au fait que le modèle de domaine doit être découpé en morceaux plus petits pour pouvoir le sérialiser sans avoir la base de données entière référencée. Cela rend son utilisation plus difficile sur le serveur. Des liens importants manquent. Certains types ne sont pas non plus sérialisables et ne peuvent pas être envoyés au client. Par exemple 'Type' ou toute classe générique. Ils doivent être non génériques et le type doit être transféré sous forme de chaîne. Cela génère des propriétés supplémentaires pour la sérialisation, elles sont redondantes et déroutantes.

Un autre problème est que les entités de l'interface utilisateur ne correspondent pas vraiment. Nous utilisons la liaison de données et de nombreuses entités ont de nombreuses propriétés redondantes uniquement à des fins d'interface utilisateur. De plus, il existe de nombreux 'BrowsableAttribute' et d'autres dans le modèle d'entité. C'est vraiment mauvais.

À la fin, je pense que c'est juste une question de savoir de quelle manière est la plus facile. Il peut y avoir des projets où cela fonctionne très bien et où il n'est pas nécessaire d'écrire un autre modèle DTO.


2
Si vous allez utiliser la liaison de données, exécutez une requête linq et liez-vous à un type anonyme. Cela vous permet d'aplatir et de modifier la hiérarchie. Vous pouvez également mettre en œuvre le filtrage et le tri très bien avec cela.
JoshBerke

@Josh: Merci pour le conseil. Cela pourrait partiellement fonctionner. Je ne suis pas moi-même un programmeur GUI et je ne suis pas beaucoup impliqué dans les concepts d'interface graphique. Le problème sera dans les cas où les données sont manipulées et renvoyées au serveur.
Stefan Steinegger

3

Il s'agit principalement de dépendances. La structure fonctionnelle de base de l'organisation a ses propres exigences fonctionnelles, et l'interface utilisateur doit permettre aux gens de modifier et d'afficher le noyau; mais le noyau lui-même ne devrait pas être tenu d'accueillir l'interface utilisateur. (Si cela doit se produire, c'est généralement une indication que le noyau n'est pas conçu par une propriété.)

Mon système comptable a une structure et un contenu (et des données) censés modéliser le fonctionnement de mon entreprise. Cette structure est réelle et existe quel que soit le logiciel comptable que j'utilise. (Inévitablement, un progiciel donné contient une structure et un contenu pour lui-même, mais une partie du défi consiste à minimiser cette surcharge.)

Fondamentalement, une personne a un travail à faire. Le DDD doit correspondre au flux et au contenu du travail. DDD vise à rendre explicites tous les travaux qui doivent être effectués de manière complètement et indépendante que possible. Ensuite, nous espérons que l'interface utilisateur facilite l'exécution du travail de la manière la plus transparente possible, de la manière la plus productive possible.

Les interfaces concernent les entrées et les vues fournies pour le noyau fonctionnel correctement modélisé et invariant.


3

Bon sang, je jure que c'est la persévérance.

Quoi qu'il en soit, c'est une autre instance de la même chose: la loi de Parnas dit qu'un module doit garder un secret, et le secret est une exigence qui peut changer. (Bob Martin a une règle qui en est une autre version.) Dans un système comme celui-ci, la présentation peut changer indépendamment du domaine . Comme, par exemple, une entreprise qui maintient les prix en euros et utilise le français dans les bureaux de l'entreprise, mais qui souhaite présenter les prix en dollars avec du texte en mandarin. Le domaine est le même; la présentation peut changer. Ainsi, pour minimiser la fragilité du système - c'est-à-dire le nombre de choses qui doivent être modifiées pour mettre en œuvre un changement dans les exigences - vous séparez les préoccupations.


2

Votre présentation peut faire référence à votre couche de domaine, mais il ne devrait y avoir aucune liaison directement de votre interface utilisateur à vos objets de domaine. Les objets de domaine ne sont pas destinés à être utilisés dans l'interface utilisateur car ils sont souvent, s'ils sont correctement conçus, basés sur des comportements et non sur des représentations de données. Il devrait y avoir une couche de mappage entre l'interface utilisateur et le domaine. MVVM, ou MVP, est un bon modèle pour cela. Si vous essayez de lier directement votre interface utilisateur au domaine, vous vous créerez probablement beaucoup de maux de tête. Ils ont deux objectifs différents.


1

Peut-être ne conceptualisez-vous pas la couche d'interface utilisateur en termes assez larges. Pensez en termes de formes de réponse multiples (pages Web, réponse vocale, lettres imprimées, etc.) et en termes de langues multiples (anglais, français, etc.).

Supposons maintenant que le moteur vocal du système d'appel téléphonique fonctionne sur un type d'ordinateur complètement différent (Mac par exemple) de l'ordinateur qui exécute le site Web (Windows peut-être).

Bien sûr, il est facile de tomber dans le piège "Eh bien dans mon entreprise, nous ne nous soucions que de l'anglais, exécutons notre site Web sur LAMP (Linux, Apache, MySQL et PHP) et tout le monde utilise la même version de Firefox". Mais qu'en est-il dans 5 ou 10 ans?



1

Avec l'aide d'un outil comme ' Value Injecter » et le concept de «Mappers» dans la couche de présentation tout en travaillant avec des vues, il est beaucoup plus facile de comprendre chaque morceau de code. Si vous avez un peu de code, vous ne verrez pas les avantages tout de suite mais lorsque votre projet grandira de plus en plus, vous serez très heureux en travaillant avec les vues pour ne pas avoir à entrer dans la logique des services, référentiels pour comprendre le modèle de vue. View Model est un autre gardien dans le vaste monde de la couche anti-corruption et vaut son pesant d'or dans un projet à long terme.

La seule raison pour laquelle je ne vois aucun avantage à utiliser le modèle de vue est que votre projet est suffisamment petit et simple pour que les vues soient directement liées à chaque propriété de votre modèle. Mais si à l'avenir, les exigences changent et que certains contrôles dans les vues ne seront pas liés au modèle et que vous n'avez pas de concept de modèle de vue, vous commencerez à ajouter des correctifs à de nombreux endroits et vous commencerez à avoir un code hérité qui vous n'apprécierez pas. Bien sûr, vous pouvez faire une refactorisation pour transformer votre modèle de vue en modèle de vue et suivre le principe YAGNI sans ajouter de code si vous n'en avez pas besoin mais pour moi, c'est beaucoup plus une bonne pratique que je dois suivre pour ajouter un couche de présentation exposant uniquement les objets de modèle de vue.


1

Voici un exemple concret des raisons pour lesquelles je trouve que c'est une bonne pratique de séparer les entités de domaine de la vue.

Il y a quelques mois, j'ai créé une interface utilisateur simple pour afficher les valeurs de l'azote, du phosphore et du potassium dans un échantillon de sol à travers une série de 3 jauges. Chaque jauge avait une section rouge, verte et rouge, c'est-à-dire que vous pouviez avoir trop ou trop peu de chaque composant, mais il y avait un niveau vert sûr au milieu.

Sans trop réfléchir, j'ai modélisé ma logique métier pour fournir des données pour ces 3 composants chimiques et une fiche technique séparée, contenant des données sur les niveaux acceptés dans chacun des 3 cas (y compris l'unité de mesure utilisée, c'est-à-dire les moles ou le pourcentage). J'ai ensuite modélisé mon interface utilisateur pour utiliser un modèle très différent, ce modèle était préoccupé par les étiquettes de jauge, les valeurs, les valeurs limites et les couleurs.

Cela signifiait que lorsque j'ai dû montrer plus tard 12 composants, j'ai simplement mappé les données supplémentaires dans 12 nouveaux modèles de vue de jauge et ils sont apparus à l'écran. Cela signifiait également que je pouvais réutiliser facilement le contrôle de la jauge et leur faire afficher d'autres ensembles de données.

Si j'avais couplé ces jauges directement dans mes entités de domaine, je n'aurais aucune de la flexibilité ci-dessus et toute modification future serait un casse-tête. J'ai rencontré des problèmes très similaires lors de la modélisation de calendriers dans l'interface utilisateur. S'il est nécessaire qu'un rendez-vous du calendrier devienne rouge lorsqu'il y a plus de 10 participants, la logique métier pour gérer cela doit rester dans la couche de gestion et tout le calendrier de l'interface utilisateur doit savoir, c'est qu'il a été invité à devenir rouge, il ne devrait pas avoir besoin de savoir pourquoi.


-1

La seule raison raisonnable d'ajouter un mappage supplémentaire entre la sémantique généralisée et spécifique au domaine est que vous avez (accès à) un corps de code existant (et des outils) qui sont basés sur une sémantique généralisée (mais mappable) distincte de la sémantique de votre domaine.

Les conceptions pilotées par domaine fonctionnent mieux lorsqu'elles sont utilisées conjointement avec un ensemble orthogonal de cadres de domaines fonctionnels (tels que ORM, GUI, Workflow, etc.). Rappelez-vous toujours que ce n'est que dans les contiguïtés de la couche externe que la sémantique du domaine doit être exposée. Il s'agit généralement du frontal (GUI) et du back-end persistant (RDBM, ORM). Toute couche intermédiaire effectivement conçue peut et doit être invariante dans le domaine.


para 1: ne créez pas d'abstraction inutile (par exemple, des composants réutilisables) à moins que vous ne les partagiez réellement entre des applications distinctes. para 2: Je me demande comment les interfaces graphiques génériques fonctionnent dans tant de domaines différents. Remarque: cette industrie est tellement cassée, ce n'est même plus drôle ...
alphazero
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.