Command Palette

Search for a command to run...

Level 2 · 25 min

Clean Architecture

Clean Architecture (Robert C. Martin) organizes code so that business logic has no dependencies on frameworks, databases, or external services. The dependency rule makes the domain independently testable and replaceable.

The Dependency Rule

The central rule: source code dependencies must always point inward. Outer layers (UI, database, frameworks) depend on inner layers (use cases, entities). Inner layers know nothing about outer layers. This means: the domain model (entities) has zero imports from Spring, Hibernate, Express, or any framework. The use case layer has no imports from HTTP, SQL, or any external library. If you need to call a database from a use case, you define an interface (repository port) in the use case layer, and the outer layer provides the implementation. This inversion of dependencies (Dependency Inversion Principle) is what makes the architecture testable: swap the real database implementation for an in-memory one in tests.

Layers and Responsibilities

From innermost to outermost: Entities: enterprise-wide business rules and data. A User entity with its validation rules exists regardless of whether the application is a web app, CLI, or batch job. Use Cases (Interactors): application-specific business rules that orchestrate entities to accomplish one goal. CreateUser use case: validate input, check uniqueness, hash password, save user, send welcome email. No HTTP, no SQL — only interfaces. Interface Adapters: controllers (convert HTTP request to use case input DTO), presenters (convert use case output to HTTP response), and gateways/repositories (implement data access interfaces defined by use cases). Frameworks and Drivers: Express/Spring, PostgreSQL/MongoDB, external APIs. The most volatile layer — replace without changing inner layers. Martin's definitive formulation: 'Source code dependencies must point only inward, toward higher-level policies. Nothing in an inner circle can know anything at all about something in an outer circle.' The architecture should scream its purpose: 'When you look at the top-level directory structure, do they scream Health Care System or Accounting System? Or do they scream Rails or Spring/Hibernate?' A Rails-first directory structure has frameworks at the center — the exact inversion of the Dependency Rule. Martin's test: if your top-level folders are 'controllers/', 'models/', 'views/', the architecture screams the framework, not the business domain. — Robert C. Martin, Clean Architecture

Practical Implementation

Folder structure: src/domain/entities (User, Order), src/application/use-cases (CreateUser, PlaceOrder), src/application/ports (UserRepository interface, EmailService interface), src/infrastructure/adapters (PostgresUserRepository implements UserRepository), src/interfaces/http (UserController, UserPresenter). Testing: CreateUser use case tests with InMemoryUserRepository — no database setup required. Integration tests for the repository implementation separately. The use case test runs in milliseconds, not seconds. Framework independence: if you decide to replace Express with Fastify, only the HTTP adapter layer changes. If you replace PostgreSQL with DynamoDB, only the repository adapter changes. The use case and entity layers are untouched.

Key Takeaways

  • Dependencies point inward. The innermost layers (entities, use cases) have zero dependencies on the outermost layers (frameworks, databases). This is enforced by dependency inversion.
  • Use cases are the most important layer — they contain the application's business logic and are framework-independent. They should be the first thing you read to understand what the system does.
  • The practical benefit is testability: use cases can be tested with in-memory implementations of their ports. No Spring context, no database — tests run in milliseconds.

Code example

arch006.learn.codeExample