Lets assume that we have a Spring Boot application that uses microservices architecture. Each of the services has its own domain models, but each service must reference a User domain object. What would be the best approach on how to solve this issue? Would it be better for each service to just have a userId and then, when needed, ask user service for user details, or would it be better to have a shared domain library for all microservices?
If you did go for microservices to benefit from scalability, loose coupling, and easy independent modification of each service, the you should stick to it to the maximum possible extent.
I think that the best approach would be:
- have a microservice for general user information management;
- keep microservice specific user information (e.g. profiles, authorizations, preferences) in each microservice (using the referene of the general id)
- This article describes very well this kind of architecture and rationale, with the specific case of authorizations.
- This article describes challenges and solution for user identity management, to avoid all the services to access to the same repository.
- This article describes ho to use JWT to pass the identity of the user between the services (noting that some basic information can be provided in the id token, which avoids having to query the user service one more after the login, at least for very basic information).
Now if you agree on the solution above, we have a user microservice (encapsulating domain model for user) and all other services are consumers of the same microservice. The question is then to know if you want:
- either each microservice to reinvent the consumer code, following the dogma of strong separation for allowing flexible and distinct release cycles,
- or to share the consumer code as part of the library, considering that this fundamental information is an extension of the "chassis" infrastructure pattern.
I will not take a clear cut position on that, as there are opinatered opinion wars on this code sharing topic, and I don't think that I'm in a position to take an objective position. Here is already some additional reading:
- This article thinks there is no best solution, and it all depends on your objectives
- This article position is that code sharing is bad only if it creates a strong coupling, and code sharing can bring some synergies
- This article (of people who implemented microservices at scale) insist on the necessity to have separate builds, and the potential decommission issues of older code. Having a shared library for consuming with solid version management does not prevent these good practices.
My own opinion on that is that you SHOULD NOT SHARE code between the user-provider and the user-consumers, in order to avoid a tight coupling. However you COULD SHARE the user-consumption code between consumers if you have a strong version management in place. This approach would have some advantages:
- Different user-consuming microservices could be build with different versions of the shared user-consumption code (as long as the versions are compatible with the independent user-provider). Same flexibility that reinventing the wheel but higher productivity.
- You could change your user-provider service independently without impact on the consumers.
- If a bug is found on consumption side, you could correct it once and deploy all the consumers as best suits (thanks to version management). THis could even lead to a higher quality of service.
- If for a reason you are obliged to update the user-provider API, you could deploy the updated user-consumption more quiclkly. It you keep old and new provider service active during the transition, this sharing possibility could allow to decommission more rapidly the older version of the consumer-provider.
I'd avoid a shared library if at all possible. Ask yourself what properties of a user does each service need? Often there is a core domain where most of the behaviour surrounding a user will live, with supporting domains often only needing a userId.
If your service needs some other details regarding a user, have a look at some suggestions here regarding how to handle such situations