Question

Une partie de la conception pilotée par le domaine qui ne semble pas être très détaillée, est comment et pourquoi vous devez 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 présentation et interface. Lorsque je leur explique qu'ils doivent utiliser des modèles d'affichage ou des DTO pour isoler la couche de domaine de la couche d'interface, ils s'aperçoivent qu'ils ne voient pas la valeur commerciale de cette opération, car vous devez maintenant gérer un objet d'interface utilisateur. ainsi que l'objet de domaine d'origine.

Je cherche donc des raisons concrètes que je peux utiliser pour justifier 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, le "découplage", veuillez expliquer pourquoi cela 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?
Était-ce utile?

La solution

Tout simplement, la raison en est une d’implémentation et de dérive. Oui, votre couche de présentation doit connaître vos objets métier pour pouvoir les représenter correctement. Oui, initialement, il semble y avoir beaucoup de chevauchement entre la mise en œuvre des deux types d’objets. Le problème est que, avec le temps, des choses s’ajoutent des deux côtés. La présentation change et les besoins de la couche de présentation évoluent pour inclure des éléments totalement indépendants de votre couche de gestion (couleur, par exemple). En attendant, vos objets de domaine changent avec le temps et si vous ne disposez pas du découplage approprié de votre interface, vous courez le risque de foirer votre couche d'interface en apportant des modifications apparemment anodines à vos objets métier.

Personnellement, je pense que la meilleure façon d’aborder les choses est de recourir au paradigme d’interface strictement appliqué; c'est-à-dire que votre couche d'objet métier expose une interface qui constitue le seul moyen de communiquer avec elle; aucun détail d'implémentation (c'est-à-dire les objets de domaine) de l'interface n'est exposé. Oui, cela signifie que vous devez implémenter vos objets de domaine à deux emplacements. votre couche d'interface et dans votre couche BO. Mais cette réimplémentation, même si elle peut sembler à l’origine comme un travail supplémentaire, contribue à renforcer le découplage qui épargnera des TONNES de travail dans le futur.

Autres conseils

Je me suis battu avec cela moi-même. Il y a des cas où un DTO est logique à utiliser dans la présentation. Supposons que je souhaite afficher un menu déroulant des sociétés de mon système et que leur identifiant soit associé à la valeur.

Au lieu de charger un CompanyObject pouvant contenir des références à des abonnements ou qui sait quoi d'autre, je pourrais renvoyer un DTO avec le nom et l'id. C’est un bon usage à mon humble avis.

Maintenant, prenons un autre exemple. J'ai un objet qui représente une estimation, cette estimation peut être composée de travail, d'équipement, etc., elle peut comporter de nombreux calculs définis par l'utilisateur, qui prennent tous ces éléments et les résument (chaque estimation peut être différente avec différents types des calculs). Pourquoi devrais-je modéliser cet objet deux fois? Pourquoi ne puis-je pas simplement avoir mon interface utilisateur énumérer les calculs et les afficher?

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

L'idée qu'une personne mette la validation dans son objet métier? Eh bien, je dis que c'est une bonne chose. Votre interface utilisateur ne doit pas être seule responsable de la validation de vos objets métier. Votre couche métier DOIT faire sa propre validation.

Pourquoi voudriez-vous mettre du code de génération d’UI dans un objet busienss? Dans mon cas, j'ai des objets séparés qui génèrent le code d'interface utilisateur séparé de l'interface utilisateur. J'ai des objets sperate qui rendent mes objets métier au format XML, l'idée qu'il vous faut séparer vos calques pour éviter ce type de contamination m'est si étrangère, car pourquoi voudriez-vous même insérer du code de génération HTML dans un objet métier ...

Modifier Comme je pense un peu plus, il y a des cas où les informations d'interface utilisateur peuvent appartenir à la couche de domaine. Et cela pourrait assombrir 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 en termes de convivialité et de 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. Il est arrivé que leur configuration inclue des informations d'interface utilisateur (les libellés des champs génériques, par exemple).

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

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

Si vous ne conservez qu'un seul objet de domaine à utiliser dans la couche présentation ET 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. Désormais, votre couche métier et votre interface utilisateur sont toutes mélangées et perturbent la couche d'entités de domaine.

Vous souhaitez réutiliser ce gadget d'interface utilisateur 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 les frameworks de votre choix) pour effectuer la validation commerciale. 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 simplement dans le même fichier.

Je ne suis pas d'accord.

Je pense que la meilleure façon de faire est de commencer par les objets de domaine de votre couche présentation jusqu'à ce que le sens le permette de faire autre chose.

Contrairement à la croyance populaire, "Objets du domaine". et " objets de valeur " peut heureusement coexister dans la couche de présentation. Et c’est la meilleure façon de le faire - vous bénéficiez des avantages des deux mondes, une duplication réduite (et un code standard) avec les objets de domaine; et la personnalisation et la simplification conceptuelle de l'utilisation d'objets de valeur pour toutes les demandes.

Nous utilisons le même modèle sur le serveur et sur l'interface utilisateur. Et c'est pénible. Nous devons le refacturer un jour.

Les problèmes tiennent principalement au fait que le modèle de domaine doit être découpé en morceaux plus petits pour pouvoir le sérialiser sans que la base de données entière soit référencée. Cela rend plus difficile à utiliser sur le serveur. Il manque des liens importants. Certains types ne sont pas non plus sérialisables et ne peuvent pas être envoyés au client. Par exemple 'Type' ou n'importe quelle classe générique. Ils doivent être non génériques et 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 beaucoup de 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 qu’il s’agit simplement de savoir de quelle manière est le plus facile. Il peut y avoir des projets où tout fonctionne bien et où il n’est pas nécessaire d’écrire un autre modèle DTO.

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 n’avez aucune fonctionnalité. Ajouter du DTO au sommet d’entités serait une perte de temps. Cela augmenterait la complexité sans augmenter l’évolutivité.

 entrer la description de l'image ici

Application non-CRUD moyennement compliquée

Dans cette taille d'application, vous aurez peu d'entités ayant un cycle de vie réel et une logique métier qui leur est associée.

Ajouter des 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 backend et frontent
  • Si vous avez des méthodes métier à l'intérieur des entités, mais pas dans DTO, alors l'ajout de DTO signifie que le code extérieur ne peut pas détruire l'état de votre entité.

 entrer la description de l'image ici

Application d'entreprise compliquée

Une seule entité peut nécessiter plusieurs modes de présentation. Chacun d'entre 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, plus besoin de contrôler le nombre de champs visibles pour chaque client. Avoir un DTO séparé pour chaque client vous aidera à choisir ce qui doit être visible.

 entrer la description de l'image ici

Il s’agit pour l’essentiel de dépendances. La structure fonctionnelle principale de l'organisation a ses propres exigences fonctionnelles, et l'interface utilisateur doit permettre aux utilisateurs de modifier et d'afficher le cœur; mais le noyau lui-même ne devrait pas être obligé de s'adapter à l'interface utilisateur. (Si cela doit se produire, c'est généralement une indication que le noyau n'est pas une propriété.)

Mon système de comptabilité 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 de comptabilité que j'utilise. (Inévitablement, un progiciel donné contient une structure et un contenu, mais le défi consiste en partie à réduire cette surcharge.)

En gros, 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 aussi complète et indépendante que possible. L’interface utilisateur facilitera ensuite le travail effectué de la manière la plus transparente et la plus productive possible.

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

Bon sang, je jure que cette persistance soit dite.

Quoi qu’il en soit, c’est un exemple supplémentaire de la même chose: la loi de Parnas stipule 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 . Par exemple, une entreprise qui maintient les prix en euros et utilise le français dans ses bureaux, mais souhaite présenter les prix en dollars avec un texte en mandarin. Le domaine est le même. la présentation peut changer. Donc, pour minimiser la fragilité du système, c'est-à-dire le nombre de choses à modifier pour mettre en œuvre un changement d'exigences, vous séparez les problèmes.

Votre présentation peut référencer votre couche de domaine, mais il ne devrait y avoir aucune liaison directe entre votre interface utilisateur et vos objets de domaine. Les objets de domaine ne sont pas destinés à une utilisation de 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 allez probablement vous créer beaucoup de maux de tête. Ils ont deux objectifs différents.

Peut-être que vous ne conceptualisez pas la couche d'interface utilisateur en termes suffisamment généraux. Pensez en termes de formes de réponse multiples (pages Web, réponse vocale, lettres imprimées, etc.) et en plusieurs langues (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 celui 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, dirigeons 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?

Voir aussi la section "Propagation des données entre les couches". dans ce qui suit, je pense que présente des arguments convaincants:

http: // galaxy .andromda.org / docs / andromda-documentation / andromda-getting-started-java / java / index.html

À l'aide d'un outil tel que " Injecteur de valeurs " et du concept de "Mappeurs" dans la couche de présentation Lorsque vous travaillez 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 immédiatement les avantages, mais lorsque votre projet se développera de plus en plus, vous serez très heureux de travailler avec les vues pour ne pas avoir à entrer dans la logique des services, des référentiels pour comprendre le modèle de vue. View Model est un autre garde 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 d'affichage est si votre projet est suffisamment petit et simple pour que les affichages soient liés directement à chaque propriété de votre modèle. Mais si à l'avenir, les exigences changent et si certaines commandes des vues ne sont pas liées au modèle et si vous n'avez pas de concept de modèle de vue, vous commencerez à ajouter des correctifs à de nombreux endroits et vous obtiendrez un code hérité qui vous n'apprécierez pas. Bien sûr, vous pouvez faire du refactoring pour transformer votre modèle de vue en modèle de modèle et suivre le principe de YAGNI sans ajouter de code si vous n'en avez pas besoin, mais pour moi-même, il s'agit bien davantage d'une meilleure pratique à suivre pour ajouter un code. couche de présentation exposant uniquement les objets du modèle de vue.

Voici un exemple réel de la raison pour laquelle je trouve qu'il est recommandé 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 d'azote, de phosphore et de potassium dans un échantillon de sol à l'aide d'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 de sécurité en vert au milieu.

Sans trop y penser, j’ai modélisé ma logique d’entreprise pour fournir les données de ces 3 composants chimiques et une fiche de données distincte, contenant des données sur les niveaux acceptés dans chacun des 3 cas (y compris quelle unité de mesure était utilisée, à savoir les moles ou 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, les valeurs, les valeurs limites et les couleurs des jauges.

Cela signifiait que plus tard, lorsque je devais montrer 12 composants, je traduisais simplement les données supplémentaires dans 12 nouveaux modèles de vue de jauge et elles apparaissaient à l'écran. Cela signifiait également que je pouvais facilement réutiliser le contrôle de jauge et leur faire afficher d'autres ensembles de données.

Si j’avais couplé ces jauges directement dans les entités de mon domaine, je n’aurais aucune de ces possibilités et les modifications à venir seraient un casse-tête. J'ai rencontré des problèmes très similaires lors de la modélisation de calendriers dans l'interface utilisateur. Si un rendez-vous du calendrier doit virer au rouge lorsqu'il y a plus de 10 participants, la logique métier permettant de le gérer doit rester dans la couche de gestion et tout le calendrier de l'interface utilisateur doit être renseigné, c'est qu'il a été chargé de: rouge, il ne devrait pas avoir besoin de savoir pourquoi.

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

Les conceptions gérées par domaine fonctionnent mieux lorsqu'elles sont utilisées conjointement avec un ensemble orthogonal de cadres de domaines fonctionnels (tels que ORM, interface utilisateur graphique, flux de travail, etc.). Rappelez-vous toujours que c'est uniquement dans les adjacences de la couche externe que la sémantique du domaine doit être exposée. Il s'agit généralement de l'interface frontale (GUI) et du back-end persistant (RDBM, ORM). Toute couche intermédiaire conçue de manière efficace peut et doit être invariante au domaine.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top