Enterprise Architecture Patterns Tutorial 0/65 lessons ~6 min read Lesson 20

    Layered Architecture

    Layered architecture organizes code into horizontal tiers — presentation, application, domain, infrastructure — with strict dependency direction downward.

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

    Introduction

    Layered architecture organizes code into horizontal tiers — presentation, application, domain, infrastructure — with strict dependency direction downward. Netflix's early streaming platform used layered monoliths before microservices; understanding layers remains essential for structuring modules inside any deployable unit.

    Real production story

    Netflix's 2010 streaming API was a classic three-tier Java monolith: JSP controllers called service classes that called DAOs. A engineer bypassed the service layer to "just query the DAO" from a controller for a hackathon feature. The shortcut shipped, then propagated — within a year, 40% of controllers hit DAOs directly, business rules duplicated across tiers, and a single schema change required touching 200 files.

    Glenn Vanderburg's refactor introduced strict layering with package-private DAOs and Checkstyle rules: presentation → application → domain → infrastructure. Test coverage on domain logic jumped from 34% to 89% because rules were testable without servlet containers. The layered monolith survived until microservice extraction began — layers became service boundaries.

    Business problem

    Business pressure: Netflix needed to iterate on recommendation UI weekly while keeping billing and playback rules consistent. Without layer discipline, UI teams embed SQL in controllers and billing logic leaks into JSPs — every UI tweak becomes a schema migration.

    • Revenue at risk: Duplicate discount logic in controller and service tiers caused inconsistent pricing for 2% of streams — millions in entitlement disputes.
    • Engineering velocity: Onboarding engineers could not locate business rules; "where does cancellation logic live?" had four answers.
    • Compliance / trust: SOC1 auditors require traceable business rule layer separate from presentation — layer skipping breaks audit narrative.

    Architecture overview

    Layered architecture stacks responsibilities vertically. Upper layers orchestrate; lower layers implement technical details. The domain layer must not depend on presentation or persistence frameworks.

    • Definition: Presentation → Application → Domain → Infrastructure, dependencies point inward/down.
    • When to adopt: CRUD-heavy enterprise apps, teams new to DDD, monoliths needing immediate structure.
    • When to defer: Event-heavy systems where layers cut across event flows — consider hexagonal instead.
    • Operability: Layer violations surface as arch tests; runtime metrics still per-endpoint, not per-layer.

    Architecture motivation

    Why architects care: Layers separate concerns that change at different rates — UI changes daily, domain rules monthly, infrastructure when vendors shift. Dependency inversion keeps domain logic independent of frameworks.

    • Force: Multiple teams modify same codebase with different change frequencies.
    • Constraint: Cannot rewrite to microservices while subscriber growth demands feature velocity.
    • Outcome: Predictable location for every class of change; testable domain core.

    Internal architecture

    Netflix streaming monolith layers — classic n-tier with inverted domain:

    • Application layer owns transaction boundaries (@Transactional at use-case level).
    • Domain layer defines Repository interfaces; infrastructure implements them.
    text
    ┌──────────────────────────────────────────────────────────┐
    │ PRESENTATION (Controllers, DTOs, View models) │
    │ │ calls application services only │
    ├───────▼──────────────────────────────────────────────────┤
    │ APPLICATION (Use cases, orchestration, transactions) │
    │ │ coordinates domain; no business rules here │
    ├───────▼──────────────────────────────────────────────────┤
    │ DOMAIN (Entities, value objects, domain services) │
    │ │ pure Java — zero Spring, zero JDBC imports │
    ├───────▼──────────────────────────────────────────────────┤
    │ INFRASTRUCTURE (JPA repos, REST clients, message adapters)│
    │ implements interfaces defined in DOMAIN │
    └──────────────────────────────────────────────────────────┘
    Dependency rule: each layer may call ONLY the layer below

    Data flow

    Primary path: REST controller receives CancelSubscriptionRequest, maps to application command, use case loads aggregate via repository port, domain applies cancel() rule, infrastructure persists and emits integration event.

    • Write path: Controller → UseCase → Domain aggregate → Repository impl → DB.
    • Read path: Query use cases may bypass full domain for read models (CQRS-lite) but still enter through application layer.
    • Async path: Infrastructure publishes to Kafka after use case commits; domain never imports Kafka SDK.

    System design diagram

    Two diagrams show the Layered Architecture topology and the primary request/event path used in production at scale.

    Layered Architecture — system view
    Presentation
    Edge
    Application
    Core
    Domain
    Data
    Infrastructure
    Async
    High-level topology for Layered Architecture.
    Layered Architecture — request / event flow
    HTTP request
    Ingress
    Use case
    Store
    Domain rule
    Store
    Repository
    Emit
    Follow this path when reviewing production designs.

    Production code example

    Spring Boot layered package structure with ArchUnit — Netflix-style enforcement:

    java
    // Package layout
    com.netflix.streaming
    .presentation.api // @RestController — DTOs in/out only
    .application.command // CancelSubscriptionUseCase
    .domain.model // Subscription aggregate, CancelPolicy
    .domain.port // SubscriptionRepository interface
    .infrastructure.jpa // SubscriptionJpaRepository implements port
    .infrastructure.kafka // SubscriptionEventPublisher
    @Service
    @RequiredArgsConstructor
    class CancelSubscriptionUseCase {
    private final SubscriptionRepository repo;
    private final EventPublisher events;
    @Transactional
    public void execute(CancelCommand cmd) {
    Subscription sub = repo.findById(cmd.subscriberId())
    .orElseThrow(() -> new NotFoundException(cmd.subscriberId()));
    sub.cancel(cmd.reason()); // domain rule — no IF in use case
    repo.save(sub);
    events.publish(sub.domainEvents());
    }
    }
    // ArchUnit: domain must not depend on infrastructure
    noClasses().that().resideInAPackage("..domain..")
    .should().dependOnClassesThat().resideInAPackage("..infrastructure..");

    Enterprise case study

    Netflix streaming API (2009–2012): Layered monolith supported 20M subscribers before microservice migration; layer discipline made domain logic portable to extracted services.

    • Before: Controllers with embedded SQL; untestable cancellation logic.
    • Decision: Enforce four layers with Checkstyle + package visibility + domain-only unit tests.
    • After: Domain tests ran in <30s CI; billing service extraction reused 80% of domain package.

    Trade-offs

    • Clarity vs rigidity: Layers make navigation predictable but encourage anemic domain models if application layer hoards logic.
    • Performance vs purity: Strict layering adds mapping hops; pragmatic teams allow read-path shortcuts with ADRs.
    • Monolith layers vs microservices: Layers are vertical slices inside one deployable; do not confuse with service boundaries.

    Security considerations

    Security is architectural: Authorization belongs in application layer (use-case guards), not sprinkled in controllers or repositories.

    • Identity: Presentation validates JWT; application layer enforces role-per-use-case.
    • Data: Infrastructure encrypts at rest; domain never sees connection strings.
    • Supply chain: Domain layer's zero-dependency rule reduces attack surface in business-critical code.

    Scalability analysis

    Scale dimensions: Netflix scaled the layered monolith horizontally until playback and billing layers needed independent fleets — layers informed but did not dictate service cuts.

    • Horizontal scale: Stateless presentation tier behind Eureka/ELB; session in Cassandra.
    • Hot spots: Application layer becomes god-service — split use cases by subdomain before extracting microservices.
    • Cost: Layer mapping (DTO explosion) increases CPU on high-QPS paths — profile before adding mappers.

    Failure scenarios

    What breaks: Layer skipping erodes over time; infrastructure exceptions leak through domain into API responses.

    • Anemic domain: All logic in application services — domain entities are data bags; changes require touching every layer.
    • Leaky abstraction: JPA annotations on domain entities couple domain to Hibernate — schema change ripples to API.
    • God service: Single application service class grows to 4000 lines — sign to split by use case or extract module.

    Staff engineer insights

    • Layers are a organizing tool, not an architecture — if your domain layer imports Spring, you have three tiers and a pretense.
    • Netflix's migration succeeded because domain logic was already isolated — layers paid for themselves at extraction time.
    • Watch for the "smart controller" anti-pattern: if PRs add business rules above the application layer, reject them.

    Interview questions

    Interview Prep

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

    3 questions
    1AdvancedQuestionWhat is the difference between layered architecture and hexagonal architecture?+

    Answer

    Layers are horizontal tiers organized by technical concern; hexagonal organizes by ports and adapters around domain with no prescribed "top." Layers often produce anemic domains; hexagonal forces domain-centric design. Many teams use layers inside hexagonal's application ring.

    Follow-up

    When would you choose layers over hexagonal for a greenfield project?
    2AdvancedQuestionHow do you prevent layer violation decay over time?+

    Answer

    Automate: ArchUnit, Checkstyle import rules, code ownership on package paths, and PR templates that ask "which layer?" Fail CI on violations; do not rely on senior reviewer memory. Quarterly dependency graph audits catch drift.

    Follow-up

    What metrics indicate layer architecture is failing?
    3AdvancedQuestionCan layered architecture coexist with microservices?+

    Answer

    Yes — each microservice is often internally layered. The mistake is mapping layers to services (presentation-service, domain-service) which creates chatty distributed layers. One service = one bounded context with internal layers.

    Follow-up

    How did Netflix map layers to services during extraction?

    Architecture review questions

    • Is dependency direction enforced (presentation → application → domain ← infrastructure)?
    • Does domain layer have zero framework imports (Spring, JPA, HTTP)?
    • Are transactions owned at application/use-case boundary?
    • Are repository and messaging ports defined in domain, implemented in infrastructure?
    • Do ArchUnit or equivalent tests fail CI on layer violations?
    • Is authorization enforced at use-case level, not duplicated in controllers?

    Summary

    Layered architecture at Netflix scale organized a generation of monoliths before microservices — presentation, application, domain, infrastructure with strict dependency direction. Staff engineers use it today inside modules and services, always guarding against anemic domains and layer-skipping shortcuts that erode the structure.

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