web-dev-qa-db-fra.com

Modèle de domaine anémique: Avantages/inconvénients

J'aimerais savoir quels sont les avantages et les inconvénients de l'utilisation d'un modèle de domaine anémique (voir le lien ci-dessous).

Article de Fowler

74
Steve Horn

Les pros:

  • Vous pouvez affirmer qu'il s'agit d'un modèle de domaine Et vous vanter auprès de vos amis développeurs Et le mettre sur votre CV.
  • Il est facile de générer automatiquement À partir de tables de base de données.
  • Il mappe étonnamment bien sur les objets de transfert de données .

Les inconvénients:

  • Votre logique de domaine existe quelque part Sinon, probablement dans une classe de méthodes [statiques) . Ou votre code d'interface graphique . Ou à plusieurs endroits, tous avec une logique conflictuelle.
  • C'est un anti-motif, alors les autres développeurs Vous demanderont si vous Comprenez les concepts de conception orientée objet .
36
Terry Wilcox

Alors que "Anemic Domain Model" est anti-pattern, pourquoi y a-t-il tant de systèmes qui implémentent cela?

Je pense qu'il y a plusieurs raisons 

1. Complexité du système

Dans un système simple (qui contient presque tous les exemples et exemple de code que vous trouvez sur Internet) si je veux implémenter:

Ajout de produit à la commande

Je mets cette fonction sur la commande

public void Order.AddOrderLine(Product product)
{
    OrderLines.Add(new OrderLine(product));
}

Nice et super objet orienté.

Maintenant, disons que je dois m'assurer que je dois valider que le produit existe dans l'inventaire et lever une exception si ce n'est pas le cas.

Je ne peux plus vraiment passer commande, car je ne veux pas que ma commande soit dépendante d'Inventory, elle doit donc maintenant passer en service.

public void OrderService.AddOrderLine(Order order, Product product)
{
    if (!InventoryService.Has(product)
       throw new AddProductException

    order.AddOrderLine(product);
}

Je pourrais également passer de IInventoryService à Order.AddOrderLine, ce qui est une autre option, mais cela rend néanmoins Order dépendant de InventoryService.

Il existe encore certaines fonctionnalités dans Order.AddOrderLine, mais elles sont généralement limitées à la portée de la commande, alors que, selon mon expérience, il existe beaucoup plus de portée de la logique applicative en dehors de la commande.

Lorsque le système est plus qu'un simple CRUD de base, vous obtiendrez l'essentiel de votre logique dans OrderService et très peu dans Order.

2. Vue du développeur sur OOP

Il y a beaucoup de discussions animées sur Internet sur la logique à suivre par les entités.

Quelque chose comme

Order.Save

Est-ce que l'Ordre devrait savoir se sauver ou pas? Disons que nous avons des référentiels pour cela.

Maintenant, l'Ordre peut-il ajouter des lignes de commande? Si j'essaie de comprendre cela en utilisant un anglais simple, cela n'a pas vraiment de sens non plus. L'utilisateur ajoute le produit à la commande, alors devrions-nous faire User.AddOrderLineToOrder ()? Cela semble exagéré.

Que diriez-vous de OrderService.AddOrderLine (). Maintenant, c'est un peu logique!

Ma compréhension de OOP est que, pour l'encapsulation, vous mettez des fonctions sur des classes où la fonction devra accéder à l'état interne de la classe. Si j'ai besoin d'accéder à la collection Order.OrderLines, je mets Order.AddOrderLine () sur Order. De cette façon, l'état interne de la classe ne sera pas exposé.

3. Conteneurs IoC

Les systèmes utilisant des conteneurs IoC sont généralement totalement anémiques.

C'est parce que vous pouvez tester vos services/référentiels qui ont des interfaces, mais vous ne pouvez pas tester (facilement) les objets de domaine, à moins de placer des interfaces sur chacun d'entre eux.

Puisque "IoC" est actuellement considéré comme une solution à tous vos problèmes de programmation, beaucoup de personnes le suivent aveuglément et aboutissent ainsi à des modèles de domaine anémique. 

4. OOP est difficile, la procédure est simple

J'ai un peu de " malédiction de la connaissance " sur celui-ci, mais j'ai découvert que Pour les nouveaux développeurs ayant DTO et services est beaucoup plus facile que Rich Domain.

C'est peut-être parce qu'avec Rich Domain, il est plus difficile de savoir sur quelles classes placer la logique. Quand créer de nouvelles classes? Quels modèles utiliser? etc..

Avec les services sans état, vous le claquez dans le service avec le nom le plus proche.

128
Eric P

Suite à cela, il y a une pensée dans ma tête depuis très longtemps maintenant. J’estime que le terme "OOP" a pris un sens qui ne lui est pas vraiment destiné. L'anagramme signifie "programmation orientée objet", comme nous le savons tous bien. L'accent est mis sur la Parole "orientée". Ce n'est pas "OMP", ce qui signifie "programmation mandatée par un objet". ADM et RDM sont des exemples de POO. Ils utilisent des objets, des propriétés, des méthodes, des interfaces, etc. Cependant, il y a une différence entre ADM et RDM dans la manière dont nous choisissons d'encapsuler les choses. Ce sont deux choses différentes. Dire que ADM est mauvais OOP n’est pas une déclaration exacte. Nous avons peut-être besoin de termes différents pour désigner différents niveaux d’encapsulation. De plus, je n’ai jamais aimé le terme anti-pattern. Il est généralement attribué à quelque chose par les membres d'un groupe adverse. Les modèles ADM et RDM sont des modèles valides, ils ont simplement des objectifs différents et visent à répondre à différents besoins de l'entreprise. Ceux d’entre nous qui pratiquent la DDD devraient au moins apprécier cela et ne pas tomber au niveau des autres en critiquant ceux qui choisissent de mettre en œuvre ADM. Juste mes pensées.

20
Drew

"C'est un anti-motif, alors les autres développeurs vous demanderont si vous comprenez les concepts de conception orientée objet."

"Un modèle de domaine anémique est un anti-modèle. Les anti-modèles n'ont pas de pros."

Que le modèle du domaine anémique soit un anti-modèle est une question d'opinion. Selon Martin Fowler, un certain nombre de développeurs qui connaissent OO disent que ce n’est pas le cas.

Même s’il était universellement accepté d’être un anti-modèle, il y a de fortes chances pour qu’il présente encore quelques avantages (bien que relativement faibles).

15
Matt

Il me semble que la principale objection de Fowler est que les ADM ne sont pas OO, dans le sens suivant. Si l'on conçoit un système "à partir de zéro" autour de structures de données passives qui sont manipulées par d'autres morceaux de code, cela sent certainement davantage la conception procédurale que la conception orientée objet.

Je suggère qu’au moins deux forces peuvent produire ce type de conception:

  1. Les concepteurs/programmeurs qui pensent encore, de manière procédurale, être obligés de travailler dans un environnement orienté objet (ou en supposant qu'ils puissent ...) produire un nouveau système, et

  2. Les développeurs s’efforçant d’ajouter un "visage" semblable à un service sur un système legacy conçu de manière non OO (quelle que soit la langue).

Si, par exemple, on construisait un ensemble de services pour exposer les fonctionnalités d'une application mainframe COBOL existante, on pourrait définir des services et des interfaces en termes de modèle conceptuel qui fait not en miroir les structures de données COBOL internes . Cependant, si le service mappe le nouveau modèle sur les données existantes pour utiliser l'implémentation existante mais cachée, alors le nouveau modèle pourrait très bien être "anémique" au sens de l'article de Fowler - par exemple. un ensemble de définitions et de relations de style TransferObject sans comportement réel.

Ce type de compromis peut très bien être commun aux limites auxquelles les systèmes idéalement purs OO doivent interagir avec un environnement existant, non-OO.

13
joel.neely

Le modèle de domaine anémique (ADM) peut constituer un bon choix si votre équipe ne peut ou ne veut pas créer un modèle de domaine riche (RDM) et le conserver au fil du temps. Gagner avec un RDM nécessite une attention particulière aux abstractions dominantes utilisées dans le système. Figurez que, dans tout groupe de développeurs, pas plus de la moitié et peut-être un dixième seulement de ses membres sont compétents pour les abstractions. À moins que ce cadre (peut-être un seul développeur) soit capable de maintenir une influence sur toutes les activités du groupe, le RDM succombera à l'entropie.

Et le RDM entropique blesse, de manière particulière. Ses développeurs vont apprendre des leçons difficiles. Au début, ils seront en mesure de répondre aux attentes de leurs parties prenantes, car ils n'auront aucun passé à la hauteur. Mais comme leur système devient plus compliqué (pas complexe) il deviendra cassant; les développeurs vont essayer de réutiliser le code mais ont tendance à induire de nouveaux bogues ou à revenir en arrière dans le développement (et donc à dépasser leurs estimations).

En revanche, les développeurs ADM définiront des attentes moins élevées pour eux-mêmes, car ils ne s'attendent pas à réutiliser autant de code pour les nouvelles fonctionnalités. Avec le temps, leur système comportera de nombreuses incohérences, mais il ne sera probablement pas démantelé. Leur temps de mise sur le marché sera plus long qu'avec un RDM réussi, mais il est peu probable que leurs parties prenantes s'aperçoivent de cette possibilité.

7
Ladlestein

"Les développeurs cherchent à mettre en place un" visage "de type service sur un système existant conçu de manière non OO (quelle que soit la langue)."

Si vous pensez à de nombreuses applications métier, ces systèmes existants n'utiliseront souvent pas le même modèle de domaine que vous. Le modèle de domaine anémique résout ce problème en utilisant la logique métier dans les classes de service. Vous pouvez insérer tout ce code d'interface dans votre modèle (au sens traditionnel OO), mais vous perdez généralement la modularité.

5
Joe Wood

Lorsque je suis arrivé pour la première fois à l'article sur le modèle de domaine anémique, je me suis dit: "Je te baise sacrement, c'est ce que je fais. De l'horreur!" J'ai persévéré et suivi les références au livre d'Eric Evan, considéré comme un bon exemple, et téléchargé la source. Il s'avère que "ne pas utiliser de modèle de domaine anémique" ne signifie pas "ne pas utiliser de classes de service, pas de médiateurs, pas de stratégies" ou même "mettre de la logique sur la classe en cours de manipulation".

Les exemples DDD ont des classes de service, XyzUpdaters, singletons et IoC. 

Je reste confus quant à ce qu'est exactement un modèle de domaine anémique. Je m'attends à "je le saurai quand je le verrai". Pour l'instant, je suis satisfait d'un exemple positif de bon design.

4
jamie

C'est le même pro que pour la plupart des anti-modèles: cela vous permet de garder beaucoup de gens occupés pendant longtemps. Comme les gestionnaires ont tendance à être plus payés quand ils gèrent plus de personnel, l'incitation à ne pas s'améliorer est forte.

3

Cela donne une meilleure prévisibilité. Les gestionnaires aiment ça, surtout si le projet est payé en temps et en matériel. Chaque changement représente beaucoup de travail. Un travail difficile peut donc être dissimulé derrière de nombreux travaux répétitifs. Dans un système DRY bien conçu, la prévisibilité est très mauvaise car vous faites constamment de nouvelles choses.

1

Conformément à la réponse d’Eric P et à ce que d’autres ont écrit plus haut, il semble que le principal inconvénient d’un SMA soit la perte de l’OOD, plus précisément de la nécessité de conserver la logique et les données d’un concept de domaine de manière à ce que les détails de l'API peut être riche.

Eric poursuit en expliquant qu'il existe souvent des informations extérieures à une classe de domaine nécessaires à la logique d'action sur cette classe, telles que la vérification d'un inventaire avant l'ajout d'un article à une commande. Je me demande toutefois si la réponse est une couche de service qui contient cette logique globale ou si elle est mieux gérée dans le cadre de la conception de l'objet. Quelqu'un doit connaître l'objet Inventory, l'objet Product et l'objet Order. Peut-être est-ce simplement un objet OrderSystem, qui a un membre Inventory, une liste de Orders, etc. Cela ne sera pas très différent d'un service, mais je pense que c'est conceptuellement plus cohérent.

Ou regardez les choses de cette façon: vous pouvez avoir un utilisateur avec un solde créditeur interne, et chaque fois que User.addItemToOrder (article) est appelé, il obtient le prix de l'article et vérifie le crédit avant de l'ajouter, etc. Cela semble raisonnable OO design. Je ne sais pas exactement ce qui est perdu en le remplaçant par Service.addItemToUserOrder (utilisateur, élément), mais je ne suis pas sûr non plus de ce qui a été gagné. Je suppose qu'une perte serait la couche de code supplémentaire, plus le style d'écriture plus brouillon et l'ignorance forcée du modèle de domaine sous-jacent.

1
Michael

Ayant travaillé avec un système "mature" avec un SMA, je sens que je peux fournir au moins des commentaires anecdotiques sur cette question.

1) manque d'encapsulation 

Dans un système en direct avec un ADM, il est possible d’écrire, par exemple, 'obj.x = 100; obj.save ', même si cela viole la logique métier. Cela conduit à un certain nombre de bugs qui ne seraient pas rencontrés si les invariants étaient modélisés sur l'objet. C’est la gravité et le caractère envahissant de ces insectes qui, à mon avis, sont les plus graves inconvénients pour un ADM. 

J’estime important de souligner ici qu’il s’agit là d’une solution fonctionnelle et de solutions procédurales différentes d’un ADM, et toute similitude que d’autres auraient pu rapprocher des similitudes de surface entre un ADM et une solution fonctionnelle est fortuite. 

2) Code ballonnement 

J'estime que la quantité de code produite dans un ADM est 5 à 10 fois supérieure à celle qu'une solution OOP/RDM créerait. Cela s'explique peut-être par 50% de répétition de code, 30% par le code de la plaque de chaudière et 20% par la résolution de problèmes posés par l'absence de RDM.

3) Mauvaise compréhension des problèmes de domaine

Un SMA et une mauvaise compréhension des problèmes du domaine vont un peu de pair. Des solutions naïves se présentent, les exigences sont mal prises en compte en raison de la difficulté de les prendre en charge avec le gestionnaire de domaine existant et le système ADM devient un obstacle important à l’innovation dans les entreprises, compte tenu des délais de développement plus longs et du manque de flexibilité.

4) Difficulté de maintenance

Un certain niveau de rigueur est nécessaire pour faire en sorte qu'un concept de domaine soit modifié à tous les endroits où il est exprimé, étant donné qu'il ne s'agit peut-être pas simplement d'une nouvelle implémentation copier-coller. Cela conduit souvent aux mêmes bogues qui sont examinés et corrigés à plusieurs reprises.

5) Augmentation de la difficulté d'intégration 

Je pense que l'un des avantages d'un GMD est la cohésion des concepts qui permettent une compréhension plus rapide du domaine. Avec un ADM, les concepts peuvent être fragmentés et manquer de clarté, donc plus difficiles à acquérir pour les nouveaux développeurs. 

J'ai également été tenté d'inclure les coûts de soutien opérationnel pour un ADM plus élevés que pour un RDM, mais cela dépend de nombreux facteurs.

Comme d'autres l'ont déjà souligné, examinez DDD (Greg Evans, Vince Vaughn et Scott Millett) pour connaître les avantages d'un GMD.

1
Mr Morphe

Il convient de noter que, au fur et à mesure que la complexité et la granularité de la variation des systèmes augmentent, l’encapsulation et la consolidation des points d’interface offertes par un modèle objet de transmission de message bien conçu permettent de modifier et de maintenir le code critique sans reformatage généralisé.

Les couches de service créées par l'ADM, bien que certainement plus faciles à mettre en œuvre (car elles nécessitent relativement peu de réflexion et comportent de nombreux points d'interface décentralisés), risquent de créer des problèmes plus tard lorsqu'il sera temps de modifier un système réel et en pleine croissance.

J'ajouterais que tous les cas n'appellent pas du tout un modèle de domaine (sans parler du modèle ADM). Parfois, il est préférable d’utiliser un style plus procédural/fonctionnel, car la tâche est axée sur les données et ne dépend pas de la logique/des règles de gestion à l’échelle de l’application.

Si vous essayez de décider des avantages et des inconvénients d'une application complète, il est important de concevoir en premier lieu à quoi chacune pourrait ressembler pour votre application AVANT de commencer à écrire une seule ligne de code. Une fois que votre application est CRC'd ou filaire dans les deux styles, prenez du recul et choisissez celle qui convient le mieux et qui convient le mieux à l'application.

Pensez également à ce qui sera le plus facile à maintenir ...

0
Peter M. Elias

Pour étendre la réponse de Michael, j'aurais pensé qu'il était (assez) clair où ce code devrait aller: dans un médiateur dédié qui gère l'interaction entre l'ordre et l'inventaire.

De mon point de vue, l’important dans le domaine est qu’il DOIT conserver le comportement de test simple, les méthodes isInThisState(), etc. Selon mon expérience, elles sont également dispersées dans les déchirures de service (sic :)) de la plupart des entreprises, et sont soit copiées soit réécrites sans cesse. Ce qui enfreint les règles de cohésion standard.

À mon avis, l’approche devrait consister à viser pour un DM qui tient le comportement le plus bizarre possible, mettez le reste dans des zones clairement désignées (c’est-à-dire non dans les services)

0
StripLight

Mon équipe préfère personnellement le SMA. nous avons un ensemble d'objets métier qui représentent des parties spécifiques de notre domaine. Nous utilisons des services pour enregistrer ces objets dans la base de données. Nos objets métier ont des méthodes, mais ces méthodes ne manipulent que son état interne. 

L'avantage pour nous d'utiliser ADM sur RDM se voit dans la façon dont nous persistons les objets dans la base de données. Les développeurs travaillant sur nos anciens systèmes de code peuvent utiliser nos objets métier (du nouveau système) et continuer à utiliser leur couche d'accès aux données actuelle pour conserver ces objets dans la base de données. L'utilisation du RDM obligerait les développeurs de notre système existant à injecter des objets de référentiel dans notre modèle d'entreprise ... ce qui ne serait pas compatible avec leur couche d'accès aux données actuelle.

0
caa