Layered Architecture
By the end of this module you will be able to:
- Describe the four standard layers of a layered architecture and what belongs in each
- Identify a layer violation and explain why it undermines testability and replaceability
- Distinguish strict layering from relaxed layering and choose the right approach
- Explain the anemic domain model anti-pattern and how it arises from misapplying layers
With the learning outcomes established, this module begins by examining what layered architecture is in depth.
5.1 What layered architecture is
Layered architecture organises code into horizontal tiers where each layer has a specific responsibility and may only depend on the layer directly below it. The canonical four-layer model has Presentation at the top, Application Services below it, Domain below that, and Data Access at the bottom.
The dependency rule is the defining characteristic. Arrows point downward only. The Presentation layer calls the Application Services layer. Application Services calls the Domain layer. The Domain layer defines interfaces that Data Access implements. No layer calls the layer above it. This one-directional constraint is what makes layering meaningful.
Eric Evans codified this pattern in Domain-Driven Design (2003), but the idea predates it significantly. The OSI model (1984), TCP/IP (1974), and UNIX shell architecture all use layering. Evans' contribution was applying it rigorously to application business logic and articulating why the Domain layer must be isolated from infrastructure concerns.
“The essential principle is that any element of a layer depends only on other elements in the same layer or on elements of the layers beneath it. Communication upward must pass through some indirect mechanism.”
Evans, E. (2003) - Part I, Putting the Domain Model to Work
Evans is describing strict layering. The phrase 'indirect mechanism' refers to events, callbacks, or observer patterns that allow lower layers to notify upper layers without importing them. If the Domain layer fires a domain event and the Application Services layer listens to it, the Domain layer never imports the Application Services layer. The arrow still points downward.
With an understanding of what layered architecture is in place, the discussion can now turn to benefits of layering, which builds directly on these foundations.
5.2 Benefits of layering
Separation of concerns. Each layer has one responsibility and one reason to change. The Presentation layer changes when the user interface or API contract changes. The Domain layer changes when business rules change. They are not coupled to each other's rate of change. In the NHS Spine case, the API standard migrated to FHIR while the clinical domain rules remained unchanged.
Independent testability. Because the Domain layer depends on nothing external, its business rules can be unit-tested without a database, without an HTTP server, and without any infrastructure. Tests run fast and reliably. The DVLA team reported that domain-layer tests ran 40 times faster after removing implicit database dependencies through strict layering.
Replaceability. When the Presentation layer imports nothing about the database and the Data Access layer imports nothing about the UI, each layer is replaceable independently. The NHS replaced its HL7 v2 API without touching the Domain layer. A team could replace PostgreSQL with Cassandra in the Data Access layer without touching the business rules.

With an understanding of benefits of layering in place, the discussion can now turn to layer violations and architecture erosion, which builds directly on these foundations.
5.3 Layer violations and architecture erosion
A layer violation occurs when a lower layer imports a class from a higher layer, or when code skips layers (the Presentation layer calling the Data Access layer directly). Both patterns introduce coupling that the layered architecture is designed to prevent.
Architecture erosion is the gradual accumulation of layer violations over time. It typically begins with a single "pragmatic shortcut": a controller that calls a repository directly to save one service call. Over months and years, these shortcuts multiply until the dependency graph is circular and the layers are in name only. Changing the database requires changes to controller code. Running domain tests requires a database connection. The benefits of layering are gone.
Static analysis tools detect layer violations automatically. ArchUnit (Java/Kotlin), Dependency Cruiser (JavaScript/TypeScript), and NetArchTest (.NET) all allow teams to write tests that fail if a layer imports from a layer it should not. These tests run in CI and prevent violations from being merged.
Common misconception
“Layered architecture prevents over-engineering by giving developers a clear structure to follow.”
Misapplying layers creates an anemic domain model: business rules leak into service classes because developers treat the Domain layer as a data container rather than the home of business logic. When domain entities have no behaviour and all business logic lives in service classes, the Domain layer provides no value. Layering prevents structural coupling; it does not prevent poor allocation of responsibility within a layer.
With an understanding of layer violations and architecture erosion in place, the discussion can now turn to strict versus relaxed layering, which builds directly on these foundations.
5.4 Strict versus relaxed layering
Strict layering requires that each layer communicate only with the layer directly below it. No skipping allowed. The Presentation layer cannot call the Data Access layer, even when it feels convenient.
Relaxed layering permits a layer to call any layer below it, not just the one immediately adjacent. The Presentation layer may call the Domain layer directly if there is no use-case logic needed. This trades structural purity for reduced ceremony in simple scenarios.
The NHS Spine system uses strict layering because the clinical Domain layer must be isolated from all presentation concerns for regulatory reasons. Martin Fowler's presentation-domain-data model uses relaxed layering in simpler web applications where an HTTP controller reading a database entity directly is a pragmatic choice that does not introduce meaningful risk.
Choose strict layering when the Domain layer contains certified, legally audited, or safety-critical logic that must be protected from infrastructure changes. Choose relaxed layering in CRUD-heavy applications where the business logic is thin and the risk of coupling is low. Document the choice in an ADR.
“The most common approach to managing this complexity is the three-layer architecture, with a presentation layer, a domain logic layer (sometimes called a business logic layer), and a data source layer.”
Fowler, M. (2002) - Patterns of Enterprise Application Architecture. Addison-Wesley. Chapter 1.
Fowler's three-layer model is the simplified version of Evans' four-layer model. Fowler combines Domain and Application Services into a single domain logic layer. This works well for simpler applications and is the basis of the Model-View-Controller (MVC) pattern that underpins most web frameworks including Rails, Django, and Laravel.

With an understanding of strict versus relaxed layering in place, the discussion can now turn to trade-offs and when layering falls short, which builds directly on these foundations.
5.5 Trade-offs and when layering falls short
Performance overhead. Strict layering means every user request traverses all four layers. Each layer transition involves object construction, mapping, and method calls. For high-throughput, low-latency APIs, this overhead is measurable. Some systems add a bypass route for read-only queries that go directly from Application Services to the database, bypassing the Domain layer. This is a deliberate trade-off, not a violation.
Anemic domain model risk. Martin Fowler identified this anti-pattern in 2003. It occurs when developers treat the Domain layer as a data-holding layer with getters and setters but no behaviour, and put all business logic in Application Services instead. The result looks like a layered architecture but behaves like a procedural system. The Domain layer provides none of the isolation benefits because it contains no logic to isolate.
Scalability limitations. Layered architectures are most natural for monolithic systems. When a system needs to scale horizontally with independent components, layering within a single codebase becomes an organisational bottleneck. Microservices and event-driven architectures address this by creating horizontal service boundaries, typically with layering within each service.
Common misconception
“You always need four layers. Any fewer is insufficient structure.”
Two-layer and three-layer designs are valid and often more appropriate than four layers. A simple web application with thin business logic works well with Martin Fowler's three-layer model (Presentation, Domain Logic, Data Source). Adding an Application Services layer for a system without complex use-case orchestration creates boilerplate without benefit. The principle is consistent downward dependency direction, not a specific number of layers.
With an understanding of trade-offs and when layering falls short in place, the discussion can now turn to testing the domain layer in isolation, which builds directly on these foundations.
Testing the Domain layer in isolation
When the Domain layer has no infrastructure dependencies, unit tests run without a database, without a web server, and without network access. The test output below shows a domain-layer test suite running in 47 milliseconds on an NHS Spine domain module.
A domain entity class imports a Spring MVC ResponseEntity class to format HTTP responses. ArchUnit flags this as a violation. Why is this a layer violation and what should change?
The NHS Spine team needs to migrate from HL7 v2 to FHIR for its external API standard. Which layers must change and which can remain unchanged?
A team builds a system where domain entities have no methods, only getters and setters. All business logic lives in large service classes. What anti-pattern does this describe?
Key takeaways
- Layered architecture organises code into horizontal tiers. The core rule is that dependencies point downward only: no layer imports from a layer above it.
- The four standard layers are Presentation (UI, HTTP), Application Services (use-case orchestration), Domain (business rules, entities), and Data Access (persistence). The NHS Spine system uses all four.
- Layer violations introduce coupling that destroys independent testability and replaceability. Static analysis tools like ArchUnit detect violations in CI before they are merged.
- Strict layering requires each layer to call only the layer immediately below. Relaxed layering allows skipping layers. Choose strict for safety-critical or legally certified Domain layers; choose relaxed for thin CRUD applications.
- The anemic domain model anti-pattern occurs when domain entities contain no behaviour and all business logic leaks into service classes. This defeats the purpose of having a Domain layer.
- Two-layer and three-layer models are valid. The principle is consistent downward dependency, not a mandatory layer count.
Standards and sources cited in this module
Evans, E. (2003). Domain-Driven Design: Tackling Complexity in the Heart of Software. Addison-Wesley
Chapter 4: Isolating the Domain
The definitive reference for strict four-layer architecture in domain-centric systems. Section 5.1 draws on Evans' formulation of the dependency rule and the rationale for isolating the Domain layer from infrastructure.
Fowler, M. (2002). Patterns of Enterprise Application Architecture. Addison-Wesley
Chapter 1: Layering, and the Presentation-Domain-Data pattern
The source for the three-layer relaxed model referenced in Section 5.4 and the Anemic Domain Model anti-pattern referenced in Section 5.5.
Fowler, M. (2003). AnemicDomainModel. martinfowler.com.
The named anti-pattern referenced in Section 5.5. Fowler argues that domain entities without behaviour are a symptom of misunderstanding object-oriented design, not a valid layered architecture.
ArchUnit documentation. ArchUnit.org.
The static analysis library used in the Terminal simulation in Section 5.3. Allows teams to write executable architecture tests that detect layer violations in CI.
NHS Digital. NHS Spine. digital.nhs.uk.
The real-world case study used in the opening and throughout the module. The four-layer architecture and the HL7 to FHIR migration are documented in NHS Digital's published technical architecture documentation.
What comes next: Layers organise code inside an application. But applications do not exist in isolation: they communicate with clients over HTTP. Module 6 covers the client-server model, request-response patterns, HTTP versions, and the real-time communication mechanisms that break the pull-based HTTP default.
Module 5 of 22 in Foundations