web-dev-qa-db-fra.com

Modèle de domaine partagé entre différents microservices

Imaginez un scénario de deux microservices différents. L'un pour gérer l'authentification au sein du service, l'autre s'occupe de la gestion des utilisateurs. Ils ont tous les deux un concept d'utilisateur et parleront d'utilisateurs en s'appelant.

À quoi appartiendrait le modèle de domaine d'un "utilisateur"? Auraient-ils tous les deux une représentation différente de ce qu'est un utilisateur au niveau de la base de données? Qu'en est-il lorsque nous avons un UserDTO à utiliser dans les appels d'API, auraient-ils tous les deux un pour leurs API respectives?

Quelle est la solution généralement acceptée pour ce type de problème architectural?

65
Kristof

Dans une architecture de microservices, chacun est absolument indépendant des autres et il doit masquer les détails de l'implémentation interne.

Si vous partagez le modèle, vous couplez des microservices et perdez l'un des plus grands avantages dans lequel chaque équipe peut développer son microservice sans restrictions et sans avoir besoin de savoir comment évoluer les autres microservices. N'oubliez pas que vous pouvez même utiliser différentes langues dans chacune d'elles, ce serait difficile si vous commencez à coupler des microservices.

S'ils sont trop liés, ils sont peut-être vraiment un comme le dit @soru.

Questions connexes:

38
gabrielgiussi

Si deux services sont suffisamment entrelacés pour que cela soit difficile de les implémenter sans partager les DTO et autres objets de modèle, c'est un signe fort que vous ne devriez pas avoir deux services.

Certes, l'exemple n'a guère de sens en tant que deux services; il est difficile d'imaginer une spécification pour la "gestion des utilisateurs" si compliquée qu'elle garderait toute une équipe si occupée qu'elle n'a pas le temps de faire l'authentification.

Si pour une raison quelconque, ils le faisaient, ils communiqueraient en utilisant des chaînes essentiellement arbitraires, comme dans OAuth 2. .

13
soru

Vous pouvez les considérer comme deux contextes délimités distincts (dans le langage de conception pilotée par domaine). Ils ne doivent pas partager de données entre eux, à l'exception d'un identifiant utilisé pour corréler "l'utilisateur" du contexte d'authentification avec l '"utilisateur" de l'autre contexte. Ils peuvent chacun avoir leur propre représentation de ce qu'est un "utilisateur", et leur propre modèle de domaine, qui contient uniquement les informations nécessaires pour assumer leur responsabilité commerciale.

N'oubliez pas qu'un modèle de domaine n'essaie pas de modéliser une "chose" du monde réel, mais ce que cette chose est dans un contexte particulier (comme la gestion des identités/autorisations ou des ressources humaines, etc.).

4
pnschofield

Ils ont tous les deux un concept d'utilisateur et parleront d'utilisateurs en s'appelant.

Je suis également d'accord avec ce que @soru a dit. Si un service a besoin des données d'un autre service, ses limites sont fausses.

Une solution intéressante est ce que @pnschofield a proposé: traiter vos services comme un contexte borné.

Pour parler du sujet, dit brièvement: les modèles de domaine partagé tuent l'autonomie des services, transformant votre système de microservices en monolithe distribué. Ce qui est apparemment encore pire qu'un monolithe.

Il reste donc une question générale non résolue - comment définir les limites de service ou de contexte, afin qu'elles prospèrent dans une grande cohésion et un bon couplage lâche.

J'ai trouvé une solution pour traiter mes contextes comme une capacité commerciale. Il s'agit d'une responsabilité commerciale de niveau supérieur, d'une fonctionnalité commerciale, contribuant à l'objectif commercial global. Vous pouvez les considérer comme des étapes que votre organisation doit suivre pour obtenir une valeur commerciale.

Ma séquence typique d'étapes que je prends lors de l'identification des limites de service est la suivante:

  1. Identifiez les capacités commerciales de niveau supérieur. Habituellement, ils sont similaires parmi les organisations du même domaine. Vous pouvez avoir une idée de ce à quoi cela ressemble en vérifiant modèle de chaîne de valeur de Porter out.
  2. Dans chaque capacité, approfondissez et identifiez les sous-capacités.
  3. Notez la communication entre les capacités. Regardez ce que fait une organisation. Habituellement, la communication est concentrée dans les capacités, informant le reste du résultat de son travail. Ainsi, lors de la mise en œuvre de l'architecture technique, votre service doit également communiquer via des événements. Cela a de multiples conséquences positives. Avec cette approche, vos services sont autonomes et cohérents. Ils n'ont pas besoin de communications synchrones et de transactions distribuées.

Un exemple de cette technique vous intéresserait probablement. N'hésitez pas à me faire part de vos réflexions, car j'ai trouvé cette approche vraiment rentable. Bien sûr, cela peut aussi fonctionner pour vous.

2
Zapadlo

Le microservice ne consiste pas à "ne rien partager", mais à "partager le moins possible". Dans la plupart des cas, "l'utilisateur" est une entité vraiment commune (simplement parce que l'utilisateur est identifié par un identifiant partagé - userId/email/phone). Ce genre d'entités partagées par définition. Le modèle utilisateur est hors de portée d'un microservice. Vous devez donc avoir un schéma global, où l'utilisateur (juste leurs champs les plus courants) doit être placé. Dans le cas strict, c'est seulement l'identifiant.

1
Evgeniy Ostapenko

Celui-ci semble être un très bon guide de micro-services: https://docs.Microsoft.com/en-us/dotnet/architecture/microservices/ , il suggère que les micro-services suivent un domaine conception (DDD) et modèle de contexte délimité ( https://docs.Microsoft.com/en-us/dotnet/architecture/microservices/architect-microservice-container-applications/data-sovereignty-per-microservice =), ce qui signifie qu'ils ne doivent pas partager de données entre eux. Je n'ai pas pu trouver de recommandation sur ce que vous faites et vous gérez vos contrats (DTO ou événements).

Une option consiste à ce que chaque service ait sa propre copie des classes de contrat, ce qui peut sembler une bonne idée, afin que chaque service puisse évoluer de lui-même. Pratiquement, ce n'est pas une bonne idée. Dans la plupart des cas, la communication entre les micro-services se résume physiquement à l'échange de messages JSON avec REST ou files d'attente de messages. JSON est un format sensible à la casse, ce qui signifie que "userID" est pratiquement différent de "userId" et "UserId", peu importe que sémantiquement, c'est la même chose. J'ai vu de nombreux problèmes juste à cause de cela, et la synchronisation d'un grand paysage est vraiment difficile.

Ce que j'aime vraiment, c'est d'avoir une bibliothèque séparée (NuGet, Maven, etc.) qui contient les contrats de données, afin qu'ils puissent être facilement réutilisés. Dans le cas d'un grand paysage, il peut être divisé en fonction des domaines. Il peut évoluer et aura différentes versions. Dans le cas de changements incessants, les micro-services peuvent continuer à travailler avec les anciennes versions, dans le cas de nouvelles versions d'API, puis de nouvelles versions sont publiées et celui qui le souhaite migrera.

J'ai entendu parler d'une approche où vous pouvez avoir un langage sémantique pour définir des contrats, et cela est compilé pour des classes particulières pour différents langages de programmation. L'idée est que la définition des données/contrats passe en premier.

0
llatinov