The microservices rollback is really an operations story
Teams are not rejecting modularity. They are rejecting a deployment model that turns every feature into distributed operations overhead.
The microservices rollback is mostly an operations story. Teams are not discovering that modularity is bad. They are discovering that every new service is an operations obligation.
A service needs deployment, logs, metrics, alerts, dashboards, ownership, versioning, secrets, networking rules, local development support, test strategy, and incident response. If the business value of the split does not exceed that overhead, the architecture is a tax.
Small teams feel the tax first
Large platform organizations can hide the cost with internal tooling. Small and mid-size teams feel it immediately. One feature now touches five repositories. One bug requires three dashboards. One local test needs a zoo of dependencies. One API change becomes a release negotiation.
The useful compromise
The practical answer is not “monolith forever.” It is a modular monolith with strict internal boundaries, plus selective extraction when the reason is concrete: different scaling profile, separate reliability domain, separate compliance boundary, or independent team ownership that is actually mature.
Cost is a design input
Cloud bills, state-machine transitions, network traffic, observability volume, and engineering time are part of architecture. If a design looks clean on a diagram but makes the monthly bill and on-call rotation worse, it is not clean.
Operational rules
- Start with modules and interfaces before services.
- Extract only when the module has a clear independent runtime need.
- Measure latency, deployment friction, and incident cost after each split.
- Merge services when the operational cost has outgrown the benefit.
The better question is no longer “microservices or monolith?” It is “which boundary deserves to become physical?”
The healthier response to microservice fatigue is not to abandon modular thinking; it is to separate logical boundaries from runtime boundaries. A modular monolith can still enforce ownership through packages, interfaces, tests, and database access rules while avoiding the operational tax of networks, retries, service discovery, distributed tracing, and partial deployments for every feature. The migration question should therefore start with failure cost. If a module must scale independently, be deployed by a separate team, or tolerate isolation from the rest of the product, a service may be justified. If the boundary mainly exists because the architecture diagram looked cleaner, the runtime split may be premature. Verification should be boring: can the team change one module without touching unrelated code, run focused tests, and roll back the whole application safely? If not, splitting it into services will usually multiply the confusion rather than create discipline.