2
votes

Dupliquer la logique métier en front-end avec le back-end de microservice ddd

Voici une question abstraite avec des implications dans le monde réel.

J'ai deux microservices; appelons-les le CreditCardsService et le SubscriptionsService .

J'ai également un SPA qui est censé utiliser le SubscriptionsService afin que les clients puissent s'abonner. Pour ce faire, le SubscriptionsService a un point de terminaison où vous pouvez POST un modèle d'abonnement pour créer un abonnement, et dans ce modèle se trouve un creditCardId qui pointe vers une carte de crédit qui devrait payer l'abonnement. Il existe certaines règles commerciales qui indiquent si vous pouvez ou non utiliser ladite carte de crédit pour l'abonnement (l'expiration est dans plus de 12 mois, c'est un VISA, etc.). Ces règles métier spécifiques sont liées au SubscriptionsService

Le problème est que l'équipe travaillant sur le SPA veut un point de terminaison / CreditCards dans le SubscriptonsService qui renvoie toutes les cartes de crédit valides de l'utilisateur qui peuvent être utilisées dans le modèle d'abonnements. Ils ne souhaitent pas implémenter les mêmes règles de validation métier dans le SPA que dans le SubscriptionsService lui-même.

Pour moi, cela semble aller à l'encontre des principes SOLID qui sont au cœur de la conception de microservices; spécifiquement la séparation des préoccupations. Je me demande aussi quel précédent cela va créer? Allons-nous devoir ajouter un point de terminaison / CreditCards au OrdersService ou à tout autre service qui pourrait utiliser creditCardId comme propriété de son modèle?

La question principale est donc la suivante: quelle est la meilleure façon de concevoir cela? La logique de validation métier doit-elle être dupliquée entre le frontend et le backend? Ce nouveau point de terminaison doit-il être ajouté au SubscriptionsService ? Devrions-nous essayer de simplifier la logique métier?


0 commentaires

4 Réponses :


3
votes

Il s'agit d'une demande tout à fait équitable et vous devriez proposer ce point de terminaison . Si vous définissez les règles pour lesquelles CC est valide pour votre service, vous devez offrir toute l'aide nécessaire pour y faire face également.

La logique ne doit pas être répétée. Cela a tendance à rendre les systèmes non maintenables.

Cela a moins à voir avec SOLID, même si SRP dirait également que si vous êtes responsable de quelque chose, toute logique connexe vous appartient également. Cette préoccupation ne peut être séparée de votre service, puisqu'elle y est définie.

En tant qu'option de solution, je voudrais peut-être voir si je peux me permettre de me connecter au service CC puisque vous en avez déjà un. Puis-je rediriger le client avec une requête construite peut-être vers le service CC pour obtenir tous les CC pertinents, sans les connaître réellement dans le service d'abonnement.


2 commentaires

L'idée de CreditCardSpecification pour aider à découpler les deux contextes est une idée intéressante. Bien que la spécification puisse vivre dans un package partagé, les entités CC elles-mêmes n'auraient pas besoin d'être connues par le contexte de l'abonnement. Vous pouvez implémenter quelque chose comme, validCardSpec = subscriptionService.validCreditCardSpecificationFor (...); validCards = creditCardService.allMatching (validCardsSpec); . Je ne sais pas si cela vaut mieux qu'une dépendance directe entre les deux contextes, mais c'est une idée à explorer à coup sûr.


Bien que je sois d'accord sur le fait que la logique ne doit pas être répétée, je pense également que l'ajout de ce point de terminaison spécifique associe davantage le service et va à l'encontre du principe de responsabilité unique, qui est au cœur des microservices. Le précédent établi est également quelque chose à considérer, car il s'agissait d'un exemple simplifié de mon problème. Nous avons un environnement de service qui compte actuellement plus de 100 services et qui finira probablement par avoir plusieurs centaines de services.



2
votes

Quelle est la meilleure façon de concevoir cela? La validation commerciale devrait-elle logique être dupliquée entre le frontend et le backend? Devrait-il nouveau point de terminaison être ajouté à SubscriptionsService? Devrions-nous essayer de simplifier la logique métier?

De mon point de vue, j'intégrerais "Subscription BC" (S-BC) avec "CreditCards BC" (CC-BC). CC-BC est en amont et S-BC est en aval. Vous pouvez le faire avec l'API REST dans CC-BC ou avec une file d'attente de messages.

Mais ce que je valide, c'est l'opération effectuée avec un CC, pas le CC lui-même, c'est-à-dire valider "ce CC est-il valable pour l'abonnement". Et cette validation est en S-BC.

Si le SPA veut récupérer "les CC d'un utilisateur qu'il / elle peut utiliser pour l'abonnement", c'est une fonctionnalité du S-BC.

Le client (SPA) doit appeler l'API S-BC pour utiliser cette fonctionnalité, et le S-BC exécute la fonctionnalité en récupérant les CC du CC-BC et en effectuant la validation.


4 commentaires

Je suppose que "BC" dans votre exemple est Bounded Context. Vous diriez donc que la liste des cartes de crédit valides pour un abonnement fait partie du contexte limité de l'abonnement?


Oui, la Colombie-Britannique est un contexte limité. Et en relisant ma réponse et en jetant un œil à la façon dont je fais la validation dans un de mes projets, j'ai réalisé que je ne l'avais pas mis correctement dans la réponse. Je vais le corriger dès que possible. Quoi qu'il en soit, l'abonnement BC n'est pas clair pour moi. Quelles entités avez-vous là-bas? Et comment est le contrat de l'opération d'abonnement? Merci


Bonjour, après avoir repensé le design, j'ai décidé de ne pas changer ma réponse. Je pense que je le ferais de cette façon. Oui, la liste des cartes de crédit valides pour un abonnement serait retournée par le S-BC, qui les obtient du CC-BC (qui est en amont). Vous intégrez S-BC en appelant une API REST de CC-BC ou en conservant une copie des cartes de crédit dans la base de données S-BC, qui est mise à jour en écoutant les événements publiés par CC-BC. S-BC doit connaître les cartes de crédit. Il les récupère de CC-BC et les renvoie au client (SPA)


De plus, si vous aviez d'autres moyens de payer un abonnement, vous devriez également intégrer S-BC avec eux, et les valider dans le S-BC. Dans le S-BC, vous auriez la "manière d'abstraction" "de payer", étant l'une d'elles par carte de crédit.



0
votes

Même lorsque la source de vérité est le modèle de domaine et que finalement vous devez avoir une validation au au niveau du modèle de domaine, la validation peut toujours être gérée au niveau du modèle de domaine (côté serveur) et l'interface utilisateur (côté client). La validation côté client est très pratique pour les utilisateurs. Cela fait gagner du temps qu'ils passeraient autrement en attente d'un aller-retour vers le serveur qui pourrait renvoyer des erreurs de validation. En termes commerciaux, même quelques les fractions de secondes multipliées des centaines de fois par jour représentent beaucoup de temps, de dépenses et frustration. Une validation simple et immédiate permet aux utilisateurs de travailler plus efficacement et produire une entrée et une sortie de meilleure qualité. Tout comme le modèle de vue et le modèle de domaine sont différents, la validation du modèle de vue et le modèle de domaine la validation peut être similaire mais servir un objectif différent. Si vous êtes préoccupé par DRY (le Répétez-vous le principe), considérez que dans ce cas, la réutilisation du code peut également signifier un couplage, et dans les applications d'entreprise, il est plus important de ne pas coupler le côté serveur au côté client que de suivez le principe DRY. (Livre NET-Microservices-Architecture-for-Containerized-NET-Applications)


1 commentaires

Ma préoccupation n'est pas de savoir si le SubscriptionService valide ces données lui-même. Cela devrait absolument. Ma préoccupation est de savoir s'il doit avoir son propre point de terminaison / CreditCards qui ne renvoie que les entités de carte de crédit valides pour les abonnements.



1
votes

Dans les microservices et DDD, le service d'abonnement doit avoir un point de terminaison de carte de crédit s'il s'agit de données pertinentes pour le contexte limité des abonnements.

Le point de terminaison des cartes de crédit peut servir un modèle de données légèrement différent de celui que vous trouveriez dans le service de cartes de crédit lui-même, car dans le contexte des abonnements, une carte de crédit peut avoir une apparence ou un comportement différent. Le service d'abonnement aurait une table de cartes de crédit ou un magasin de sauvegarde, probablement, pour prendre en charge le stockage de son propre schéma de cartes de crédit et se référer à une source de vérité pour maintenir ces données en bon état (par exemple, des messages sur les événements de carte sur un bus, ou un autre mécanisme).

Cela permet 3 choses, premièrement, le service d'abonnement ne sera pas complètement désactivé si les cartes tombent en panne pendant un certain temps, il peut se référer à sa propre table et fonctionner de toute façon. Deuxièmement, votre code de domaine sera plus ciblé car il n'aura à traiter que les propriétés des cartes de crédit qui comptent vraiment pour résoudre le problème actuel. Enfin, si votre magasin de cartes peut même avoir des propriétés supplémentaires spécifiques au domaine qui sont calculées et matérialisées sur le magasin.

Lien Fowler obligatoire: Modèle de contexte borné


1 commentaires

J'aime cette réponse. C'est similaire à la réponse stellaire que j'ai obtenue de @ robert-bräutigam, mais il a également le lien obligatoire de fowler pour résumer les choses.