Appearance
Clean Architecture
The architectural philosophy that guides system design at Synapse Studios
What is Clean Architecture?
Clean Architecture is a way of organizing software that creates systems with clear separation of concerns and explicit boundaries between different parts of the codebase. Popularized by Robert C. Martin, it presents the core ideas from Hexagonal Architecture (Alistair Cockburn), Onion Architecture (Jeffrey Palermo), and other architectural patterns in an accessible, unified vocabulary that has become widely adopted in the industry.
At its core, Clean Architecture organizes code into concentric layers, each with distinct responsibilities and dependencies that flow in only one direction: inward toward the business logic.
Why We Use Clean Architecture
Business Value Protection
The most important reason we adopt Clean Architecture is to protect and highlight our business logic. Your domain logic—the rules and processes that make your application valuable—should be the most visible, most stable, and most reusable part of your codebase.
Framework Independence
Frameworks are tools, not lifestyle choices. Clean Architecture ensures our business logic doesn't depend on whether we use Express, NestJS, React, or any other framework. This independence means we can upgrade or even replace frameworks without rewriting our core business logic.
Testability
When business logic has no dependencies on databases, UI, or external services, it becomes trivial to test. Unit tests run fast, require no complex setup, and clearly verify business rules without technical distractions.
Flexibility & Maintainability
By establishing clear boundaries and dependencies, Clean Architecture makes systems easier to understand, modify, and extend. New features can be added without modifying existing code. Technical implementations can be swapped without touching business logic.
Managing Coupling and Cohesion
At its core, Clean Architecture is a strategy for managing coupling and cohesion. The concentric layers create high cohesion within each layer (related responsibilities grouped together) while the Dependency Rule ensures loose coupling between layers (dependencies only flow inward). This deliberate structure ensures that the most stable, important code (domain logic) is protected from volatile, changing details (frameworks and infrastructure).
The Four Layers
Clean Architecture defines four concentric layers, each with specific responsibilities.
Note on Terminology: At Synapse, we refer to the innermost "Entities" layer as the Domain layer. This aligns with Domain-Driven Design terminology and better reflects that this layer contains not just entities, but also value objects, domain services, and other core business concepts. Throughout our documentation, when you see "Domain layer," it corresponds to what Clean Architecture calls the "Entities layer."
┌─────────────────────────────────────────────────────────────────┐
│ Frameworks & Drivers │
│ (Web, UI, DB, External APIs) │
│ ┌───────────────────────────────────────────────────────────┐ │
│ │ Interface Adapters │ │
│ │ (Controllers, Presenters, Gateways) │ │
│ │ ┌─────────────────────────────────────────────────────┐ │ │
│ │ │ Use Cases │ │ │
│ │ │ (Application Business Rules) │ │ │
│ │ │ ┌───────────────────────────────────────────────┐ │ │ │
│ │ │ │ Domain │ │ │ │
│ │ │ │ (Enterprise Business Rules) │ │ │ │
│ │ │ └───────────────────────────────────────────────┘ │ │ │
│ │ └─────────────────────────────────────────────────────┘ │ │
│ └───────────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────────┘
← Dependencies flow inward →The key insight: dependencies only point inward. The inner circles know nothing about the outer circles.
1. Domain (Enterprise Business Rules)
The innermost layer contains the enterprise-wide business rules. This Domain layer encapsulates the most general and high-level rules that would exist even if the application didn't exist—they represent core business concepts. This includes entities, value objects, and domain services.
Characteristics:
- Completely framework-agnostic
- No dependencies on any other layer
- Changes only when business rules change
- Reusable across multiple applications in the enterprise
Examples:
- User entity with validation rules
- Order entity with pricing calculations
- Domain-specific value objects like Email or Money
- Domain services for complex business operations
2. Use Cases (Application Business Rules)
This layer contains application-specific business rules. Use Cases orchestrate the flow of data to and from the Domain layer and direct domain objects to apply their business rules to achieve a goal.
Characteristics:
- Implements specific application behaviors
- Orchestrates domain object interactions
- Defines application-specific business rules
- Independent of delivery mechanism (HTTP, CLI, etc.)
- Independent of data storage mechanism
Examples:
- "Create Order" use case that validates inventory and processes payment
- "Register User" use case that ensures uniqueness and sends welcome email
- "Generate Report" use case that aggregates and formats business data
3. Interface Adapters
This layer converts data between the formats most convenient for Use Cases and the Domain layer, and the formats needed by external agencies like databases or the web.
Characteristics:
- Contains MVC controllers, presenters, and gateways
- Converts between internal and external data representations
- Implements repository interfaces defined by Use Cases
- Adapts external services to internal interfaces
Examples:
- REST API controllers that convert HTTP requests to Use Case inputs
- Repository implementations that translate between domain objects and database models
- Presenters that format Use Case outputs for specific UI requirements
4. Frameworks & Drivers
The outermost layer contains frameworks and tools such as databases, web frameworks, and other external dependencies. This layer is where all the technical details live.
Characteristics:
- Contains implementation details
- Most volatile layer (changes frequently)
- Minimal custom code—mostly configuration
- Easily replaceable components
Examples:
- Database connections and ORM configurations
- Web server setup and routing
- Third-party service integrations
- UI frameworks and libraries
The Dependency Rule
The fundamental rule that makes Clean Architecture work:
Source code dependencies must point only inward, toward higher-level policies.
This means:
- Inner layers cannot know anything about outer layers
- Data formats used in outer layers cannot be used by inner layers
- Names declared in outer layers must not be mentioned by inner layer code
This rule ensures that:
- Business logic remains independent of technical details
- Changes in outer layers don't affect inner layers
- The core of your application remains stable and portable
Data Flow
While dependencies point inward, data flows both ways across boundaries:
- Inbound Flow: External request → Controller → Use Case → Domain
- Processing: Domain objects apply business rules, Use Cases orchestrate
- Outbound Flow: Domain → Use Case → Presenter → External response
Data crossing boundaries is always in simple data structures—never in framework-specific formats. This typically means:
- Plain objects or data transfer objects (DTOs)
- Simple arrays and primitives
- Never framework-specific request/response objects in inner layers
Key Principles
Separation of Concerns
Each layer has a single, well-defined responsibility. Business logic is separated from technical implementation details.
Dependency Inversion
High-level modules don't depend on low-level modules. Both depend on abstractions defined by the high-level modules.
Stable Abstractions
The most stable (least likely to change) code is at the center. The most volatile (likely to change) code is at the edges.
Testability First
The architecture naturally creates testable code by isolating business logic from external dependencies.
Common Misconceptions
"Too Many Layers"
The layers aren't about creating complexity—they're about managing it. Not every feature needs all four layers explicitly. Simple CRUD operations might pass through quickly, while complex business logic benefits from clear separation.
"Over-Engineering"
Clean Architecture isn't about predicting the future; it's about creating boundaries that make change easier when it comes. Start simple and add layers as complexity emerges.
"Requires Specific Folder Structure"
The architecture is about dependencies and boundaries, not folder names. Organize your code in a way that makes sense for your team while respecting the Dependency Rule.
Applied In
The following implementation guides show how to apply Clean Architecture principles in specific technologies:
- NestJS Implementation Guide - Complete NestJS implementation with Clean Architecture:
- Modular Monolith in NestJS - Module boundaries and organization
- Clean Architecture in NestJS Modules - Layered architecture implementation
- Repository Pattern in NestJS - Data access patterns
- Acceptance Testing Guidelines - How Clean Architecture principles apply to test organization
Related Concepts
- Coupling and Cohesion - The fundamental principles Clean Architecture manages
- Modular Monolith - Applying Clean Architecture at the module level
- Use Cases - Deep dive into the Use Case layer
- Dependency Inversion & Ports/Adapters - How to implement the Dependency Rule
Further Reading
- The Clean Architecture - Original article by Robert C. Martin
- Clean Architecture: A Craftsman's Guide to Software Structure and Design - Complete book by Robert C. Martin