Layered and modular monolith
Most software ever written is a monolith, and most of it is layered: screens on top, business rules in the middle, data access at the bottom. It's the default for good reasons: simple, cheap and familiar. Its domain-partitioned cousin, the modular monolith, keeps those benefits while organising code around the business, and is many teams' best answer to "should we do microservices?". This module covers both, including how they decay and how to stop it.
1. The idea
Layered (technically partitioned)
The code is split into horizontal layers: presentation, business, persistence and the database. Each layer has one technical job. Layers are usually closed: a request must pass through each layer in turn, never skipping one. That gives layers of isolation: a change in one layer (a new database) doesn't affect the others.
Modular monolith (domain partitioned)
The code is split into business modules (orders, payments, catalogue), each with its own layers inside and a small public API. Modules talk only through those APIs or through in-process events, and ideally each owns its own tables. It's still one deployment and one database server, so it's simple to run, but changes stay inside a module.
Both are one architecture quantum (Module 09): they scale, fail and deploy as a whole. That's their main limit, and also why they're cheap.
How they rate
| Characteristic | Layered | Modular monolith |
|---|---|---|
| Partitioning | technical | domain |
| Quanta | 1 | 1 |
| Cost | ★★★★★ | ★★★★★ |
| Simplicity | ★★★★★ | ★★★★★ |
| Scalability | ★★★★★ | ★★★★★ |
| Elasticity | ★★★★★ | ★★★★★ |
| Fault tolerance | ★★★★★ | ★★★★★ |
| Evolvability | ★★★★★ | ★★★★★ |
| Deployability | ★★★★★ | ★★★★★ |
| Testability | ★★★★★ | ★★★★★ |
| Performance | ★★★★★ | ★★★★★ |
Our qualitative ratings, 1 to 5 stars, more is better (for cost, more stars = cheaper). They compare styles in general; your context can move any of them.
2. How it works
Closed layers, isolation, and the sinkhole
Two requests travel through the same four layers. Watch what each layer does with them, then a database change, then a common shortcut.
A modular monolith keeping its boundaries
Modules are only as separate as the rules that keep them apart. In one codebase, nothing stops a developer importing another module's internals, except a test. Watch one.
3. Try it yourself
Would the architecture test pass?
Each line is a change someone proposes. Decide whether it respects the structure, then reveal the rule and the kind of automated test that would catch it.
4. Trade-offs
Technical vs domain split
Layers make technical changes (a new UI framework, a new database) local; modules make business changes local. Business changes are far more frequent in most systems, which is why the modular monolith usually ages better.
Closed vs open layers
Closed layers isolate change but force pass-through code. Opening a layer (letting requests skip it) removes the sinkhole but couples the upper layer to the lower one. Open a layer only for a named reason, and record it.
One deployment vs independence
One deployment means one pipeline, easy transactions, in-process calls and simple debugging. It also means one release train and one scaling unit for everything.
Shared vs owned tables
A modular monolith with one shared schema still couples modules through the data. Giving each module its own tables (or schema) costs some joins, and makes later extraction into a service far easier.
5. In real projects
Layered is the starting point of most frameworks. MVC web frameworks produce controllers, services and repositories by default. That's fine for small systems; as they grow, every business change crosses every layer and every team.
The modular monolith is a deliberate choice, not a stepping stone you're ashamed of. Several large, well-known products run as modular monoliths, and tools exist to enforce module boundaries inside one codebase: ArchUnit for Java, Spring Modulith, Packwerk for Ruby, Java's own module system, or plain package-visibility rules.
Agility isn't only for microservices. A well-modularised monolith with good tests and continuous delivery can release many times a day. What hurts agility is poor modularity and slow, risky releases, and those can exist in any style.
Say it in the interview
- "What's the architecture sinkhole?" Requests that pass through layers that add nothing, just forwarding calls. A little is normal; if most requests do it, the layering is costing more than it gives.
- "Why a modular monolith instead of microservices?" It keeps changes local by business area, like microservices, without the network, data distribution and operations cost. It's a good default when all parts can share one set of characteristics.
- "How do you stop a modular monolith decaying?" Each module exposes a small public API and owns its tables, and architecture tests in the build fail if any module reaches into another's internals.
- Calling a monolith "legacy" by definition.
- Modules that share every table, described as independent.
- No mechanism to enforce boundaries inside one codebase.
6. Remember it
How this hook works: what "floors or shops" means
What the slogan means, phrase by phrase
- "Floors"
- Horizontal layers: every sale visits every floor, so most changes visit every layer.
- "Shops"
- Vertical modules: each shop has its own till and stockroom, so a change stays in one shop.
- "one building"
- Either way, one deployment: it scales and fails as a whole.
Why this picture fits: it captures the one decision that separates the two styles (the direction of the split) and the property they share (one quantum).
The story → the concept
| The building | The architecture |
|---|---|
| Tills floor, stockroom floor | Presentation layer, persistence layer |
| Shops with their own tills | Modules with their own layers |
| Shop doors onto the mall | A module's public API |
| Security guard checking back doors | Architecture tests in the build |
The trap it saves you from
Believing that a monolith must be a big ball of mud, or that modules stay separate without enforcement.
7. Common mistakes
8. Design exercise (30 minutes)
- Measure the sinkhole (10 min). Pick ten endpoints in a layered system you know. How many have real logic in the business layer?
- Draw the modules (10 min). Sketch the same system as a modular monolith: which modules, what each one's public API would be, and which tables it would own.
- Write two rules (10 min). Write two architecture-test rules you'd add to the build, in plain English, and what each would have prevented.
9. Self-check quiz
What does it mean for a layer to be closed?
What is the architecture sinkhole?
In a modular monolith, how should Orders get data from Payments?
How many architecture quanta does a modular monolith with one database have?
Why does a modular monolith usually age better than a layered one?
10. Go deeper
| Resource | Time | Why |
|---|---|---|
| Fundamentals of Software Architecture, 2nd edition (Richards and Ford) | book | The chapters on the layered and modular monolith styles. |
| ArchUnit user guide | 30 min | Writing layer and module rules as unit tests (Java; similar tools exist for other languages). |
| Spring Modulith | 20 min | A framework built around modular monoliths: module APIs, events and verification. |