You’ll get a plain explanation of how microservices architecture splits an application into independently deployable services, what that split costs in reliability and team effort, and a practical test for deciding whether your project should do it. Most articles on the subject list benefits and stop there. This one adds the availability math and the failure pattern that catches teams a year after they migrate. Along the way you’ll see the core components, the communication options, and a six-step path out of a monolith. By the end, you’ll be able to judge whether your own system is ready for services, and what to do first if it is.
The Short Answer
Microservices architecture builds one application from many small services, each owning a business capability and its own data, deployed separately and talking over APIs. It buys independent scaling and faster releases for large teams, but costs network failures, harder debugging, and operational overhead that small teams often can’t justify.
What a Microservices Architecture Is Made Of
The core idea is an application split into independently deployable services that communicate through APIs, instead of one codebase shipped as a single unit. Each service is organized around a business capability such as billing, search, or shipping, not around a technical layer like “all the database code.” Every service can be developed, deployed, and scaled without affecting the others, so the team that owns billing can release on a Tuesday without waiting for the team that owns recommendations.
Microsoft’s architecture guidance on the microservices style describes the same shape. Each service is managed as its own codebase, small enough for one team to maintain. That team-sized boundary matters more than any line-count rule.
A working system needs more than the services themselves. The usual supporting pieces look like this.
- An API gateway, which acts as the single entry point, routes client requests, and handles shared concerns like authentication.
- Service discovery, so services can find each other as instances start, stop, and move.
- A separate data store per service, which is where polyglot persistence comes from, with one service on SQL and another on a document database.
- Orchestration, usually Kubernetes or a managed equivalent, to start, restart, and scale containers.
- Observability, meaning centralized logs, metrics, and distributed tracing.
Observability is the item teams underbudget. In a single process, a stack trace tells you what broke. With thirty services, one user click can touch eight of them, and unless a trace ID travels with the request through every hop, you’re guessing.
How Services Talk to Each Other
Communication comes in two flavors, and picking between them is one of the most consequential design choices you’ll make. Synchronous calls, usually REST or gRPC, make the caller wait for an answer. Asynchronous messaging, through a broker like Kafka or RabbitMQ, lets a service publish an event and move on while other services react on their own schedule.
My position is to default to asynchronous for anything the user doesn’t need an answer to right now. Take an online order. Charging the card has to be synchronous because the customer needs to know whether it worked. The confirmation email, the inventory update, and the analytics record can all be events, and none of them should be able to slow down or break the checkout.
Choreographed events do have a cost, because the flow of a business process ends up spread across many services and no single file shows it end to end. Teams handle that with good tracing and with documented event contracts. It’s a real tradeoff, but it’s usually a better one than a long chain of blocking calls, for reasons the next section makes concrete.
The Availability Math Most Diagrams Leave Out
Suppose every service in your system hits 99.9 percent availability, which sounds excellent and works out to about 8.8 hours of downtime a year for a single service. Now chain ten of them in a synchronous request path, so the user’s request only succeeds if all ten respond. Multiply 0.999 by itself ten times and you land near 99.0 percent, which is roughly 87 hours of failure a year.
Twenty chained services drop you to about 98 percent, close to 174 hours. These figures assume failures are independent and every call is required, so real systems will vary, but the direction is reliable. Every synchronous dependency you add makes the whole path a little less available than its weakest member.
That’s why the standard defenses exist. Timeouts stop one slow service from freezing its callers, circuit breakers stop repeated calls to something that’s already down, and caching removes calls entirely. Good designs also let features fail individually, and applications built on services can degrade functionality instead of crashing entirely, but only if you deliberately write that fallback behavior.
Where People Go Wrong With Service Size
The word “micro” pushes people into thinking the goal is tiny services, and that more services means a better architecture. The confusion is understandable, because there’s no industry consensus on the exact properties of microservices and no official definition, so the name ends up doing the explaining. Teams then slice a codebase by class or function and end up with dozens of fragments that can’t do anything alone.
Boundaries should follow business capabilities and team ownership, and the size that results is whatever that capability needs. The failure mode has a name, the distributed monolith. Services that must be deployed together, that share a database, or that call each other in long chains carry all the coupling of the old monolith plus every network failure on top.
A quick test catches it early. Ask whether you can deploy one service without coordinating with any other team, and whether you can change its data schema without breaking someone else. One very common tell is a single database table written to by two different services, and if you find one, your boundary is in the wrong place.
When a Monolith Is the Better Call
For a team under roughly ten engineers, working on one product whose domain is still changing, I’d start with a well-organized modular monolith. That number is a judgment call and not a law, since a disciplined team of fifteen can run a monolith happily and a chaotic team of six can drown in services. Still, the operational load of gateways, orchestration, and tracing lands on the same few people who are supposed to be shipping features.
The pattern authors agree that the monolithic architecture is not an anti-pattern. Big names took the microservices route only after growth forced their hand, and most large-scale sites, including Netflix, Amazon, and eBay, evolved from a monolith instead of starting with services. They earned the complexity with real scaling pain first.
Splitting starts to pay off when teams block each other’s releases, when one component needs to scale very differently from the rest, or when a part of the system needs a different technology. If you’d like to see how similar cost-versus-benefit calls get worked through elsewhere, there are more everyday tech tradeoffs explained in plain language worth a look.
Moving From a Monolith Step by Step
Migrations fail when they’re treated as rewrites. The safer route is gradual, pulling pieces out one at a time while the old system keeps running, and it goes roughly like this.
- Map the monolith by listing its modules, who owns each one, which tables each touches, and how often each changes.
- Enforce boundaries inside the existing codebase first, so modules only talk through defined interfaces.
- Extract one low-risk edge capability, such as notifications or image processing, that has few dependencies.
- Define and version the API contract before moving any code, so callers and the new service agree on the shape.
- Put service discovery, a gateway, and distributed tracing in place before you extract a second service.
- Split the data last, giving each service its own store and syncing changes through events, because shared data is the hardest thing to untangle.
Notice that step two often reveals the answer. If you can’t draw clean boundaries inside one codebase, network calls won’t create them, and some teams stop there with a modular monolith and consider the job done well.
Your Next Move
The takeaway on microservices architecture is that it’s an organizational tool first and a technical one second. It pays off when independent teams need to ship independently, and it hurts when a small team takes on network failures and tracing without needing the scale. Before splitting anything, draw your current modules on a whiteboard and mark which ones share tables. If you can’t separate the data cleanly on paper, you can’t separate it in production either, so fix that first.
FAQ
How small should a microservice be?
Small enough for one team to own and understand fully, and large enough to deliver a complete business capability. Line counts don’t matter. If two services can’t work without each other, they’re probably one service.
Can microservices share a database?
Technically yes, but it removes the independence that makes the style worthwhile. Schema changes then need cross-team coordination, and you’ve built a distributed monolith. Each service should own its data and expose it through an API or events.
Do microservices require Kubernetes?
No. Kubernetes is the common choice for orchestration, but managed container services, serverless functions, or even a few virtual machines can run services. You do need some automated way to deploy, restart, and scale them.
Is microservices architecture the same as SOA?
They’re related but not identical. Service-oriented architecture usually means larger, enterprise-wide services often connected through a central bus, while microservices favor smaller, independently deployed services with lightweight communication and decentralized data.
How many developers do you need for microservices?
There’s no fixed threshold, but the benefits show up when several teams need to release independently. With fewer than about ten engineers on one product, the operational cost usually outweighs the gains.