Many organizations rush into microservices and end up with the worst of both worlds: the complexity of distributed systems without the benefits of independent deployment. The culprit? Misaligned interfaces between your runtime architecture and your deployment processes.
The Interface Problem
Think of deployment and testing processes as function calls with specific contracts. The problem happens when these contracts don’t match your runtime architecture:
When contracts assume all-or-nothing:
(runTests(allServices) -> deploy(serviceA, serviceB, serviceC))
What the contracts should look like for true microservices:
(runTests(serviceA) -> deploy(serviceA))
(runTests(serviceB) -> deploy(serviceB))
(runTests(serviceC) -> deploy(serviceC))
Many places end up with microservice runtimes but monolithic test management. You have services that could run independently, but your testing pipeline treats them as a single unit. This breaks the fundamental promise of microservices: independent change and deployment.
The Visual Reality
The boxes in this illustration represent different code bases with their own histories, and the colors represent concerns that could be loosely coupled. What we want is either a modular monolith or properly designed microservices.
What to avoid: The third scenario—runtime decoupling with verification-time coupling. When any change requires going through a process involving everything else, you’ve fundamentally contradicted the independent change implied by decomposing concerns into separate services.
Why This Happens

what teamwork means to some
what teamwork can be
The Mismatched Reality
Runtime decoupling + Verification-time coupling = Distributed Monolith
If your “microservices” all need to be deployed together, tested together, or versioned together, you haven’t gained the benefits of microservices.
Better Approaches
- Modular Monolith: Keep it simple with good internal boundaries
- True Microservices: Achieve genuine independent deployment and operation
- Don’t cargo cult: Understand the costs before adopting distributed architecture
The key is ensuring that your deployment and verification processes match your runtime architecture. If you’ve split services at runtime, they should be independently deployable and testable.
Conclusion
Before breaking up your monolith, ask yourself: Can each service truly change, deploy, and operate independently? If not, you might be building a Frankenstein MonoMicroLith that gives you complexity without the benefits.
For deeper insights on modular software design, check out this article by Threedots on achieving modularity with both microservices and monoliths.