From DDD’s Four‑Layer Model to Clean Architecture: Tracing the Evolution of Layered Design
The article examines how software architecture has progressed from the traditional DDD four‑layer structure through Hexagonal, Onion, and Clean architectures, explaining essential versus accidental complexity, layering principles, dependency inversion, and how each pattern refines modularity, testability, and dependency direction.
What Is Architecture?
Architecture is defined as the means to manage and reduce a system’s core complexity, which consists of essential complexity (the inherent business logic) and accidental complexity (technical and structural overhead). Essential complexity cannot be eliminated, only managed, which DDD addresses through domain concepts and bounded contexts.
DDD Four‑Layer Architecture
The traditional DDD four‑layer model includes:
User Interface Layer : Presents information and interprets commands for users, programs, tests, or scripts.
Application Layer : Thin layer handling use‑cases and orchestration; it coordinates multiple aggregates from the domain layer.
Domain Layer : Implements core business logic via entities, value objects, aggregates, and domain services. Entities use a rich (anemic) model; when a single entity cannot fulfill a function, a domain service composes multiple entities.
Infrastructure Layer : Provides technical services such as databases, messaging, caching, and third‑party tools.
In this loose layering, higher layers may directly depend on the infrastructure layer, which can hinder testing and violate layering principles.
Improving the Four‑Layer Model
Applying the Dependency Inversion Principle (DIP) reverses the direction of dependencies: higher‑level components define abstract interfaces, and lower‑level services implement those interfaces. This yields a strict layering where each layer only depends on the one directly below it, simplifying testing and change propagation.
Hexagonal (Ports & Adapters) Architecture
Introduced by Alistair Cockburn in 2005, this style separates the application core from external tools via ports (abstract contracts) and adapters (implementations). Primary (driving) adapters such as Controller handle input, invoke the core through a ServiceInterface, and secondary (driven) adapters implement the ports (e.g., JpaUserRepositoryImpl, RedisCacheAdapter). The flow is
Controller → ServiceInterface → ServiceImpl → Repository.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
Architectural Methodology
Guides senior programmers on transitioning to system architects, documenting and sharing the author's own journey and the methodologies developed along the way. Aims to help 20% of senior developers successfully become system architects.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
