web-dev-qa-db-fra.com

Les API RESTful ont-elles tendance à encourager les modèles de domaine anémiques?

Je travaille sur un projet dans lequel nous essayons d'appliquer à la fois une conception basée sur le domaine et REST à une architecture orientée services. Nous ne nous inquiétons pas de 100% REST; il serait probablement préférable de dire que nous essayons de créer des API HTTP orientées ressources (~ niveau 2 de Richardson REST) Néanmoins, nous essayons de rester à l'écart de l'utilisation de style RPC des requêtes HTTP, c'est-à-dire que nous essayons d'implémenter nos verbes HTTP selon RFC2616 plutôt que d'utiliser POST pour faire IsPostalAddressValid(...), par exemple.

Cependant, l'accent mis sur cela semble se faire au détriment de notre tentative d'appliquer une conception pilotée par domaine. Avec seulement GET, POST, PUT, DELETE et quelques autres méthodes rarement utilisées, nous avons tendance à créer des services CRUDdy, et les services CRUDdy ont tendance à avoir modèles de domaine anémique.

POST: recevoir les données, les valider, les vider dans la base de données. GET: récupérer les données, les renvoyer. Pas de véritable logique métier là-bas. Nous utilisons également des messages (événements) entre les services, et il me semble que la majeure partie de la logique métier finit par se construire autour de cela.

REST et DDD sont-ils en tension à un certain niveau? (Ou est-ce que je comprends mal quelque chose ici? Sommes-nous peut-être en train de faire autre chose de mal?) Est-il possible de construire un modèle de domaine solide dans un service orienté l'architecture tout en évitant les appels HTTP de style RPC?

34
Kazark

La première loi de Martin Fowler sur les systèmes distribués: "Ne distribuez pas vos objets!" Les interfaces distantes doivent être à grain grossier et les interfaces internes à granularité fine. Souvent, le modèle de domaine riche ne s'applique que dans un contexte délimité .

L'API REST sépare deux contextes différents ayant chacun leurs propres modèles internes. Les contextes communiquent via une interface à grain grossier (API REST) ​​à l'aide d'objets "anémiques" (DTO).

Dans votre cas, il semble que vous essayez de répartir un contexte sur une limite qui est REST. Cela peut conduire à une interface distante à grain fin ou à un modèle anémique. Selon votre projet, il peut ou peut ne pas être un problème.

39
simoraman

POST a été délibérément conçu pour être "intentionnellement vague;" le résultat d'un POST est spécifique à l'implémentation. Ce qui vous empêche de faire ce que Twitter et d'autres concepteurs d'API faire et définir chaque méthode POST dans la partie non CRUD de votre API en fonction de vos besoins spécifiques? POST est le verbe catchall. Utilisez-le lorsque aucun des autres verbes ne convient parfaitement à l'opération que vous souhaitez effectuer.

En d'autres termes, votre question pourrait être également posée comme "Les objets" intelligents "encouragent-ils la conception de style RPC?" Même Martin Fowler (qui a inventé le terme "modèle de domaine anémique") concède que les DTO nus ont certains avantages:

Mettre le comportement dans les objets du domaine ne doit pas contredire l'approche solide consistant à utiliser la superposition pour séparer la logique du domaine de choses telles que la persistance et les responsabilités de présentation. La logique qui devrait être dans un objet de domaine est la logique de domaine - validations, calculs, règles métier - peu importe comment vous voulez l'appeler.

En ce qui concerne le Richardson Maturity Model , vous pouvez accéder au niveau 3 sans jamais vous préoccuper des "modèles de domaine anémiques". N'oubliez pas que vous n'allez jamais transférer de comportement au navigateur (sauf si vous prévoyez d'injecter du Javascript dans vos modèles).

REST concerne principalement l'indépendance de la machine; implémentez le modèle REST dans la mesure où vous voulez que vos points de terminaison représentent les ressources, et pour que les consommateurs de votre API puissent facilement accéder et maintenir ces ressources de manière standard. Si cela semble anémique alors qu'il en soit ainsi.

Voir aussi
J'ai besoin de plus de verbes

10
Robert Harvey

L'API REST n'est qu'un type de couche de présentation. Cela n'a rien à voir avec le modèle de domaine.

La question que vous avez posée vient de votre confusion selon laquelle vous devez en quelque sorte vous adapter les uns aux autres. Non.

Vous mappez votre modèle de domaine à votre REST de la même manière que vous mappez votre modèle de domaine à un SGBDR via un ORM - il doit y avoir cette couche de mappage.

Domaine ← ORM → RDBMS
Domaine ← REST Mappage → REST

4

Cet article est assez lié au sujet et je crois qu'il répond à votre question.

Un concept de base qui, je pense, répond très bien à votre question, est résumé dans le paragraphe suivant de l'article mentionné:

"Il est très important de faire la distinction entre les ressources dans REST API et les entités de domaine dans une conception pilotée par domaine. La conception pilotée par domaine s'applique à l'implémentation des choses (y compris l'implémentation API) tandis que les ressources dans REST L'API pilote la conception et le contrat de l'API. La sélection des ressources de l'API ne doit pas dépendre des détails d'implémentation du domaine sous-jacent. "

3
Majix

À mon humble avis, je ne pense pas qu'ils tendent à encourager les modèles de domaine anémique (ADM), mais ils vous obligent à prendre un peu de temps et à réfléchir.

Tout d'abord, je pense que la principale caractéristique des SMA est qu'ils ont peu ou pas de comportement. Cela ne veut pas dire que le système n'a aucun comportement, juste qu'il se trouve généralement dans une sorte de classe de service (voir http://vimeo.com/4359819 ).

Et bien sûr, si le comportement n'existe pas dans l'ADM, alors qu'est-ce qui existe? La réponse est bien sûr les données. Et alors, comment cette carte correspond-elle à REST? Eh bien, les données sont probablement mappées au contenu de la ressource et le comportement correspond aux verbes HTTP.

Vous avez donc tout ce dont vous avez besoin pour créer un modèle de domaine riche, il vous suffit de voir comment les verbes HTTP sont mappés aux opérations de domaine sur les données, puis de placer ces opérations dans les mêmes classes qui encapsulent vos données.

Je pense que là où les gens ont tendance à rencontrer des problèmes, c'est qu'ils ont du mal à voir comment les verbes HTTP correspondent à leur comportement de domaine lorsque le comportement est au-delà du simple CRUD, c'est-à-dire lorsqu'il y a des effets secondaires dans d'autres parties du domaine au-delà du ressource en cours de modification par la requête HTTP. Une façon de résoudre ce problème est avec les événements de domaine ( http://www.udidahan.com/2009/06/14/domain-events-salvation/ ).

3
RibaldEddie

Plusieurs implémentations raisonnablement réussies que j'ai vues/construites répondent à la question de savoir comment elles mélangent la métaphore verbe + nom en utilisant des méthodes `` conviviales '' à grain grossier qui agissent sur les entités.

Ainsi, au lieu de la méthode/service (condamné) getName(), exposez getPerson(), en passant des choses comme l'identifiant-type/ID, en retournant l'entité Person entière.

Étant donné que les comportements de l'entité Personne dans un tel contexte ne peuvent pas être adéquatement transmis (ni peut-être ne devraient-ils pas être dans un contexte centré sur les données comme celui-ci), il est parfaitement raisonnable de définir un modèle de données (par rapport à Objet) pour les paires demande/réponse de les services.

Les services et les verbes définis eux-mêmes ajouteront des comportements, des contrôles et même des règles de transition d'état pour les entités. Par exemple, il y aurait une logique spécifique au domaine quant à ce qui se passe dans l'appel de service transferPerson() mais l'interface elle-même ne définirait que les entrées/entités de sortie/données sans définir LEURS comportements internes.

Je ne serais pas d'accord avec les auteurs qui diraient, par exemple, qu'une implémentation de verbe transfer appartient à la classe Person ou associée à un service centré sur la personne. En effet, la méthode de transfer pour un Person et ses options (dans cet exemple simple) serait mieux définie par un Carrier, où le Person peut ne pas savoir même quelles méthodes de transfert sont disponibles ni comment le transfert a lieu (qui sait comment les moteurs à réaction fonctionnent de toute façon).

Cela rend-il l'anémie Person anémique? Je ne pense pas.

Il peut/devrait y avoir une logique concernant les choses spécifiques à la personne qui sont internes à la personne comme leur état de santé, qui ne devraient pas être définies par une classe externe.

Cependant, selon les cas d'utilisation, il est tout à fait acceptable qu'une classe d'entité n'ait aucun comportement important/pertinent dans certains systèmes, comme un service d'attribution de siège dans un système de transport. Un tel système peut très bien implémenter des services basés sur REST qui traitent des instances Personne et des identifiants associés mais ne définissent/mettent jamais en œuvre leurs comportements internes.

1
Darrell Teague

Votre problème est-il que vous essayez de ranger votre modèle dans l'ensemble de verbes de base, en utilisant autant que possible POST?

Ce n'est pas nécessaire - je sais que pour la plupart des gens REST signifie POST, GET, PUT et DELETE, mais le http rfc dit:

L'ensemble des méthodes courantes pour HTTP/1.1 est défini ci-dessous. Bien que cet ensemble puisse être étendu, des méthodes supplémentaires ne peuvent pas être supposées partager la même sémantique pour des clients et serveurs étendus séparément.

Et des systèmes tels que SMTP utilisent le même style de méthodes verbales mais avec un ensemble totalement différent.

Donc, il n'y a aucune raison pour que vous les utilisiez, vous pouvez utiliser n'importe quel ensemble de verbes que vous aimez (cependant, vous constaterez que vous pouvez faire tout ce dont vous avez besoin dans le 4 de base avec un peu de réflexion). La chose qui rend REST distinctif des autres mécanismes est sa manière sans état et cohérente d'implémenter ces verbes. Vous ne devriez pas essayer d'implémenter un système de transmission de messages entre les niveaux comme vous ne le faites pas fondamentalement = REST alors, vous faites plutôt un mécanisme de passage de message, RPC ou file d'attente de messages qui vous perdra sans aucun doute les avantages de REST (c'est-à-dire la simplicité de qui le fait fonctionner très bien sur une connexion http).

Si vous voulez un protocole de messagerie complexe et complet, alors construisez-le (si vous pouvez le faire sur le Web, il y a une raison pour laquelle REST est si populaire), mais sinon essayez de vous en tenir à la conception architecturale de REST.

0
gbjbaanb