Nguyen Le PhongNguyen Le Phong

Foundations of Software ArchitecturePart 12 of 15

The True Cost of Microservices

Microservices can create real team autonomy, but they move cost into operations, data consistency, observability, testing, and coordination. This piece asks when that cost is worth paying and when a modular monolith is the kinder architecture.

The quietest architecture conversations often happen before they reach the diagram. Someone points at the release calendar and says the checkout team is blocked again because the catalog team is not ready. Another person opens the dependency board and shows three features waiting behind the same shared deployment. A week later, the word microservices appears in a planning document, not as a technology choice yet, but as a hope that teams can finally stop waiting for each other.

That hope is understandable. A growing monolith can feel heavy. One deployment pipeline serves every team. One shared database becomes the place where every shortcut and emergency fix settles. A small change in billing can create fear in onboarding. Meetings become less about product decisions and more about finding a release window that does not hurt anyone too much. When people say they want microservices, they are often asking for something very human: room to move.

Nguyen Le Phong talks with two teammates around a release-planning table while a dependency calendar and service cards cover the wall behind them.
Microservices often enter the room first as a human hope: maybe this time the team can stop waiting behind the same release calendar.

The difficult part is that microservices rarely remove complexity. They relocate it. The code may become smaller inside each service, but the system becomes larger between services. A function call becomes a network call. A transaction becomes a saga or an eventually consistent workflow. A local stack trace becomes a trace across five services, three queues, and two dashboards. The cost does not disappear just because the repository looks cleaner.

The first cost is operational. Every service needs a build, deployment, configuration, secret management, health check, alert, log stream, dashboard, rollback path, and owner. One service is manageable. Ten services require discipline. Fifty services require a platform. Without that platform, engineers spend less time improving the product and more time remembering which service owns which failure mode. Microservices ask the organization to become good at operations before the architecture can feel light.

Nguyen Le Phong and a platform teammate sit under blue-hour monitor light, tracing service dashboards, alert timelines, and architecture sketches spread across the desk.
The architecture starts to feel expensive at night, when every service wants its own dashboard, alert path, rollback plan, and owner.

The second cost is data. In a monolith, consistency is often boring in the best possible way. A database transaction can update related records together, and the code can rely on that boundary. In microservices, each service should own its own data, which means the system must accept delay, duplication, and repair. An order may be created before the invoice is visible. A payment may succeed while the notification service is down. These are solvable problems, but they are not free problems. They require careful event design, idempotency, reconciliation, and product language that helps people understand temporary states.

Nguyen Le Phong and a product teammate map delayed event states across a glass wall of cards and arrows so temporary order and payment states stay understandable.
Distributed data stops being abstract the moment the team must explain a temporary state clearly enough for both the product and the repair path to survive it.

The third cost is observability. When a user says the page is slow, the answer is no longer in one log file. It may sit inside a chain: API gateway, auth service, order service, inventory service, payment service, message broker, email worker. To debug that without guesswork, the team needs trace IDs, structured logs, metrics, SLOs, and enough shared practice to read them under pressure. Observability is not decoration for microservices. It is part of the architecture.

The fourth cost is testing. Unit tests remain useful, but many important failures live at the boundary between services: a changed API contract, a missing event field, a timeout that only appears when a downstream dependency is slow. Teams need contract tests, integration environments, realistic fixtures, and a habit of thinking about failure paths. Otherwise the system only works when every service behaves politely, which is not a reliable assumption.

The fifth cost is coordination, even though coordination is the thing microservices are supposed to reduce. Teams can deploy independently only when their contracts are stable, their ownership is clear, and their dependencies are honest. If every service still needs three other teams to release first, the organization has not escaped the monolith. It has built a distributed version of the same waiting room.

This is why the most useful question is not, should we use microservices? A better question is, which cost are we already paying, and which cost are we ready to pay next? A modular monolith may be the wiser answer for a long time. It can give teams clearer boundaries, better ownership, and cleaner code without forcing every product change to cross the network. Sometimes the kindest architecture is the one that keeps simple things simple while preparing clean seams for the day extraction becomes necessary.

Microservices begin to make more sense when the pain is no longer theoretical. Teams are blocked by shared deployments every week. Some domains need independent scaling. Failures should be isolated because one part of the product is much riskier or much busier than the rest. The organization has enough engineering maturity to own pipelines, observability, incident response, and service contracts. At that point, microservices can be a good trade, not because they are modern, but because they match the shape of the work.

I have seen teams become calmer after extracting the right service. The deploy became smaller. The owner became clearer. The dashboard finally showed one team the health of the thing they were responsible for. I have also seen teams become slower after extracting too early. Every feature needed choreography. Every local setup became fragile. Every bug became a small investigation across services that nobody fully owned. The difference was not the architecture diagram. It was whether the team had enough reason and enough practice to pay the bill.

The true cost of microservices is not only cloud spend, Kubernetes YAML, or extra repositories. It is the attention required to keep a distributed system understandable. It is the discipline to make contracts explicit, failure visible, data repairable, and ownership real. If your team is ready to pay that cost, microservices can create meaningful freedom. If not, there is no shame in staying with a well-kept modular monolith a little longer. Good architecture is not the one that sounds advanced in a meeting. It is the one your team can operate, explain, and improve on an ordinary Tuesday afternoon.

Before choosing microservices, a team can ask a very plain question: which cost are we already paying, and which new cost are we ready to own every week? The answer usually says more than the architecture label.

What did you think?