Architecture Patterns

Lesson 1 of 5

Monolith vs Microservices

"Any organization that designs a system will produce a design whose structure is a copy of the organization's communication structure." — Melvin Conway

There is no more over-sold idea in modern software than microservices. Conference talks, vendor blogs, and résumés all whisper the same promise: break your app into dozens of tiny services and you will scale like Netflix. What they leave out is the bill. Splitting one program into many turns every method call into a network call, every transaction into a distributed problem, and every deploy into a choreography. This chapter is the honest ledger — what a monolith buys you, what microservices buy you, and the hard truth about when the second is worth its very real cost.

The question this chapter answers

Should your system be one deployable unit or many independent services — and how do you tell the difference between a scaling problem microservices actually solve and one they just make more expensive?

Core Concepts

The monolith: one deployable unit

A monolith is a single application containing all your features — auth, billing, catalog, notifications — compiled and deployed as one unit, usually talking to one database. This is not a slur. It is how almost every successful company started, and how most should.

Rendering diagram…

The strengths are exactly the things junior teams underrate. One codebase you can open in one editor and reason about end to end. In-process calls — no network, so no latency, no partial failure, and a single database transaction can wrap a change across billing and orders atomically. One thing to deploy, test, and debug: a stack trace runs from the HTTP handler to the SQL call without crossing a wire. For a small team and an early product, this simplicity is not a compromise — it is a superpower.

The weaknesses appear at scale, and they are largely organizational. When fifty engineers across six teams share one codebase, they contend over the same files, the same release train, the same deploy. You must ship everything together — a one-line fix waits for the whole app to be tested and released. You cannot scale the parts independently: if only the image-processing path is CPU-hungry, you still have to run more copies of the entire app to get more of it. One memory leak or infinite loop can take the whole thing down. And you are locked into one tech stack for everything.

The engineer's notebook

Before you reach for microservices, reach for the middle ground:

• The modular monolith — one deployable unit, but with strict internal module boundaries: billing may only call orders through a defined interface, never its tables. You get clean seams and a single deploy.
• It keeps in-process speed and real transactions while making a future split cheap — the modules become the service boundaries.
• Most teams that "need microservices" actually needed a well-structured monolith. This is the most underrated architecture in the industry.

Microservices: many small, independent services

Microservices decompose the system into many small services, each independently deployable, each owning its own data, each communicating over the network — usually HTTP/gRPC for synchronous calls or a message broker for asynchronous events.

Rendering diagram…

The strengths are real and specific. Teams deploy independently — the orders team ships ten times a day without asking anyone. You scale independently — run 40 copies of the image service and 3 of billing, sized to their load, not the app's. Each service can use the right tech — Go for the hot path, Python for the ML service. And you get fault isolation: if notifications crash, orders keep flowing (if you designed the boundaries well).

Now the honest bill — and it is heavy. You have just opted into distributed systems — every hard thing from Part V arrives at once. A local method call that never failed becomes a network call that adds latency and can time out, retry, or vanish. You lose cross-service transactions: a monolith wraps "charge card + reserve stock" in one commit; across services you need a saga — a sequence of local transactions with compensating undo steps, and eventual (not immediate) consistency. Operational overhead explodes: you now need centralized logging, distributed tracing, metrics, service discovery, health checks, and a deployment pipeline per service. Testing an end-to-end flow means standing up many services. And the hardest part of all — getting the boundaries right. Split wrong and every feature touches five services at once.

Everyday analogy

A monolith is a house where every room is down the hall — you walk to the kitchen in seconds and carry three plates at once without dropping any (one transaction). Microservices are a neighborhood of separate houses: each family owns and renovates theirs freely (independent deploy), but now dinner means driving between houses (network latency), the food might not arrive (partial failure), and there is no single moment where every dish lands on every table at once (eventual consistency). Separate houses are wonderful — once you actually have enough families to fill a neighborhood.

The comparison

Dimension Monolith Microservices
Initial complexity Low — one app, one repo, one deploy High — distributed system from day one
Deployment All at once; one pipeline Per service; many pipelines, orchestration
Scaling Whole app together (coarse) Per service, independently (fine-grained)
Team fit Small teams / one team Many teams needing autonomy
Data & transactions One DB, easy ACID transactions DB-per-service; no distributed txn → sagas, eventual consistency
Failure isolation Weak — one bug can down all Strong (if boundaries are good)
Tech flexibility One stack Right tool per service
Operational cost Low — one thing to run & watch High — tracing, discovery, per-service ops
Debugging One stack trace, end to end Across service logs; hard
Best when Early product, small team, unproven domain Many teams, proven domain, org-scale pain

The key lesson: start with a monolith

Say it plainly: start with a monolith. Microservices primarily solve an organizational scaling problem — many teams that can no longer share one codebase and one release train — far more than a technical one. Most technical scaling (more traffic, more data) is better solved first with caching, read replicas, a bigger box, and background workers, all of which a monolith supports fine.

This is where Conway's Law (our opening quote) earns its keep: your architecture will end up mirroring your org's communication structure whether you plan it or not. Microservices work at Amazon and Netflix because those companies have hundreds of small autonomous teams — the architecture matches the org. A ten-person startup has no such structure to mirror, so imposing microservices creates coordination overhead the org isn't built to absorb.

History changed here

Amazon's early-2000s "two-pizza teams" and its famous internal mandate — every team exposes its data only through service interfaces, no shared databases — is the origin story microservices advocates cite. But the lesson usually gets truncated. Amazon adopted services because it had grown into thousands of engineers strangling on a shared codebase; the architecture solved an organizational crisis at massive scale. Netflix did the same after a 2008 database corruption took down DVD shipping for days. Both were escaping pain they had actually earned. Copying their solution without their problem is cargo-culting the endpoint of a decade-long journey.

Real-world example — chika.ng Academy

chika.ng is a monolith: one Next.js application talking to one MySQL database through Drizzle, on a single host. Auth, the Academy, the Library, enrollment, and the admin dashboard all live in one deployable unit. This is exactly right for a solo/small operation — a change ships in one deploy, a bug shows one stack trace, and a certificate write plus an enrollment update happen in one transaction. Splitting this into an "auth service," a "library service," and a "billing service" would add network hops, distributed-transaction headaches, and a fleet of pipelines to babysit — pure overhead bought with money and complexity, in exchange for autonomy that a one-person team does not need. The right architecture is the one that matches your scale, not the one on the conference slide.

Thought experiment

You split your app into eight microservices, but rendering the home page still requires calling all eight in sequence, they share concepts so a feature change touches five of them at once, and you can only deploy them together because they'd break otherwise. What have you built? A distributed monolith — the coupling of a monolith plus the network cost of microservices: the single worst outcome, and the most common one. The tell is simple: if you can't deploy one service without deploying the others, you never had microservices — you had a monolith with extra latency and a bigger AWS bill.

Common Mistakes

  • Starting with microservices. Before product-market fit you don't yet know your domain boundaries — and boundaries are the one thing microservices demand you get right. Guess wrong early and every service split becomes a migration.
  • Building a distributed monolith. Services that must be deployed together, or that reach into each other's databases, give you all the cost of distribution and none of the independence.
  • Splitting by technical layer, not domain. A "database service," a "logic service," and a "UI service" means every feature crosses all three. Split by business capability, not by tier.
  • Ignoring the operational tax. Microservices need tracing, centralized logs, service discovery, and per-service CI/CD before they pay off. Teams that skip this fly blind across a dozen processes.
  • Confusing organizational scale with traffic scale. High traffic on a small team is a caching/replica problem, not a microservices problem. Microservices are for when the team can't share a codebase anymore.
  • Cargo-culting Netflix. "It works for them" ignores that they have thousands of engineers and the platform teams to run it. Copy the reasoning, not the diagram.

Interview Corner

Interview Corner — the same idea at three levels. Answer yours; recognise the one above it.
Junior
"What's the difference between a monolith and microservices?"
Model answer — "A monolith is one deployable application containing all features, usually with one database — simple to build, test, and deploy. Microservices split the system into many small services that deploy independently and own their own data, communicating over the network. Microservices trade simplicity for independence."
Follow-up they'll throw: "Which would you start a new project with?" → A monolith — it's simpler and you don't yet know your boundaries. Say that confidently; it's the senior-approved answer.
Intermediate
"When would you actually move from a monolith to microservices, and what do you give up?"
Model answer — "When the pain is organizational — multiple teams contending over one codebase and one release train, or one part needing to scale very differently from the rest. You give up ACID transactions across features (you now need sagas and eventual consistency), you take on network latency and partial failure, and you pay a big operational tax: tracing, service discovery, per-service pipelines. I'd first try a modular monolith — clean internal boundaries — and only extract services when a specific one earns it."
Follow-up: "How do you decide where to draw the service boundaries?" → By business domain / bounded context (DDD), each service owning its data — never by technical layer.
Senior
"Our monolith is slowing the org down — 60 engineers, one release train, deploys are scary. Walk me through the migration."
Model answer — "First I'd confirm the problem is organizational, not just performance — if it's traffic, caching and replicas are cheaper. Given team contention, I'd use the strangler-fig pattern: put a facade in front of the monolith, then peel off one bounded context at a time — start with something loosely coupled, give it its own database, route its traffic to the new service, and delete the old code once it's proven. I'd invest in observability (distributed tracing, centralized logs) and a per-service pipeline before the second extraction. For cross-service consistency I'd use sagas with compensating actions and design for eventual consistency. Crucially, I'd align services to teams — Conway's Law means the boundaries will mirror the org anyway, so I'd make that deliberate."
Senior insight: the failure mode to name is the distributed monolith — if extracted services still deploy together or share data, stop and fix the boundary before continuing. Migrate incrementally; never rewrite from scratch.
Company lens — how the same topic gets asked
micro1Live and conversational — reason out loud. State the trade-off early ("I'd start with a monolith because...") and justify as you go; the AI interviewer rewards hearing your reasoning, not a memorized verdict.
GoogleWants rigor and scale: quantify the operational cost, discuss consistency models (sagas, eventual consistency) precisely, and defend where you'd draw boundaries and why.
MetaPragmatic, product-scale: expect "you don't need microservices for this — prove you know when NOT to." Show judgment about the modular monolith middle ground.
AmazonOperational excellence and cost: two-pizza teams, service ownership, the ops tax in dollars, and how you'd migrate safely (strangler-fig) without a big-bang rewrite. Ties directly to Leadership Principles.
Hands-on exercise
  1. Sketch the diagram: take an e-commerce app and draw it twice — once as a monolith (one box, one DB) and once as microservices (gateway + auth, catalog, orders, payments, each with its own DB). Mark every place a network call replaces an in-process call.
  2. Say the trade-off out loud (as in a micro1 screen): "I'd start this project as a monolith because ___, and I'd only split when ___." Fill both blanks in one breath.
  3. Estimate the cost: your monolith runs on 3 servers. You split into 6 services, each needing 2 instances for redundancy plus a message broker and a tracing stack. Roughly how many moving pieces must you now run and monitor — and who watches them at 3am?
  4. Pick one feature of your current project and describe how you'd extract it using the strangler-fig pattern, step by step, without a big-bang rewrite.

Chapter Summary

  • A monolith is one deployable unit with one database — simple to build, test, deploy, and debug, with fast in-process calls and real transactions. Ideal for small teams and early products.
  • Microservices are many independently deployable services owning their own data over the network — buying independent deploy/scale/tech and fault isolation at the cost of distributed-systems complexity.
  • The costs are real and heavy: network latency and partial failure, no cross-service transactions (sagas + eventual consistency), and a large operational tax (tracing, discovery, per-service pipelines).
  • Start with a monolith. Microservices solve organizational scaling (many teams) more than technical scaling; adopt them only when team/codebase pain justifies the cost.
  • Conway's Law: architecture mirrors org structure — make that deliberate. The modular monolith is the underrated middle ground; the distributed monolith is the worst of both.
  • If you split: by business domain / bounded context (DDD), not technical layer; database-per-service; migrate gradually with the strangler-fig pattern — never a big-bang rewrite.
Narrative bridge

Splitting into services forces one question to the surface: how do independent services talk without becoming tightly coupled again? Synchronous request/response chains recreate the distributed monolith — one slow service stalls them all. The escape is to let services communicate through events: fire-and-forget messages a service publishes without knowing or waiting on who consumes them. That's the subject of the next chapter — Event-Driven Architecture — where decoupling, asynchrony, and eventual consistency stop being costs to endure and become the design itself.

Editorial reflection — microservices are the clearest case in our field of an advanced solution mistaken for a best practice. They are not a rite of passage or a sign of seriousness; they are a specific, expensive answer to a specific, organizational problem most teams do not yet have. The engineers who impress me are not the ones who can wire up forty services — it's the ones who can look at a whining monolith, correctly diagnose whether the ache is technical or organizational, and have the confidence to say "not yet." Simplicity is not what you build before you know better. It is what you protect because you do.

Q&A · 0

Enrol to ask questions and join the discussion.

No questions yet — be the first to ask.