2013-07-31 6 views
10

Je travaille sur une application web standard avec un domaine organisé autour de concepts DDD. Je me demande quel genre d'objets mes services d'application devraient accepter et retourner. Disons que j'ai un service d'application pour User agrégat.Paramètres de service d'application/types de retour

1) DTO/types simples (string, int, etc.)

public interface UserApplicationService { 
    void registerUser(UserDTO userDTO); 
    List<UserDTO> getUsersForOrganization(String organizationId); 
} 

Dans ce cas, le service d'application est chargé d'appeler l'assembleur transformer DTO aux objets de domaine et l'inverse.

L'avantage de cette approche est que mon service d'application est une limite claire pour mes objets de domaine. Un autre est que le service d'application est une frontière de transaction claire. Les objets de domaine gérés par le contexte de persistance ne fuient pas en dehors de la transaction. Inconvénient: dans le cas de formulaires, la validation doit être basée sur DTO. Donc, mes règles de validation sont dupliquées entre le domaine (l'objet est responsable de son état) et les règles de validation DTO. (Comme dans le cas de Spring MVC sample application). Aussi, si certaines parties de la vue nécessitent une autre forme de modèle (disons que UserDTO n'a pas assez d'informations pour que la vue soit rendue), je vais devoir créer un autre DTO et une base sur deux DTO retournés par le service d'application. , utilisé par vue.

2) types de domaine

public interface UserApplicationService { 
    void registerUser(User user); 
    List<User> getUsersForOrganization(OrganizationId organizationId); 
} 

Dans ce cas, le contrôleur/présentateur est responsable de la transformation.

Gros inconvénient est que mes objets de domaine fuient du service d'application - pas de séparation claire. En outre, où sont nos limites de transaction? Les objets de domaine qui peuvent être liés à, par exemple, la session Hibernate, fuient en dehors de la couche des services d'application. (Cependant, j'ai remarqué que c'est le nombre d'applications exemples qui sont écrites.)

L'avantage est que le contrôleur/présentateur est responsable de la préparation du modèle pour la vue, de sorte qu'il peut composer des bases de DTO sur les exigences de vue. Par exemple, view peut nécessiter des informations supplémentaires qui ne sont pas renvoyées dans DTO à partir de #getUsersForOrganizationMethod. En outre, la validation peut être basée sur des objets de domaine, elle n'est donc pas dupliquée entre les objets DTO et les objets de domaine.

3) objets de domaine + façade

Cette troisième option est utilisé dans DDDsample application. Les services d'application renvoient des types de domaine, mais une certaine facade est responsable de la transformation. Donc dans mon cas, le contrôleur/présentateur parle de la façade avec les DTO, la façade fait la transformation et parle avec les services de l'application en utilisant les objets du domaine. Cependant, à mon humble avis, il semble un peu écrasant - trop de couches, trop de code standard. Pour un service d'application, cela peut sembler bien, mais si nous en avions des dizaines, nous devions avoir le même nombre de méthodes de façade - une duplication pure. De plus, où sont les limites de transaction?

Répondre

4

+1

Je préfère une solution mélangée.

1) J'utilise des objets de domaine comme arguments, mais limités à ValudObject s.Je crois que le cycle de vie Entité s devrait être géré avec soin, et la plupart du temps la vue n'a pas assez de valeur pour peupler l'ensemble Entité sauf très simples applications CRUD. J'ai vu plusieurs fois que certains développeurs initient Entité par constructeur avec négligence et les peuplent avec seulement une partie des champs dont ils ont besoin pour une fonction particulière, ce qui rend très facile l'introduction de bogues pour NullPointerException et le pauvre gars qui est assigné pour réparer problème doit rechercher à travers des dizaines de méthodes pour trouver où Entité donné a été créé. L'entité s est extraite de Dépôt ou créé par Factory dans mes projets.

Parfois, j'utilise certains objets de formulaire en tant que paramètre pour plus de simplicité.

2) J'utilise un contrôleur mvc pour convertir les objets de domaine renvoyés par le service d'application à ViewAdapter (un composant sépare les modèles de domaine de ui), parfois le travail de dettach doit être fait ici.

3) J'utilise un Facade uniquement lorsque le service d'application doit être exposé via un appel de procédure à distance comme un service Web. Dto s sont utilisés comme arguments et types de retour dans ce cas et la façade est responsable de la conversion DTO et Domain Model.

4) La validation est gênante si le service d'application doit être exposé à la fois à la vue Web et à l'appel de procédure à distance. Cela provoque la validation en double implémentée sur les objets de formulaire et Dtos. Je ne valide que des contraintes simples (non nul, longueur pour n'en nommer que quelques-unes, règles métier validées par des objets de domaine par programmation) car je n'ai pas encore trouvé de solution parfaite.

J'espère que cela aide et s'il y a de meilleures solutions faites le moi savoir s'il vous plaît.

Update1:

1) Je dois avouer que je ne suis pas un gourou dans ce domaine et je suis en train de trouver une bonne solution aussi bien. Il y a donc parfois des incohérences dans ma solution actuelle, comme le formulaire que vous avez mentionné dans le commentaire. Parfois, nous prenons un bean de formulaire en tant que commande et y placons une certaine logique de domaine, de sorte que ces commandes appartiennent à la couche de domaine dans ce cas.

2) La limite de transaction est sur le service d'application. Techniquement, l'objet domaine pourrait être modifié hors de la frontière par inadvertance. Nous couvrons ceci par discipline d'équipe et révision de code.

+0

Belle réponse, merci! Couple de commentaires: 1) si vous acceptez la VO dans les services applicatifs, quel serait votre type de paramètre en cas d'opération tel que le paiement? Il y a deux ou trois produits que vous aimeriez passer dans une invocation de méthode, et vous aurez besoin d'un agrégat pour chacun d'eux - voici les DTO à mon humble avis; Je pense que le bean formulaire appartient à la couche de présentation et ne devrait pas être accepté par le service. 2) Où sont vos limites de transaction? Si nous renvoyons des entités à partir de services, cela permettrait au contrôleur de le modifier et potentiellement conduire à des problèmes étranges (en particulier si l'entité est un proxy transactionnel). –

+0

@ woof-woof quelques mises à jour et je ne comprends pas tout le "checkout" et "produits", pourriez-vous expliquer un peu plus? – Hippoom

+0

Disons que vous avez une application de magasin et que l'utilisateur veut acheter un certain nombre de produits A et de produits B. L'utilisateur effectue donc une extraction (c'est ma compréhension :)). L'utilisateur veut acheter tout ou rien - c'est pourquoi nous aurons besoin d'un objet pour agréger les objets et leur quantité. –

3

Je me trouve généralement penché vers l'approche un, en utilisant des commandes et des requêtes.

Voici un extrait d'un article de blog que je publie ce week-end.

Commandes vous aider à soutenir la langue omniprésente par explicitement capture l'intention des utilisateurs dans les limites de votre système - pensez cas d'utilisation . Ils servent de couche sur votre domaine, découplant l'intérieur de l'extérieur, vous permettant d'introduire progressivement des concepts sur le à l'intérieur, sans casser l'extérieur.L'exécuteur de commande vous donne un bon pipeline dont vous pouvez tirer parti pour centraliser la sécurité, les métriques de performance , la journalisation, la gestion de session, etc. Et aussi, si c'est votre truc - les commandes peuvent être traitées en série de manière asynchrone.

Vous pouvez trouver un exemple de ceci sur mon blog; http://www.jefclaes.be/2013/01/separating-command-data-from-logic-and.html. En ce qui concerne vos préoccupations concernant la validation, gardez à l'esprit que la validation en double n'est pas horrible; http://gorodinski.com/blog/2012/05/19/validation-in-domain-driven-design-ddd/.

0

J'utilise un peu des trois approches mais d'une manière très cohérente qui adhère aux principes de stratification décrits par Eric Evans dans le DDD blue book.

Les entrées dans les couches d'application sont toujours des types simples (ou des paramètres d'objet les encapsulant), les sorties sont toujours des types de domaine et la couche de présentation gère le mappage vers/depuis les types d'affichage.

j'expliquer mes raisons de prendre cette approche dans ma réponse à une question similaire ici: https://stackoverflow.com/a/41230822/509891