Skip to content

Microservices

Why Does the Microservices Architecture Exist?

As a monolith and its engineering team both grow large, two specific pressures become genuinely limiting, not just theoretically inconvenient: the inability to scale one bottlenecked piece of the system independently of the rest (from the Monolith chapter), and the organizational friction of many teams all needing to coordinate deployments, releases, and changes within one shared codebase. Microservices exist to address both directly — splitting a system into independently deployable, independently scalable services, each owned by a smaller team, communicating over the network rather than through in-process function calls.

Monolith:       one deployable unit, one team's worth of coordination
                (or many teams FORCED to coordinate through it)

Microservices:  many independently deployable services, each owned
                by a smaller team, each scalable on its own, each
                shippable on its own schedule

The Real Benefits

Independent scaling:     scale JUST the checkout service under load,
                          not the entire system — a direct fix for
                          the Monolith chapter's all-or-nothing
                          scaling problem

Independent deployment:   one team ships its own service without
                          waiting for, or coordinating a release
                          with, every other team — a genuine
                          organizational velocity benefit once a
                          company has grown to many teams

Fault isolation:           one service crashing doesn't necessarily
                           take down the whole system, unlike a
                           monolith's single shared process and
                           shared fate

Technology flexibility:     each service can use whatever language or
                            framework genuinely fits its own specific
                            problem best, rather than the whole
                            system being locked into one technology
                            choice

The Real Costs — Stated Honestly

This is the part that separates a genuinely useful discussion of microservices from a one-sided sales pitch, and it's worth being precise and honest about, since every one of these costs is real and directly connects to entire sections of this handbook.

Network calls where function calls used to be:  latency, and
    genuine partial failure, replace what used to be an instant,
    always-succeeds function call — the entire Distributed
    Systems section exists largely because of exactly this shift

Operational complexity becomes REQUIRED, not optional:  service
    discovery, load balancing, distributed tracing all become
    necessary just to operate the system at all, not optional
    nice-to-haves

Data consistency across services becomes genuinely hard:  no
    more single-database ACID transactions spanning the whole
    operation — this is exactly why the Saga Pattern and
    Two-Phase Commit chapters exist

Testing and debugging get genuinely harder:  reproducing and
    diagnosing an issue that spans multiple services requires
    the entire Distributed Tracing chapter's tooling, rather
    than stepping through one process in a debugger

None of this means microservices are a bad choice — it means the decision to adopt them needs to honestly weigh these real, unavoidable costs against the genuine benefits, for the specific system and team in question, rather than assuming the benefits are free.


Conway's Law

A genuinely important, frequently cited organizational insight, worth understanding precisely: organizations design systems that mirror their own communication structure.

If three teams communicate mostly within themselves, and only
loosely with each other

↓

The system they build will naturally end up structured as
THREE loosely-coupled components, mirroring that communication
pattern — whether or not anyone explicitly designed it that way

Microservice boundaries are frequently drawn deliberately to mirror team boundaries — specifically so each team can own and independently ship its own service, minimizing the cross-team coordination that slows down a large, shared monolith. This is a genuinely two-way relationship worth understanding: sometimes teams are deliberately organized around desired service boundaries (an "inverse Conway maneuver"), and sometimes services end up shaped by whatever team structure already existed, for better or worse.


The Distributed Monolith — Given Its Full Treatment

Previewed in the Monolith chapter, and worth stating precisely here: this is the most common, most expensive way a microservices adoption fails in practice.

Services that are technically deployed SEPARATELY

↓

But are STILL tightly coupled underneath:

- A SHARED database across multiple services (any schema change
  in one service risks breaking others silently)
- Synchronous call chains where Service A must wait on B, which
  must wait on C, ALL succeeding together for the original request
  to succeed at all
- Deploys that must happen in a specific, coordinated LOCKSTEP
  order across services, because of hidden dependencies
Result:  you pay EVERY real cost of microservices (network calls,
         latency, operational complexity, harder debugging)

         while gaining NONE of the actual benefits (you still
         CAN'T deploy or scale services independently, because
         of the hidden coupling underneath)

This is worth naming precisely and confidently in an interview — it's a genuinely common, expensive real-world failure mode, and recognizing it (rather than assuming "we have separate services, therefore we have microservices' benefits") is a strong signal of real understanding.


When NOT to Adopt Microservices

A small team:                the coordination overhead of many
                              separately-deployed services isn't
                              worth it when there's no cross-team
                              deployment friction to solve in the
                              first place

A system that doesn't need
independent scaling of
different pieces:              if nothing about the system's load
                                pattern actually requires scaling
                                one piece independently of others,
                                microservices' main technical
                                benefit doesn't apply

An early-stage product still
finding its shape:              premature service boundaries, drawn
                                 before the actual domain and its
                                 natural boundaries are well
                                 understood, are expensive to
                                 redraw later — a monolith's internal
                                 module boundaries are comparatively
                                 cheap to refactor as understanding
                                 improves, while genuinely splitting
                                 and re-merging separate SERVICES is
                                 a much bigger, riskier undertaking

This directly echoes the Horizontal Scaling chapter's premature-complexity warning, applied specifically to architectural choice — reaching for microservices before an actual, concrete need exists means paying real, ongoing coordination costs for a problem the system doesn't have yet.


Real-World Examples

Netflix

One of the most cited, most influential real-world microservices case studies — a genuine, large-scale need for independent scaling (wildly different load patterns across different parts of their system) and independent team ownership drove a deliberate, well-documented microservices adoption, alongside significant investment in the supporting infrastructure (circuit breakers, service discovery, distributed tracing) this handbook's Distributed Systems and Observability sections cover in depth.


Amazon

Famously restructured around independently-owned, independently-deployable services specifically to remove cross-team coordination bottlenecks at massive organizational scale — a direct, real-world instance of Conway's Law being deliberately leveraged (the "inverse Conway maneuver") rather than just observed after the fact.


The Distributed Monolith as a Real, Common Failure

Widely documented across the industry as one of the most common ways a microservices migration goes wrong — teams that split a system's deployment without actually addressing its underlying coupling (a shared database, synchronous cross-service dependencies) end up worse off than before, having paid real costs for benefits they never actually received.


Common Interview Questions

What are the real trade-offs of microservices — not just the benefits?

Independent scaling, independent deployment, fault isolation, and technology flexibility are the real benefits — but they come with real costs: network calls replacing function calls (latency, genuine partial failure), operational complexity (service discovery, distributed tracing) becoming mandatory rather than optional, much harder cross-service data consistency (no more single-database transactions), and genuinely harder testing and debugging across multiple services.


What is Conway's Law, and how does it relate to microservice boundaries?

The observation that organizations design systems mirroring their own communication structure — teams that communicate mostly within themselves and loosely with others will naturally build a system structured the same way. Microservice boundaries are often deliberately drawn to mirror team boundaries specifically so each team can own and ship its own service independently, minimizing cross-team coordination.


What is a distributed monolith, and why is it worse than a real monolith?

Services that are technically deployed separately but remain tightly coupled underneath — a shared database, synchronous call chains requiring multiple services to succeed together, deploys that must happen in lockstep. This pays every real cost of microservices (network calls, operational complexity) while gaining none of the actual benefits (you still can't scale or deploy independently), making it genuinely worse than either a clean monolith or well-executed microservices.


When would you NOT recommend microservices to a team?

A small team without significant cross-team deployment friction, a system with no actual need to scale different pieces independently, or an early-stage product still discovering its natural domain boundaries — in all these cases, microservices' real, ongoing coordination costs aren't justified by a concrete, existing need, and a monolith (or modular monolith) is the more pragmatic choice.


How would you decide where to draw microservice boundaries?

Around genuine business capabilities and domain boundaries, not technical layers (a "database service" or a "business logic service" are both usually wrong ways to split a system) — this is exactly the problem Domain-Driven Design's bounded contexts, covered in the next chapter, exist to solve precisely.


Common Mistakes

❌ Adopting microservices for a small team or early-stage product without an actual need for independent scaling or deployment.

Pays real, ongoing coordination costs prematurely for a scaling or organizational problem the team may not have yet — the same premature-complexity mistake as reaching for horizontal scaling too early.


❌ Ending up with a distributed monolith by splitting deployment without actually decoupling the database, call patterns, or release schedule.

The single most common, most expensive way a microservices adoption fails — paying every real cost while gaining none of the actual benefits.


❌ Drawing service boundaries around technical layers instead of business capabilities.

A "database service" or "authentication service" split purely along technical lines, rather than around a genuine business domain boundary, tends to produce services that are constantly, tightly coupled to each other anyway — exactly the problem Domain-Driven Design's bounded contexts address directly.


Key Takeaways

  • Microservices split a system into independently deployable, independently scalable services, directly addressing a monolith's all-or-nothing scaling and cross-team coordination limitations as both the system and team grow large.
  • The real costs — network calls replacing function calls, mandatory operational complexity, harder cross-service data consistency, and genuinely harder debugging — are just as real as the benefits, and need to be honestly weighed, not assumed to be free.
  • Conway's Law explains why microservice boundaries often mirror team boundaries — organizations tend to build systems that reflect their own communication structure, sometimes deliberately leveraged (the inverse Conway maneuver).
  • A distributed monolith — services split without actually decoupling the database, call patterns, or deployment schedule — is the most common, most expensive way a microservices adoption fails, paying every real cost while gaining none of the actual benefits.
  • Microservices aren't the right choice for every team or system — a small team, a system without an actual independent-scaling need, or an early-stage product still finding its domain boundaries are all cases where a monolith (or modular monolith) remains the more pragmatic choice.