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

    Layered Architecture

    Layered Architecture stacks the application in horizontal layers — presentation, application, domain, infrastructure — each depending only on layers below.

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

    Introduction

    Layered Architecture stacks the application in horizontal layers — presentation, application, domain, infrastructure — each depending only on layers below. It's the lingua franca of enterprise software: Controller → Service → Repository → DB. The goal isn't ceremony; it's predictable placement so teams ship without stepping on each other.

    The story

    A startup MVP had controllers calling SQL directly. After 18 months every feature touched HTTP + SQL + business rules in one file. Introducing layers (Controller → Service → Repository) took 4 weeks; new developers shipped features in 2 days instead of 2 weeks.

    The business problem

    Monolithic handlers mixing transport, logic, and persistence create team friction:

    • No test seam: every test needs HTTP server + real database.
    • Ownership blur: newcomers can't find where business logic lives.
    • Merge conflicts: all teams edit the same controller files.
    • Change ripple: swapping DB touches every endpoint.

    The problem teams faced

    Layered Architecture fits when:

    • CRUD-heavy enterprise app with multiple contributors.
    • Team size exceeds ~5 and needs shared vocabulary.
    • Long-lived system with separate presentation and persistence churn.
    • Tests must run without full infrastructure stack.

    Understanding the topic

    Intent: Separate concerns into layers with downward-only dependencies.

    • Presentation — HTTP controllers, CLI, GraphQL resolvers.
    • Application — use cases, orchestration, transaction boundaries.
    • Domain — entities, value objects, business rules (optional explicit layer).
    • Infrastructure — DB, messaging, external APIs.

    Internal architecture

    Layered checkout flow:

    ts
    // Presentation
    app.post("/orders", (req, res) => orderController.place(req, res))
    // Application
    class OrderService {
    constructor(private orders: OrderRepository) {}
    async place(cart: Cart) { /* business rules */ return this.orders.save(order) }
    }
    // Infrastructure
    class PostgresOrderRepository implements OrderRepository { /* SQL */ }

    Visual explanation

    Three diagrams cover layer stack, dependencies, and leak detection:

    Classic 4-layer stack
    Controller
    Presentation
    Service
    Application
    Repository
    Infrastructure IF
    Database
    Infrastructure impl
    Dependencies point down — Controller never imports SQL driver.
    Layer violation detector
    Import check
    Repo in controller?
    Violation
    Skip layers
    Fix seam
    Inject service
    ArchUnit / lint
    CI enforce
    Layer rules enforced in CI — not hope and code review.
    When layers earn cost
    Team > 5?
    Vocabulary wins
    CRUD enterprise?
    Classic fit
    Tiny script?
    Skip layers
    Measured pain?
    ADR first
    Layers add files — apply when onboarding and test pain are real.

    Informative example

    Before / after — controller with SQL to layered:

    ts
    // ❌ Everything in controller — untestable, coupled
    app.post("/orders", async (req, res) => {
    const client = await pool.connect()
    const total = req.body.items.reduce((s, i) => s + i.price, 0)
    await client.query("INSERT INTO orders ...", [total])
    res.json({ ok: true })
    })
    // ✅ Layers — test service with fake repo
    class OrderService {
    constructor(private repo: OrderRepository) {}
    async place(cart: Cart) {
    const order = Order.fromCart(cart)
    return this.repo.save(order)
    }
    }

    Execution workflow

    1Introduce layers incrementally
    1 / 4

    Extract service

    Move business logic out of controller.

    Controller validates + delegates.

    Real-world use

    Spring Boot (@Controller/@Service/@Repository), ASP.NET layers, Rails MVC + service objects, most enterprise CRUD apps.

    Production case study

    Startup MVP layer extraction:

    • Before: controllers with SQL; 2-week feature cycles for new hires.
    • After: Controller → Service → Repository; onboarding 2 days to first PR.
    • Metric: test suite ran without DB using in-memory repo fakes.

    Trade-offs

    • Pro: predictable structure; testable seams; team vocabulary.
    • Con: more files; wrong layer placement hard to fix later.
    • Con: anemic domain if all logic lives in service layer.

    Decision framework

    • Use for CRUD enterprise apps with team > 5.
    • Use when test isolation from HTTP/DB is required.
    • Avoid for tiny apps — layers add ceremony without payoff.
    • Don't skip domain layer when rules are complex — avoid anemic services.

    Best practices

    • Controllers thin — validate input, call service, map response.
    • Repositories return domain types — not raw ORM rows to controllers.
    • Enforce dependency direction in CI.

    Anti-patterns to avoid

    • Smart controller with SQL and business rules.
    • Repository called directly from controller — skips application layer.
    • Layers as folders only — no dependency rules enforced.

    Common mistakes

    • Anemic domain — all logic in services, entities are data bags.
    • Layer leak — ORM entities in presentation layer.
    • Premature layers before team pain exists.

    Debugging tips

    • Trace bug layer-by-layer — which layer owns the wrong assumption?
    • Import graph visualization finds layer violations.

    Optimization strategies

    • Don't add domain layer until rules exceed simple CRUD.

    Common misconceptions

    • Layers ≠ microservices. Layers are in-process; services are deployment boundaries.
    • Hexagonal/Clean refine layers with explicit ports — not replace them entirely.

    Advanced interview questions

    Interview Prep

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

    3 questions
    1IntermediateQuestionLayered vs Hexagonal?+

    Answer

    Layered: horizontal stack presentation→infra. Hexagonal: domain center with ports/adapters — emphasizes domain isolation over layer names.

    Follow-up

    When upgrade to hex?
    2IntermediateQuestionWhere do business rules go?+

    Answer

    Domain layer (entities/services) for rich model; application layer orchestrates. Avoid fat controllers or fat repositories.

    Follow-up

    Anemic domain?
    3AdvancedQuestionTest layers how?+

    Answer

    Unit test domain without DB; integration test repository; controller tests with mocked service.

    Follow-up

    Skip E2E?

    Summary

    You can structure CRUD apps in layers, enforce dependency direction, and know when layers earn their cost. Tell the controller-with-SQL startup story — if you can do that, you own Layered Architecture.

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