Je me plonge dans Domain Driven Design et certains des concepts que je découvre ont beaucoup de sens en surface, mais lorsque j'y réfléchis davantage, je me demande si c'est vraiment une bonne idée.
Le concept d'agrégats, par exemple, a du sens. Vous créez de petits domaines de propriété afin que vous n'ayez pas à traiter avec le modèle de domaine entier.
Toutefois, lorsque j'y pense dans le contexte d'une application Web, nous consultons fréquemment la base de données pour récupérer de petits sous-ensembles de données. Par exemple, une page peut ne lister que le nombre de commandes, avec des liens sur lesquels cliquer pour ouvrir la commande et voir son identifiant.
Si je ne me trompe pas Agrégats compréhension, je généralement utiliser le modèle référentiel pour retourner un OrderAggregate qui contiendrait les membres GetAll
, GetByID
, Delete
et Save
. Ok, ça sonne bien. Mais...
Si j'appelle GetAll pour répertorier toutes mes commandes, il me semblerait que ce schéma exigerait le renvoi de la liste complète des informations globales, des commandes complètes, des lignes de commande, etc. Lorsque je n'ai besoin que d'un petit sous-ensemble de ces informations (informations d'en-tête seulement).
Est-ce que je manque quelque chose? Ou y a-t-il un niveau d'optimisation que vous utiliseriez ici? Je ne peux pas imaginer que quiconque puisse préconiser de renvoyer des agrégats complets lorsque vous n'en avez pas besoin.
Certes, vous pouvez créer des méthodes sur votre référentiel GetOrderHeaders
, mais cela semble aller à l’encontre du but qui consiste à utiliser un modèle tel que référentiel.
Quelqu'un peut-il clarifier cela pour moi?
MODIFIER:
Après de nombreuses recherches, je pense que le point négatif est qu'un modèle de référentiel pur diffère de ce que la plupart des gens pensent d'un référentiel.
Fowler définit un référentiel comme un magasin de données qui utilise la sémantique de la collection et est généralement conservé en mémoire. Cela signifie créer un graphe d'objet entier.
Evans modifie le référentiel pour inclure les racines d'agrégat. Le référentiel est donc amputé pour ne prendre en charge que les objets d'un agrégat.
La plupart des gens semblent penser que les référentiels sont des objets d'accès aux données glorifiés, dans lesquels vous créez simplement des méthodes pour obtenir toutes les données que vous souhaitez. Cela ne semble pas être l'intention telle que décrite dans Patterns of Enterprise Application Architecture de Fowler.
D'autres encore considèrent un référentiel comme une simple abstraction utilisée principalement pour faciliter les tests et les moqueries, ou pour dissocier la persistance du reste du système.
Je suppose que la réponse est qu'il s'agit d'un concept beaucoup plus complexe que je ne le pensais au départ.
la source
Réponses:
N'utilisez pas votre modèle de domaine et vos agrégats pour l'interrogation.
En fait, ce que vous demandez est une question assez commune pour qu'un ensemble de principes et de modèles ait été établi pour éviter cela. Cela s'appelle CQRS .
la source
Je me suis battu, et je suis toujours aux prises, pour savoir comment utiliser au mieux le modèle de référentiel dans une conception dirigée par un domaine. Après l'avoir utilisé maintenant pour la première fois, j'ai proposé les pratiques suivantes:
Un référentiel devrait être simple; il est uniquement responsable du stockage des objets du domaine et de leur récupération. Toute autre logique doit figurer dans d'autres objets, tels que des usines et des services de domaine.
Un référentiel se comporte comme une collection comme s'il s'agissait d'une collection en mémoire de racines agrégées.
Un référentiel n'est pas un DAO générique, chaque référentiel a son interface unique et étroite. Un référentiel a souvent des méthodes de recherche spécifiques qui vous permettent de rechercher la collection en termes de domaine (par exemple: donnez-moi toutes les commandes ouvertes pour l'utilisateur X). Le référentiel lui-même peut être implémenté à l'aide d'un DAO générique.
Idéalement, les méthodes de recherche ne renverront que des racines agrégées. Si cela est trop inefficace, il peut également renvoyer des objets de valeur en lecture seule qui ne contiennent exactement ce dont vous avez besoin (bien que ce soit un avantage si ces objets de valeur peuvent également être exprimés en termes de domaine). En dernier recours, le référentiel peut également être utilisé pour renvoyer des sous-ensembles ou des collections de sous-ensembles d'une racine agrégée.
De tels choix dépendent des technologies utilisées, car vous devez trouver le moyen d'exprimer le plus efficacement possible votre modèle de domaine avec les technologies utilisées.
la source
Je ne pense pas que votre méthode GetOrderHeaders vole le but du référentiel du tout.
DDD souhaite (entre autres choses) veiller à ce que vous obteniez ce dont vous avez besoin par le biais de la racine agrégée (vous n’auriez pas de OrderDetailsRepository, par exemple), mais cela ne vous limite pas à la façon dont vous le mentionnez.
Si OrderHeader est un concept de domaine, vous devez le définir en tant que tel et disposer des méthodes de référentiel appropriées pour les récupérer. Assurez-vous simplement que vous passez par la racine agrégée correcte quand vous le faites.
la source
Mon utilisation de DDD peut ne pas être considérée comme une "pure" DDD, mais j’ai adapté les stratégies du monde réel suivantes utilisant DDD par rapport à un magasin de données de base de données.
** Vous n'êtes pas obligé de ramener un agrégat entier. Cependant, si vous voulez plus, vous devez demander à la racine, pas à un autre service ou référentiel. Ceci est un chargement paresseux et peut être effectué manuellement avec un chargement paresseux pauvre (en injectant le référentiel / service approprié dans la racine) ou en utilisant un ORM qui le supporte.
Dans votre exemple, je fournirais probablement un appel au référentiel contenant uniquement les en-têtes de commande si je voulais charger les détails lors d'un appel séparé. Notez qu'en disposant d'un "OrderHeader", nous introduisons en réalité un concept supplémentaire dans le domaine.
la source
Votre modèle de domaine contient votre logique métier dans sa forme la plus pure. Toutes les relations et opérations qui soutiennent les opérations commerciales. Ce qui vous manque dans votre carte conceptuelle, c'est l'idée de la couche de service d'application que la couche de service enveloppe autour du modèle de domaine et fournit une vue simplifiée du domaine métier (une projection si vous voulez) qui permet au modèle de domaine de changer en fonction des besoins. sans impact direct sur les applications utilisant la couche de service.
Aller plus loin. L'idée de l'agrégat est qu'il existe un seul objet, la racine de l'agrégat, chargé de maintenir la cohérence de l'agrégat. Dans votre exemple, la commande serait responsable de la manipulation de ses lignes de commande.
Pour votre exemple, la couche service exposerait une opération telle que GetOrdersForCustomer qui ne renverrait que ce qui est nécessaire pour afficher une liste récapitulative des commandes (lorsque vous les appelez OrderHeaders).
Enfin, le modèle de référentiel n'est pas simplement une collection, mais permet également des requêtes déclaratives. En C #, vous pouvez utiliser LINQ comme objet de requête ou la plupart des autres O / RM fournissent également une spécification d’objet de requête.
Voyant que vous pouvez créer des requêtes sur le référentiel, il est également judicieux de fournir des méthodes pratiques qui gèrent les requêtes courantes. Par exemple, si vous souhaitez uniquement les en-têtes de votre commande, vous pouvez créer une requête qui renvoie uniquement l'en-tête et l'exposez à l'aide d'une méthode pratique dans vos référentiels.
J'espère que cela aide à clarifier les choses.
la source
Je sais que c’est une vieille question, mais il semble que ma réponse soit différente.
Lorsque je crée un référentiel, il enveloppe généralement certaines requêtes mises en cache .
Conservez ces référentiels dans la RAM de vos serveurs. Ils ne font pas que transmettre des objets à la base de données!
Si je suis dans une application Web avec une page répertoriant les commandes, sur laquelle vous pouvez cliquer pour afficher les détails, il est probable que je souhaite que ma page de liste des commandes contienne des détails sur les commandes (ID, nom, montant, date). pour aider un utilisateur à décider lequel il veut regarder.
À ce stade, vous avez deux options.
Vous pouvez interroger la base de données et extraire exactement ce dont vous avez besoin pour créer la liste, puis interroger à nouveau pour extraire les détails individuels que vous souhaitez voir sur la page de détail.
Vous pouvez faire une requête qui extrait toutes les informations et les met en cache. Sur la page suivante, demandez que vous lisiez à partir du serveur RAM au lieu de la base de données. Si l'utilisateur clique en arrière ou sélectionne la page suivante, vous ne faites toujours aucun déplacement vers la base de données.
En réalité, la manière dont vous la mettez en œuvre est juste cela, et les détails de la mise en œuvre. Si mon plus gros utilisateur a 10 commandes, je veux probablement utiliser l'option 2. Si je parle de 10 000 commandes, l'option 1 est nécessaire. Dans les deux cas ci-dessus et dans de nombreux autres cas, je souhaite que le référentiel masque ces détails d'implémentation.
A l'avenir, si je reçois un ticket pour indiquer à l'utilisateur combien il a dépensé en commandes ( données agrégées ) au cours du dernier mois sur la page de liste des commandes, est-ce que j'écrirais plutôt la logique pour calculer cela en SQL et faire un autre aller-retour pour la base de données ou préférez-vous la calculer à l'aide des données déjà présentes dans le serveur virtuel?
D'après mon expérience, les agrégats de domaine offrent d'énormes avantages.
la source