Clean Architecture
Robert C. Martin's Clean Architecture organises code into concentric layers where dependencies point inward — outer layers know about inner layers, never the reverse.
The Dependency Rule
Source code dependencies must point inward, toward higher-level policies.
Nothing in an inner layer can reference anything in an outer layer — not a name, a type, a function, or a module. Data crossing boundaries flows via simple DTOs or interfaces defined by the inner layer.
Layers (Inside → Outside)
1. Entities (Enterprise Business Rules)
- Domain objects encapsulating critical business rules
- Zero dependencies on anything external
- Survive framework changes, DB changes, UI changes
2. Use Cases (Application Business Rules)
- Orchestrate flow of data to/from entities
- Define application-specific rules (not business rules)
- One use case = one application action
- Depend only on entities
3. Interface Adapters
- Convert data between the format convenient for use cases and the format required by external agents (DB, web, etc.)
- Controllers, presenters, gateways, repository implementations
- Depend on use cases and entities
4. Frameworks & Drivers
- Web framework, database drivers, message brokers, UI framework
- Glue code only — minimal logic
- The most volatile layer
Boundaries
A boundary is a line separating components with different rates of change. Enforce with:
- Interfaces — inner layers define ports; outer layers implement them
- Dependency Injection — wire implementations at composition root
- Module/package boundaries — enforce via build system (separate packages, internal visibility)
Screaming Architecture
The top-level directory structure should scream the use cases of the system, not the framework:
# BAD — screams "Rails" # GOOD — screams "Clinic Scheduling"
app/ appointments/
controllers/ book_appointment.py
models/ cancel_appointment.py
views/ patients/
register_patient.py
update_insurance.py
Decision Framework
| Signal |
Recommendation |
| Long-lived system, evolving requirements |
Full Clean Architecture |
| Multiple delivery mechanisms (API, CLI, queue consumer) |
Full — adapters layer pays for itself |
| Simple CRUD, stable requirements |
Simplified 2-3 layer structure |
| Prototype / throwaway |
Skip — add layering when validated |
| Team > 3 engineers on same service |
Full — boundaries prevent coupling |
| Single delivery mechanism, tight deadline |
Simplified — extract layers later |
Simplified Layering (When Full Is Overkill)
handlers/ ← HTTP/gRPC handlers (thin, delegates immediately)
service/ ← business logic
repository/ ← data access (interface + impl)
Still follows the dependency rule, just fewer layers.
Anti-Patterns
- Leaking frameworks inward — ORM entities used as domain entities
- Anaemic use cases — use case just calls repository.save() with no logic
- Shared mutable models across layers — breaks isolation
- Circular dependencies — always signals a boundary violation
Cross-References
- See
architecture/knowledge-hexagonal-architecture — ports & adapters is the same core idea, different vocabulary
- See
principles/knowledge-solid — Dependency Inversion Principle underpins the dependency rule
1---2name: knowledge-clean-architecture3description: Clean Architecture principles: dependency rule, layers, boundaries, and screaming architecture. Decision framework for when to apply full Clean Architecture vs simplified layering. Use when discussing service structure, layer separation, or dependency direction.4---56# Clean Architecture78Robert C. Martin's Clean Architecture organises code into concentric layers where **dependencies point inward** — outer layers know about inner layers, never the reverse.910## The Dependency Rule1112> Source code dependencies must point inward, toward higher-level policies.1314Nothing in an inner layer can reference anything in an outer layer — not a name, a type, a function, or a module. Data crossing boundaries flows via simple DTOs or interfaces defined by the inner layer.1516## Layers (Inside → Outside)1718### 1. Entities (Enterprise Business Rules)19- Domain objects encapsulating critical business rules20- Zero dependencies on anything external21- Survive framework changes, DB changes, UI changes2223### 2. Use Cases (Application Business Rules)24- Orchestrate flow of data to/from entities25- Define application-specific rules (not business rules)26- One use case = one application action27- Depend only on entities2829### 3. Interface Adapters30- Convert data between the format convenient for use cases and the format required by external agents (DB, web, etc.)31- Controllers, presenters, gateways, repository implementations32- Depend on use cases and entities3334### 4. Frameworks & Drivers35- Web framework, database drivers, message brokers, UI framework36- Glue code only — minimal logic37- The most volatile layer3839## Boundaries4041A boundary is a line separating components with different rates of change. Enforce with:42- **Interfaces** — inner layers define ports; outer layers implement them43- **Dependency Injection** — wire implementations at composition root44- **Module/package boundaries** — enforce via build system (separate packages, internal visibility)4546## Screaming Architecture4748The top-level directory structure should **scream** the use cases of the system, not the framework:4950```51# BAD — screams "Rails" # GOOD — screams "Clinic Scheduling"52app/ appointments/53 controllers/ book_appointment.py54 models/ cancel_appointment.py55 views/ patients/56 register_patient.py57 update_insurance.py58```5960## Decision Framework6162| Signal | Recommendation |63|--------|---------------|64| Long-lived system, evolving requirements | Full Clean Architecture |65| Multiple delivery mechanisms (API, CLI, queue consumer) | Full — adapters layer pays for itself |66| Simple CRUD, stable requirements | Simplified 2-3 layer structure |67| Prototype / throwaway | Skip — add layering when validated |68| Team > 3 engineers on same service | Full — boundaries prevent coupling |69| Single delivery mechanism, tight deadline | Simplified — extract layers later |7071### Simplified Layering (When Full Is Overkill)7273```74handlers/ ← HTTP/gRPC handlers (thin, delegates immediately)75service/ ← business logic76repository/ ← data access (interface + impl)77```7879Still follows the dependency rule, just fewer layers.8081## Anti-Patterns8283- **Leaking frameworks inward** — ORM entities used as domain entities84- **Anaemic use cases** — use case just calls repository.save() with no logic85- **Shared mutable models across layers** — breaks isolation86- **Circular dependencies** — always signals a boundary violation8788## Cross-References8990- See `architecture/knowledge-hexagonal-architecture` — ports & adapters is the same core idea, different vocabulary91- See `principles/knowledge-solid` — Dependency Inversion Principle underpins the dependency rule