DRY vs Microservices: When Reuse Becomes a Liability | Microservice Architecture — Ep. 17
“Don’t Repeat Yourself” principle sits at the core of software engineering. We usually structure our code to have as few to changes as possible when requirements shift.
This approach is right inside any single microservice — use it! But it gets trickier when DRY is applied across microservices. Not every duplicated piece of logic should be extracted into a shared library.
Remember, the goal of microservice architecture is independent deployment. Shared libraries work against that goal and introduce coupling:
- Updating a library forces coordinated releases across multiple services (who owns the library and coordination then, by the way?).
- A bug in the library makes all dependent services vulnerable.
- Frequent library updates open a potential for version conflicts and dependency hell.
So what if logic really needs to be shared?
If it is cross-service communication logic, sharing code can be a good tradeoff. Libraries or code generation to keep contracts in sync (schemas, clients, message definitions) usually increase development speed rather than hinder it.
If it is business logic, this might indicate a boundary problem. Combine microservices into a single, more cohesive one — or extract that logic into a dedicated service.
If introducing a new service is undesirable, the sidecar pattern is a possible solution. Move shared logic into a separate process running co-host with each service instance. This way service and sidecar lifecycles get separated, avoiding tight compile-time dependencies.
In microservices, duplication is often cheaper than coordination.