Clean Architecture is an architectural concept proposed by Robert C. Martin (commonly known as Uncle Bob) in 2012, with the goal of ensuring independence from databases and frameworks. The diagram below represents its iconic image.
Clean Architecture should be understood not as a "specific architectural pattern," but rather as "principles to follow in architectural design."
Before the introduction of Clean Architecture, approaches like Layered Architecture, Hexagonal Architecture, and Onion Architecture were widely known, all aiming to achieve "separation of concerns." Clean Architecture can be seen as a standardization that integrates these approaches.
As shown in the diagram above, Clean Architecture does not mandate a strict division into four layers: Enterprise Business Rules, Application Business Rules, Interface Adapters, and Frameworks & Drivers. This is merely an example. Robert C. Martin himself mentioned that "this diagram is just an overview, and Clean Architecture can have more than four layers."
The crucial point is "separation of concerns." To achieve this, important concepts such as "dependency rules" between layers and "dependency injection" play a vital role.
"Separation of concerns" refers to the idea that different elements of a system should have distinct roles and responsibilities. For example, business logic should exist independently of the database or UI. This enables each part of the system to be modified independently, such as changing the UI without affecting the business logic or changing the database without requiring a complete system rebuild.
In the "dependency rules," the direction of dependencies in the source code should always point inward (toward the business rules). The inner layers should be designed so that they do not depend on the outer layers (UI, database, frameworks).
Dependency Injection is a technique where the dependencies required by a class or component are provided from outside. This prevents a class from creating its dependencies or becoming tied to specific implementations. Using Dependency Injection makes it easier to manage dependencies and keeps the coupling between modules low.
By achieving "separation of concerns," the following benefits can be realized:
In this project, we adopt the following four primary layers:
This layer defines the most critical business rules and domain within the system. From a DDD (Domain-Driven Design) perspective, the Entity Layer is where domain models and important operations on the domain are defined. These entities are independent of other parts of the system and represent universal rules that are not dependent on specific applications or infrastructure.
The Entity Layer corresponds to Enterprise Business Rules in the Clean Architecture diagram.
This layer is responsible for implementing the technical details, such as databases and email sending. It abstracts the handling of data persistence and interaction with external systems so that other layers do not depend on technical details. For example, the details of database access are hidden within the Repository Layer, and other layers are unaffected by its specific implementation.
The Repository Layer corresponds to Frameworks & Drivers in the Clean Architecture diagram.
This layer is responsible for implementing specific use cases (business logic) provided by the system. It defines the system's behavior by utilizing entities and repositories. Use cases represent scenarios or processes to achieve specific business objectives and operate on entities.
Changes in the Usecase Layer are expected not to impact the entities. Additionally, this layer should remain independent of changes in databases, UI, or common frameworks. This layer is isolated from these concerns.
The Usecase Layer corresponds to Application Business Rules in the Clean Architecture diagram.
This layer is responsible for implementing the user interface (UI) and interaction with external systems. It defines the interfaces with the outside world, receives input from external sources, and delegates processing to the internal use cases or entities. It also returns processing results to the external world.
Changes in the Interfaces Layer are expected not to affect other layers.
The Interfaces Layer corresponds to both Interface Adapters and Frameworks & Drivers in the Clean Architecture diagram.
The dependencies between the layers are as follows:
[!NOTE] We allow the use of methods across layers (e.g., interfaces -> entity) as long as the direction of dependencies is correct. This is because strictly managing dependencies can lead to numerous conversions within each layer, potentially making the code more redundant.
[!NOTE] In this project, the Repository interface is implemented within the Repository Layer. Therefore, while it may appear that the Usecase Layer depends on the Repository Layer, it actually only depends on abstract interfaces, not concrete implementations. This approach adheres to the dependency rule. If you wish to manage dependencies more strictly, it is advisable to place the Repository interfaces as follows:
./domain/ ├─ entity/ └─ repository/
In progress of writing
In progress of writing