Architecture and Scale

Microservices Architecture

Microservices solve real problems and create new ones. Interviewers want to know you understand both, not that you cargo-cult the pattern.


The Concept Explained

Microservices structure an application as a set of independently deployable services, each owning its data and communicating over a network.

The word doing the work in that definition is independently deployable. That is the property everything else follows from, and it is the only one that reliably distinguishes microservices from a monolith with good modules. If two services must be released together, you have a distributed monolith: all the costs of the network and none of the independence.

Owning its data is the other load-bearing clause. A service that shares tables with another service cannot be deployed independently, because a schema change affects both. Private data per service is what makes the deployment independence real rather than nominal.

KEY CONCEPT

Microservices are primarily an organizational technology. The main thing they buy is the ability for teams to ship without coordinating, which is a constraint that scales with headcount rather than traffic. Every technical property, targeted scaling, technology diversity, contained blast radius, is real but secondary, and each is achievable by other means at lower cost.


How It Works

What They Genuinely Solve

Release independence. A team deploys when its work is ready, without waiting for a shared release train or being blocked by another team's failing test. In an organization with many teams this is transformative, and it is the reason the pattern spread.

Targeted scaling. A component needing far more capacity than the rest can be scaled alone rather than replicating the entire application. Genuine, though the saving is often smaller than expected, since the dominant cost is usually one component that would have needed scaling anyway.

Contained blast radius. A crash or memory leak affects one service. This only holds if the system degrades gracefully when a service is unavailable, which is design work rather than an automatic property.

Technology flexibility. A workload suited to a different runtime can have one. Useful occasionally, and frequently overstated: most organizations benefit more from consistency than from per-service language choice.

Clear ownership. Each service has a team accountable for it, on call for it, and free to evolve it. That accountability is itself worth something.

What They Introduce

This half is what interviewers listen for, and the costs are specific rather than general.

Every call can fail, and failure is ambiguous. In a monolith a function call returns or throws. Across a network a call can also time out, and a timeout does not tell you whether the work happened. Every remote call now needs timeouts, retries, and idempotency, and every retry mechanism without idempotency is a duplicate-execution mechanism.

Availability multiplies down. If a request passes through services in sequence and each is independently available 99.9% of the time, five in series gives 99.5%, roughly 44 hours of downtime a year. Ten gives 99.0%, about 87 hours. This surprises people, and it is why reducing synchronous dependencies is one of the highest-value moves in a service architecture.

Services in a synchronous chainEach at 99.9%Downtime per year
199.90%8.8 hours
399.70%26.3 hours
599.50%43.7 hours
1099.00%87.2 hours

Transactions become sagas. One database gave you atomic commits across everything. Split data means an operation spanning services needs a sequence of local transactions with compensating actions, no isolation, and visible intermediate states. This is a large permanent cost and it is the one most often underestimated.

Debugging requires new infrastructure. A single stack trace becomes correlated traces across services. Distributed tracing, log aggregation, and correlation identifiers are not optional extras, they are the minimum to operate the system at all.

Operational surface multiplies. Every service needs a pipeline, monitoring, alerting, on-call, dependency updates, and security patching. Forty services means forty of each unless you have built a platform, and building that platform is itself a substantial investment.

What a Single Function Call Becomes After Decomposition

Click each step to explore

WARNING

The most common failure is the distributed monolith: services split apart but still deployed together, still sharing a database, still requiring coordinated releases. This is the worst of both models, paying the full network and operational cost while retaining every coupling that made the monolith painful. The test is simple: can you deploy any one service to production, alone, right now, without coordinating with another team? If not, the split has not delivered its main benefit.


System Design Implications

When not to use them is the sharpest part of the interview question, and there are several clear answers.

When the team is small. Microservices trade engineering complexity for organizational independence. A team of five has no coordination problem to solve and will simply absorb the complexity for nothing.

When domain boundaries are still uncertain. A wrong boundary inside a monolith is a refactor. Across services it is a migration with an API version and a dual-running period. Splitting early locks in boundaries you do not yet understand.

When operations are not ready. Without deployment automation, centralized logging, distributed tracing, and service discovery, running many services is materially harder than running one. The platform investment is a precondition rather than a follow-up.

When the domain is deeply transactional. If most operations span many entities and need atomicity, splitting converts every one into a saga. Some domains simply resist decomposition, and recognizing that is a strength.

Design guidance when you do adopt them. Draw boundaries around business capabilities rather than technical layers, since a service per layer means every feature touches every service. Give each service its own data. Prefer asynchronous communication where the operation permits, because each synchronous dependency removed multiplies back into your availability. And invest in the platform before the service count grows, not after.

PRO TIP

A strong answer gives the availability maths unprompted. Five services at 99.9% each in a synchronous chain is 99.5%, about 44 hours a year, which is worse than any individual component. That single number reframes the conversation from "microservices scale better" to "microservices trade availability and complexity for organizational independence," which is the accurate framing.


Tradeoffs and Decision Framework

DimensionMonolithMicroservices
Deploy independenceNoneThe main benefit
Internal call costNanosecondsSub-millisecond, can fail
Cross-cutting transactionsACIDSaga with compensation
Availability of a chainOne componentProduct of all in the path
DebuggingOne stack traceDistributed tracing required
ScalingUniformTargeted
Operational surfaceOneOne per service
Right forSmall teams, uncertain domainsMany teams, stable boundaries

The framework in four questions. Is the pain deployment coordination between teams, which is the problem microservices actually solve? Are the domain boundaries stable enough to commit to? Does the operational platform exist to run many services? And can the domain tolerate losing cross-service transactions?

Four yeses is a sound case. Fewer than that and the honest recommendation is a modular monolith, extracting individual services where a specific justification exists. That answer demonstrates more seniority in an interview than enthusiasm for decomposition does.


Common Mistakes

Adopting them for code quality. Poor structure follows you across the network and gains latency on the way.

The distributed monolith. Services that must be deployed together have the costs and none of the independence.

Sharing a database between services. The schema recouples every deploy, which removes the only benefit that mattered.

Ignoring the availability multiplication. Long synchronous chains are less available than any of their parts, and this is arithmetic rather than an implementation flaw.

Splitting by technical layer. A service per layer means every feature change touches every service, maximizing coordination instead of removing it.

Retries without idempotency. A timeout does not tell you whether the work ran, so every retry is a potential duplicate execution.

Building the platform after the service count grows. Tracing, aggregation, discovery, and deployment automation are preconditions, and retrofitting them across forty services is far harder than establishing them across three.

Assuming graceful degradation is automatic. Blast radius is contained only if callers have defined behaviour when a dependency is unavailable. Otherwise one service failing still fails the request.


INTERVIEW QUESTION

What problems do microservices solve, and what new problems do they introduce? When would you NOT use them?