Clean Architecture
Clean Architecture is a way to structure software so that business rules stay independent of frameworks, databases, and UI details. The payoff is long-term maintainability: swapping a database, moving from REST to GraphQL, or redesigning the UI shouldn't force a rewrite of your core domain logic, because that logic never knew about those details in the first place.
The single idea that makes it work is the dependency rule: dependencies point inward, toward your business rules. Everything external — the web framework, the database driver, the API client — is a replaceable "detail" at the edges. You trade some extra structure for testability and flexibility.
TL;DR
- Put business rules in the center; dependencies point inward.
- Code depends on abstractions (interfaces), not concrete frameworks.
- Frameworks and databases are details at the edges.
- You gain testability and flexibility at the cost of more structure.
Quick Example
A use case depends on an interface it owns; infrastructure implements it:
The Dependency Rule
Dependencies must point inward:
- Outer layers may depend on inner layers.
- Inner layers must not depend on outer layers.
This is what prevents your domain from importing database drivers, HTTP frameworks, or UI code — and it's the whole game. Everything else is a consequence.
The Layers
From inner to outer (teams name these differently, but the direction is what matters):
- Entities / Domain — core business objects and invariants.
- Use Cases (Interactors) — application-specific rules; orchestrate entities and define input/output ports (interfaces).
- Interface Adapters — controllers, presenters, gateways; convert between HTTP/DB formats and domain types.
- Frameworks & Drivers — the web framework, database, external APIs, UI.
Wiring It Together
The HTTP adapter translates a request into a use-case call — the use case never knows HTTP exists:
Because the use case depends only on the PostRepository port: its tests need no HTTP or real database, the database can be swapped by changing one implementation, and REST or GraphQL can call the exact same use case.
Testing Strategy
- Unit tests — entities and use cases in isolation, with fakes for the ports. Fast and framework-free.
- Integration tests — the infrastructure adapters (real DB, external APIs) and the controllers/routing that wire it all up. See Integration Testing.
Best Practices
- Own your interfaces in the inner layer; implement them at the edges (Dependency Inversion).
- Keep frameworks at the boundary — no framework imports in domain/application code.
- Match structure to complexity — don't impose four layers on a tiny app.
- Test use cases with fakes; reserve real infrastructure for integration tests.
- Treat the folder layout as a guide, not dogma — the dependency direction is the real rule.
Common Mistakes
Over-abstracting a small app
Business logic in the controller
FAQ
How is Clean Architecture different from a normal layered (MVC) app?
Traditional layered apps often let dependencies flow toward the database (the UI depends on services, which depend on the data layer). Clean Architecture inverts the outermost dependency: the database and framework depend on the application, via interfaces the application owns. That inversion is what keeps business rules pure and swappable — a standard MVC app usually has the domain coupled to the ORM.
Isn't all this indirection overkill?
It can be — for small apps or prototypes, the layers add ceremony without payoff. Clean Architecture earns its keep when the domain is genuinely complex, multiple interfaces exist (web + mobile + API), you expect framework or datastore changes, or the code needs to live for years. Match the investment to those signals rather than applying it reflexively.
Where does validation belong?
Domain/use-case validation (business rules — "a post must have a title," "a transfer can't overdraw") belongs in the inner layers, expressed in domain terms. Input-shape validation (is this JSON well-formed, are required fields present) can sit at the adapter boundary. Keep the business invariants in the core so every interface enforces them consistently.
How does it relate to Hexagonal Architecture / Ports & Adapters?
They're essentially the same idea with different vocabulary. Hexagonal Architecture's "ports and adapters" map directly onto Clean Architecture's interfaces (ports) and their implementations (adapters), and both enforce dependencies pointing toward the core. Onion Architecture is another close relative. Pick the terminology your team prefers; the dependency rule is identical.
Related Topics
- SOLID Principles — Dependency Inversion underpins it
- Design Patterns — Adapters, factories at the edges
- Domain-Driven Design — Modeling the core
- Integration Testing — Testing the adapters
- Microservices — Boundaries at service scale