The term “microservices” now comes up in many technical proposals, and it’s sometimes presented as if it were a mark of modernity in itself. But it’s an architectural choice with clear benefits and clear costs, and the right question isn’t whether it’s modern, but whether your situation needs it now.
This decision isn’t for the technical team alone. It determines how much the system costs to run each month, how many people you need to look after it, and how long it takes to release any change. That’s why we explain it here in the language of decision-makers, not architects.
What microservices are, in plain language
Imagine a system that manages orders, inventory, and invoicing. In the traditional approach, all of this is a single application, deployed in one go and using one database. In a microservices architecture, the system is split into small, independent services: each one handles a single business capability, each has its own data, and they communicate with one another through defined APIs.
The essential difference is that each service is deployed on its own: the invoicing service can be changed and released without redeploying the rest of the system. That is the source of its strength, and of its cost too, because what used to be a call inside one program becomes a network connection between separate programs.
You could compare it to a company that moves each of its departments into a separate building. Each department gains more freedom to organize its work, but every bit of coordination between two departments now takes messages and waiting, and every breakdown in those messages becomes a problem someone has to track down.
The alternative we’re comparing against here isn’t a system whose parts are tangled together without order. It’s a single system divided internally into modules with clear boundaries, known as a modular monolith. It’s deployed as one application, but each module in it has a defined responsibility and data it owns.
The real cost that does not show in the first proposal
Every additional service means one more thing to run, monitor, and update. The cost shows up in five places:
- Operations: each service has its own deployment environment, configuration, and resources, and the services usually need a tool that manages how they run and restarts any that fail.
- Monitoring: when a single request fails, the error may be in any service it passed through. So you need central logs and tracing of each request across the services; otherwise, diagnosing a problem turns into a long search.
- Data consistency: when data is spread across several databases, a single operation is no longer one transaction that either fully succeeds or fully fails. An order may be recorded in one service while the stock deduction in another service lags behind, and the design has to handle that case explicitly.
- Deployment and versions: every update to a service must avoid breaking the services that depend on it, which requires discipline in managing API versions.
- Team size and experience: distributed systems need broader operational experience, and extra time for every problem that runs through more than one service.
This cost doesn’t mean the architecture is bad. It means the architecture has to give you something you actually need in return for what you pay to run and look after it.
And the cost shows up in the company’s numbers, not just in the code: a higher hosting bill because each service needs its own resources, more of the team’s time spent on operations instead of building features, and a need for skills your current team may not have.
When microservices are worth the cost
Microservices justify their cost when several conditions like the following come together, not when just one of them appears:
- Parts of the system that need to scale at different rates, such as an online store that comes under heavy load in peak seasons while accounting stays steady.
- Several teams that work independently and need to release their updates without waiting for one another.
- Parts that are very different in nature, such as a service that processes large files alongside simple data-entry screens, or a part that needs a different technology from the rest.
- Modules whose failures must be isolated, so that one of them failing doesn’t stop the rest of the system.
- Clear, stable business boundaries between the parts, which aren’t expected to change much.
Suppose a company has an online store, a warehouse system, and an accounting system, each with its own independent team, and demand on the store peaks in certain seasons. Here, splitting the store into a separate service that scales on its own becomes a decision with a clear practical justification, because each team releases its changes on its own schedule, and the load on the store doesn’t touch accounting.
When a single system with clear modules is the better start
If the team is small, if the system is just starting out and the business rules are still changing, or if the boundaries between its parts aren’t clear yet, splitting early locks in boundaries that may be wrong. And changing those boundaries later, between separate services, is much harder than changing them inside one system.
A single system divided into modules gives you many of the benefits of a clear structure without the cost of distributed operations: one deployment, one database, transactions that either fully succeed or fully fail, and easier diagnosis of errors. This model covers the needs of many business systems that serve one company and its branches, as long as it has been built with discipline.
Suppose a trading company with a small development team wants a system for sales, inventory, and purchasing. Splitting that system into services from the start multiplies what has to be monitored and run, without solving any problem the company actually faces. Building it as a single system with clear modules, on the other hand, lets it be launched module by module at a lower running cost.
How to keep the door open
Starting with a single system doesn’t close the road to microservices later, provided it’s built in a way that allows parts to be split off when a real reason appears:
- Clear boundaries for each module: orders, inventory, and invoicing are separate modules in the code, each with a written responsibility.
- Data owned by each module: no module writes directly to another module’s tables or reads its internal details.
- Defined interfaces between modules: modules communicate through declared, API-like interfaces, so any of them can easily be turned into a real API over the network.
- Events instead of tangled calls, where it fits: when an order is approved, its module announces it, and the modules concerned act on that.
- Monitoring and well-organized logs from the start, so that splitting a module off doesn’t begin from scratch when the time comes.
This way, a module that becomes a candidate for splitting off is almost ready: its boundaries are known, its data is separate, and the way to communicate with it is defined. Splitting it off remains a decision you make when the need arises, not a bet you start paying for today.
Start with clear boundaries inside the system, and split off a service when you find a practical reason to, not before.
A quick decision guide
- Do you have more than one team that needs to release its changes independently of the others? If not, a single system is often the better fit.
- Does a specific part need to scale separately from the rest, and has that need actually appeared, rather than being assumed?
- Are the business boundaries between the parts stable and understood, or are they still changing with every stage?
- Does your team have experience running, monitoring, and troubleshooting distributed systems?
- Are you willing to accept higher running and monitoring costs in exchange for independent parts?
If most of the answers are no, start with a single system with clear modules, and ask the question again when circumstances change. If they’re yes, first split off the part that most justifies it, not the whole system at once.
And when the time to split comes, it doesn’t happen all at once. One module is split off into a separate service, its behavior is watched in production, and then you decide whether to split off others or stop there. A single system with one or two separate services may be the right shape for your situation, with no need to split up the rest.
A sound architectural decision starts from the nature of the business, the size of the team, and the growth plan, not from buzzwords. If you’re evaluating the architecture of a new system or thinking about splitting up an existing one, you can discuss your situation with the ITS team before committing to either option.
Related serviceBackend services and microservices
