TL; DR - Est-il possible de partager une bibliothèque POJO entre les services?
Généralement, nous aimons garder le partage entre les services strictement limité à aucun si possible. Il y a eu un débat sur la question de savoir si le service qui partage des données devrait fournir une bibliothèque-client à utiliser par les clients. Le client-lib est généralement facultatif pour un client du service à utiliser et peut consommer l'API comme bon lui semble, que ce soit pour utiliser le client-lib, ou utiliser un autre langage et utiliser les aspects généraux de la bibliothèque et autres.
Dans mon cas - je considère un service qui crée un objet de données. Supposons que cet objet soit un PET. Ce n'est PAS l'entité de base de données, mais strictement un POJO qui représente implicitement les données sous-jacentes. Ce POJO est ce que l'API a défini. Supposons: Animal de compagnie - âge, poids, nom, propriétaire, adresse, espèce, etc.
Service 1 - PetKeeper: Il générera un animal de compagnie pour une raison quelconque et conservera toutes les données et doit référencer ce service pour obtenir l'animal de compagnie, ou apporter des modifications à l'animal de compagnie, disons que le nom change, ou le changement d'adresse doit être effectué via un appel API à ce service.
Service 2 - PetAccessor: Ce service rassemble l'animal et effectue des contrôles de validation
Service 3,4 - Plus d'appels de service intermédiaires
Service 5 - Interface utilisateur
Ce sont très arbitraires mais le point est simple. L'interface utilisateur ou un service orienté utilisateur souhaite présenter en quelque sorte cet objet "PET". Il doit appeler via une API un service, qui appelle un service, qui appelle un service, etc. jusqu'à ce qu'il atteigne le service qui rassemble les informations requises et recommence le relais. Enfin, le service d'interface utilisateur a l'objet PET à afficher.
Ceci est assez courant - mais avec notre mentalité absolue, nous avons dupliqué le principe PET dans chaque service. DRY (ne vous répétez pas)) le principe ne s'applique qu'aux code INSIDE un service et ne s'applique pas à travers les services mais le point est toujours là. Et si nous ajoutons un champ ... nous devons modifier 5 services du POJO dans chacun.
--OU-- Nous pouvons fournir une bibliothèque Pet-Objects qui contient certains des pojo de l'API et chaque service peut importer/dépendance sur la bibliothèque. Il n'y a aucune dépendance sur le (s) service (s) eux-mêmes, mais uniquement sur la bibliothèque générale. J'aime cette idée pour que chaque service ait le même type d'objet et les mises à jour soient plus faciles. Mais je suis préoccupé par les objets divins.
Quels sont les avantages et les inconvénients - quel est le meilleur design? Qu'avez-vous fait pour transmettre des données entre les services afin de minimiser la répétition des mêmes classes POJO tout en restant découplé?
Quel est le meilleur design?
Vous pouvez réutiliser le même Pet
[~ # ~] dto [~ # ~] objet parmi les services backend (qui traitent le type logique métier), mais en ce qui concerne le niveau de présentation (interface utilisateur), il est généralement recommandé d'utiliser un FormBean (un bean différent avec champs supplémentaires pour la logique de présentation) afin que il y ait une séparation claire entre la logique de présentation et la logique métier .
Ceci est nécessaire car les services doivent être réutilisables et un seul service peut être exposé/réutilisé par plusieurs points de terminaison/différents (comme le frontend ou peut être un service Web différent, etc.) et chacun de ces points de terminaison peut nécessiter des champs supplémentaires qui seront remplis par les contrôleurs ou couches respectives (comme les adaptateurs) au-dessus des services.
Qu'avez-vous fait pour transmettre des données entre les services afin de minimiser la répétition des mêmes classes POJO tout en restant découplé?
Si vous utilisez un seul bean entre les niveaux métier et Web, vous couplez étroitement la logique de présentation avec la logique métier , ce qui n'est pas une bonne pratique et vous vous retrouverez changer les services pour une exigence dans le Frontend (comme par exemple, un format de date différent à afficher dans l'interface utilisateur). De plus, pour effectuer ce processus de remplissage/copie des données sur les beans (comme DTO vers FormBean ou Viceversa), vous pouvez utiliser des bibliothèques comme ApacheBeanUtils.copyProperties()
ou Bulldozer pour éviter le code passe-partout .
Si le DTO représente la même entité commerciale dans tous les microservices, il ne devrait y avoir qu'une seule classe, partagée entre les services. Il n'est (presque) jamais correct d'avoir du code en double pour le même objet.
La façon dont je prévois de le faire maintenant, c'est que chaque service ne regroupe que des DTO et les place dans Nexus en tant que lib jar. Quand un autre service en aura besoin, il obtiendra ces librairies DTO comme dépendance dans manve/gradle. Si la nouvelle version de DTO est publiée sur un service, c'est bien tant que l'ancienne version est également prise en charge en même temps, alors ne rompez pas la compatibilité ascendante, le versioning, etc. Aussi pour éviter la dépendance circulaire, il vaut mieux séparer le service de l'emballage dto
Maintenant, regardez backend-to-frontend et vice versa Je ne suis pas d'accord avec les commentaires précédents selon lesquels l'interface utilisateur en tant que couche de présentation est différente. IT IS NOT !!! UI est juste un autre microservice pour moi qui consomme et produit également des événements.
Direction backend-to-frontend Ce que je fais est de convertir POJO (dtos) en interfaces TypeScript et de les empaqueter en NPM et de les charger également dans Nexus. Le projet basé sur UI nodejs les consomme et les utilise ensuite. C'est un service de façon à l'interface utilisateur.
direction Frontend-to-backend Pour l'interface utilisateur pour desservir les événements de la couche, je convertis les interfaces TypeScript et les convertis en POJO (dtos), les empaquette sous forme de jar et les télécharge sur Nexus (ou un dépôt) sous forme de jar à être consommé par les services backend.
Ces processus sont facilement gérés par les processus CI (Travis, Gitlab CI, etc.)
Tous les commentaires sur cette approche sont les bienvenus.