Design Patterns Tutorial 0/70 lessons ~6 min read Lesson 45

    Clean Architecture

    Clean Architecture (Uncle Bob) codifies concentric layers: Entities → Use Cases → Interface Adapters → Frameworks.

    Course progress0%
    Focus
    21 guided sections
    Practice signal
    Examples included
    Career prep
    Interview Q&A included

    Introduction

    Clean Architecture (Uncle Bob) codifies concentric layers: Entities → Use Cases → Interface Adapters → Frameworks. The dependency rule: source code dependencies point inward only. Frameworks and DB are plugins at the outer edge — business rules at the center survive technology churn.

    The story

    Teams at Uber and major banks converged on Clean/Hexagonal/Onion independently. Adopters report longer codebase lifespans — framework upgrades become adapter swaps, not domain rewrites.

    The business problem

    Framework-as-architecture makes upgrades bet-the-company projects:

    • Upgrade paralysis: Spring/Rails version jump touches every file.
    • Logic scatter: same rule in controller, service, and repository.
    • Untestable use cases: business flow requires HTTP + DB to test.
    • Onboarding chaos: no agreement where new code belongs.

    The problem teams faced

    Clean Architecture fits when:

    • System expected to live 5+ years with framework/DB changes.
    • Use cases must be testable independent of delivery mechanism.
    • Multiple interfaces (REST, GraphQL, gRPC) share business rules.
    • Team needs explicit dependency rule beyond informal layers.

    Understanding the topic

    Intent: Concentric layers with inward-only dependencies.

    • Entities — enterprise business rules (Order, Money).
    • Use Cases — application-specific rules (PlaceOrder).
    • Interface Adapters — controllers, presenters, gateways.
    • Frameworks & Drivers — DB, web framework, external APIs.

    Internal architecture

    Clean Architecture rings:

    text
    [ Web · DB · Queue ] ← Frameworks (outer)
    [ Controllers · GW ] ← Interface Adapters
    [ Use Cases ] ← Application
    [ Entities ] ← Domain (inner)
    PlaceOrderUseCase → depends on → OrderRepository (interface)
    PostgresOrderRepository → implements → OrderRepository
    OrderController → calls → PlaceOrderUseCase

    Visual explanation

    Three diagrams cover dependency rule, layer ring, and use case isolation:

    Dependency rule
    Frameworks
    Outer ring
    Adapters
    Controllers · GW
    Use Cases
    Application rules
    Entities
    Core
    Arrows point inward — outer depends on inner, never reverse.
    Use case testability
    PlaceOrderUseCase
    No HTTP import
    Fake repos
    In-memory
    Unit test
    Milliseconds
    E2E separate
    Adapter tests
    Use cases tested without web server or database.
    Clean vs anemic
    Rich entities?
    Logic in domain
    Use case orchestrates
    Thin coordination
    Fat controller?
    Violation
    Dependency check
    CI ArchUnit
    Clean without domain logic in entities is just extra folders.

    Informative example

    Before / after — framework-coupled to Clean use case:

    ts
    // ❌ Use case imports Express and Prisma
    export async function placeOrder(req: Request, res: Response) {
    const order = await prisma.order.create({ data: req.body })
    res.json(order)
    }
    // ✅ Use case — zero framework imports
    class PlaceOrderUseCase {
    constructor(
    private orders: OrderRepository,
    private payments: PaymentGateway,
    ) {}
    async execute(cmd: PlaceOrderCommand): Promise<OrderId> {
    const order = Order.create(cmd)
    await this.payments.charge(order.total)
    await this.orders.save(order)
    return order.id
    }
    }
    // Adapter — Express only here
    router.post("/orders", async (req, res) => {
    const id = await placeOrderUseCase.execute(mapReq(req))
    res.json({ id })
    })

    Execution workflow

    1Clean Architecture adoption
    1 / 4

    Entities first

    Model Order, Money with business invariants.

    Rich where rules exist.

    Real-world use

    Uncle Bob's Clean Architecture book; converges with Hexagonal and Onion; NestJS clean modules; many bank and fintech codebases.

    Production case study

    Framework migration at scale:

    • Scenario: Bank codebase tied to aging application server.
    • Decision: Clean layers — use cases extracted with port interfaces.
    • Outcome: New delivery mechanism (gRPC) added as adapter; domain untouched.

    Trade-offs

    • Pro: framework longevity; clear dependency rule; testable core.
    • Con: significant upfront structure; overkill for small apps.
    • Con: team discipline required — rings degrade without CI enforcement.

    Decision framework

    • Use for long-lived systems with expected tech churn.
    • Use when use case tests are architectural requirement.
    • Avoid for prototypes — start layered, evolve toward Clean when pain appears.

    Best practices

    • One use case class per user story — PlaceOrder, CancelOrder.
    • Entities hold invariants — not just data transfer.
    • Enforce dependency rule mechanically in CI.

    Anti-patterns to avoid

    • Clean folder structure without dependency inversion — cargo cult.
    • Use cases that import ORM entities from outer ring.
    • 100 use case classes with zero domain logic — anemic.

    Common mistakes

    • Mapping overhead between layers — use mappers at adapter boundary only.
    • Team disagreement on ring placement — document in ADR.

    Debugging tips

    • If entity tests pass but API fails — bug in adapter mapping layer.

    Optimization strategies

    • Don't build all rings day one — grow inward as rules accumulate.

    Common misconceptions

    • Clean ≠ many layers mandatory on day 1. Dependency rule is the point; rings can start minimal.
    • Same forces as Hexagonal — different diagram, same inversion.

    Advanced interview questions

    Interview Prep

    Practice concise answers, then expand each card for the explanation.

    3 questions
    1IntermediateQuestionClean Architecture dependency rule?+

    Answer

    Source code dependencies point inward only. Outer rings (frameworks) depend on inner (entities/use cases), never the reverse.

    Follow-up

    How enforce?
    2AdvancedQuestionEntities vs Use Cases?+

    Answer

    Entities: enterprise-wide business rules (Money can't be negative). Use Cases: application-specific flow (PlaceOrder orchestrates charge + save).

    Follow-up

    Anemic entities?
    3IntermediateQuestionClean vs Hexagonal?+

    Answer

    Convergent — Clean names concentric rings and dependency rule; Hexagonal names ports/adapters. Often combined in same codebase.

    Follow-up

    Which diagram in ADR?

    Summary

    You can explain the dependency rule, place use cases at the center, and test without frameworks. Tell the framework migration survival story — if you can do that, you own Clean Architecture.

    Ready to mark this lesson complete?Track your journey across the entire course.