Microservices — Don’t Create Shared Libraries
As we have made the progression from a monolith toward a microservices based architecture the topic of shared libraries in microservices has continued to be a point of contention.
The debates really center around the apparent conflict between the DRY (Don’t Repeat Yourself) and loose coupling principles. Within a single project these principles are complementary whereas with microservices they can lead to conflicts when attempting to figure out how best to handle code that is common across these services.
Experienced developers have spent a lot of time perfecting the art of avoiding all forms of code duplication as much as possible. The inevitable result of this virtuous initiative is the creation of a “common” package. In a traditional software project the creation of the “common” library is almost always a good idea. When we start building microservices we naturally feel the need to create common packages and then ultimately a “common” library as we start creating separate microservices projects. The creation of these “common” libraries is ultimately a bad idea.
Shared Libraries and Coupling
One of the primary goals of microservices is to create loosely coupled services which can be changed independently from other services. The creation of our own “common” libraries creates coupling between the projects that depend on them because of the following reasons:
- The “common” library may contain complex logic which all the microservices depend on. When bug fixes and changes are applied to the common library, dependent services would need to update their dependencies to get the new changes. We may get into a situation where all dependent services would need to update their dependencies at the same time, depending on the nature of the fix.
- In another scenario, a single project may get into a state of “dependency hell” if they need to make a change to the common library. It would be best to apply the changes in the latest version of the common library. The latest version of the library may have its own new dependencies which are incompatible with the project’s own dependencies. Other methods in the common library may have also been changed in the new version forcing the dependent service to make multiple changes, unrelated to the original requirement, in order to maintain compatibility.
These are both symptoms of tight coupling where the coupling point is the shared library itself.
Strategies for Sharing Code
Duplicate It
Developers of microservices need to embrace the reality that duplication of code between microservices is actually okay; up to a point. Duplication of code within a specific microservice is NOT okay.
Common Service
If two or more microservices require the same logic and this logic is reasonably complex it would be a good idea to extract this functionality and deploy it as a separate microservice.
Technical vs Business Code
As a rule of thumb there should be no need to put business logic into a common library. If you are doing this, then the bounded context of your microservices domains are most likely incorrect, and/or you are missing a microservice.
For infrastructural code or code which handle purely technical concerns e.g. HTTP Request setup, Connection Pool management, Circuit Breaker and or Bulkhead implementations, we need to critically evaluate the need to extract these implementations into common libraries.
In most cases it would be far better to simply duplicate the implementation in each project to reduce the inevitable coupling issues.