System Design Space
Knowledge graphSettings

Updated: June 24, 2026 at 7:41 PM

Modular Monoliths and Other Facepalms (short summary)

medium

Why a modular monolith returns teams to engineering discipline: information hiding, dependency rules, independent deployability, and the cost of distribution.

A modular monolith story matters because it gives teams permission not to rush into microservices just because the idea sounds modern.

In real design work, the chapter shows how module boundaries, dependency discipline, and an intentional path toward services can improve control without immediate operational overhead.

In interviews and engineering discussions, it helps talk about premature decomposition, team overload, and the false sense of maturity often hidden behind the word microservices.

Practical value of this chapter

Design in practice

Separate real domain constraints from fashion-driven “microservices first” decisions.

Decision quality

Use modular monolith intentionally when team scale and load do not justify service split yet.

Interview articulation

Demonstrate maturity: choose architecture shape by context, not trend pressure.

Failure framing

Avoid premature decomposition and operational overload of teams.

About the talk

Modular Monoliths and Other Facepalms

A walkthrough of why a modular monolith is not a new style, but a return to engineering discipline: information hiding, module boundaries, and dependencies you can verify in the build instead of just promising on a slide.

Talk

Modular Monoliths and Other Facepalms

Kevlin Henney's NDC London talk about modularity, boundaries, and the cost of distributed architecture.

Main idea

The problem is usually the boundary, not the deployment model

Microservices do not fix poor decomposition — they move it onto the network and make every mistake more expensive to operate.

A team hits a monolith that is hard to change and reaches for microservices as the cure. Here the modular monolith is not a compromise between “old” and “new” — it is a disciplined form that solves the same pain more cheaply. Henney's point is about order of operations: information hiding, module boundaries, and explicit dependency rules need to be in place before a team chooses independently deployable services. Skip that step and you get a distributed monolith: the same coupling, now over the network.

Source

Microservices

Definition of microservices and the basic trade-offs behind independent deployability.

Open article

Main points of the talk

A modular monolith is a return to engineering basics

The talk strips away the novelty: modularity, information hiding, and componentization existed long before microservices became fashionable — what changed was the packaging, not the principle.

Microservices were often used as forced partitioning

When a monolith has lost healthy boundaries, splitting it across the network feels like a fix. But a boundary the team never drew in code will not appear just because the call became remote.

The false choice is monolith versus microservices

The monolith-versus-microservices argument is a distraction: architecture is held together by the quality of boundaries, contracts, and dependencies, not by the number of running processes.

Classic decomposition principles still matter

Parnas, ADT, and component thinking are not history for its own sake — they are working tools when you have to decide where the boundary goes right now.

Distribution amplifies poor architecture

The network does not heal weak structure, it stretches it: you get a distributed monolith — the same coupling, now with network failures, latency, and an operating bill on top.

Practical takeaway: strengthen the modular monolith first

First get the modules in order inside one process, then extract services one at a time — when a specific piece has a durable reason for independent deployability.

How the idea of modularity evolved

The conversation about modules has run since the 1970s and keeps hitting the same question: where to draw the stable responsibility boundary. The names changed; the question did not.

1972

D. Parnas - decomposition criteria and information hiding

The criterion: a module hides the decision most likely to change and holds a stable boundary. The implementation can shift without breaking its neighbors.

1974

Liskov & Zilles - abstract data types (ADT)

Data abstraction strengthened a contract-oriented way of designing interactions between parts of a program.

1997

Foote & Yoder - the Big Ball of Mud anti-pattern

The paper shows how a system quietly slides into a tangle of dependencies where any change touches everything at once.

2014

Lewis & Fowler - microservices as independently deployable services

The value of microservices is tied to independent deployment, not to the label itself.

2014

Simon Brown - the distributed version of Big Ball of Mud

When boundaries are not clear up front, distribution does not remove architectural mistakes — it makes each one more expensive to debug and operate.

2026

Modular monolith as a return to modularity

The framing is a return to basic engineering discipline, not the arrival of a new architecture style.

Takeaways for developers

  • Modularity lives in dependencies and contracts, not in infrastructure or service count — moving to Kubernetes will not add it.
  • Describe architecture as dependency rules the build can check: no cycles, imports flow one way, no skipping layers.
  • A boundary that exists only in a folder name is not a boundary: code, CI, and architecture tests have to hold it, or it erodes within a couple of sprints.
  • Extract services only around stable business boundaries and a real need for independent deployment.

Takeaways for tech leads

  • Let the modular monolith be the default and make every microservice a separate call the team has justified and agreed to pay for.
  • Treat distribution as its own line item: observability, security, delivery platform, and data consistency are a recurring bill, not a one-time cost at split time.
  • Manage architecture with structure metrics: dependency graphs, forbidden dependencies, cycles, and drift between modules.
  • Formalize module ownership and architectural violation policy: current baseline plus a debt-reduction plan.

Practical plan for 2-4 weeks

  1. 1Name 3-7 module boundaries and generate a dependency graph from the codebase.
  2. 2Add 5-10 architecture rules to CI: layers, cycles, and forbidden imports.
  3. 3Set a violation baseline: no new violations, and a clear plan to reduce the old ones.
  4. 4Review service candidates only where there are separate SLAs, release cycles, and a clear owner for change.

When to stay in a monolith and when to extract services

Modular monolith as the baseline strategy

Until independent deployment is a durable requirement, it is cheaper to invest in module boundaries, architecture tests, and clear change ownership inside one process — same structural cleanliness, none of the network bill.

Microservices as an intentional step

Extract services when there are clear drivers for independent deployability, separate SLAs, partial scaling, and readiness to pay the cost of distribution.

Risks and limitations

  • Moving to microservices without mature boundaries produces a distributed monolith: the coupling stays, and network failures, distributed transactions, and on-call duty you did not have before pile on top.
  • The label “modular monolith” becomes marketing if dependency rules are not testable.

References

Related chapters

Enable tracking in Settings