Understanding Clean Architecture
Discover the Essentials of Clean Architecture Through This Beginner-Friendly Guide
Clean Architecture is one of the most popular software architectures to help organize your source code.
Here is everything you need to get started with Clean Architecture!
Proposed by Robert C Martin, aka Uncle Bob, the Clean Architecture offers some significant advantages:
Independent of Frameworks: The architecture does not require some external libraries to work. It can stand on its own.
Testability: The business logic is independent of the web UI, Databases, and external sources so that it can be tested independently.
Separation of Concerns: Web UI, Databases, and Business logic are all separated into different layers, making the system modular and less interdependent.
High Cohesion and Low Coupling: All the layers specialize in their own domain and are not coupled to each other. Thus, any change in UI or databases will not affect the business logic and so on.
So, what is it that makes this architecture so powerful?
The answer to this question is the Dependency Inversion Principle.
The Dependency Inversion Principle is the main engine or the driving force behind any Layered Architecture.
Dependency Inversion Principle
The Dependency Inversion Principle basically states that:
High-level modules should not depend on low-level implementation details. Instead, they should depend on abstractions that are implemented by the low-level modules. Thus, inverting the direction of the dependencies.
Consider a traditional Asp.Net Webforms application. In such applications, business logic is strongly tied to the User Interface and Database.
Thus, any changes in the UI or database logic would force changes in the business logic as well.
However, with dependency inversion, we can separate the business logic from the user interface and database by separating them into individual layers.
These layers, instead of depending on each other, depend on abstractions. Thus, any change in one layer does not affect any other layer.
So far, there have been multiple implementations of Layered Architecture, including Hexagonal, Onion, Clean Architecture, and more.
Let’s dive deep into the Clean Architecture now.
Clean Architecture
If you google the term Clean Architecture, you will see a diagram somewhat like this one.
The diagram consists of concentric circles representing the different layers of the system.
As you get closer to the center, you will find high-level abstract details like the Domain Entities.
Moving outwards, you will encounter low-level implementation details like services, databases, etc.
Let’s have a look at what is inside each of these layers.
Domain Layer
At the heart of the system is the Domain Layer. The domain layer consists of the core business entities.
All the other layers in the system depend on the Domain layer and are there to support the Domain Layer.
Domain Layer itself does not depend on any other Layer.
Application Layer
Neighboring the Domain Layer is the Application Layer.
The Application layer is where all the magic happens. This is where your business logic resides.
Based on the business rules and regulations, this layer controls the flow of data to and from your business entities.
Generally, this layer consists of all your services, commands, queries, exceptions, logs, etc.
Infrastructure Layer
Next, we have the Infrastructure Layer. This is where all your external services and database logic are located.
All your external services, like email service, storage solutions, message queues, third-party API calls, etc., are handled by this layer.
Besides, it is also a common practice to separate database logic into its own Persistence Layer. This is where your DbContext and migrations, etc., will go.
Presentation Layer
Lastly, we have the presentation layer. This is the gateway or the entry point to your application.
This layer is responsible for presenting data to the end user in an easily understandable manner.
You will probably implement this layer as a Web or API project consisting of controllers defining the Action Methods or API endpoints.
So, these are the four layers in the Clean Architecture. But, now the question is:
Will there always be 4 layers?
The answer to that question is “No”.
You can always add more layers according to your requirements. The point of the layers is to organize and manage the source code.
For example, you may add a Common Layer at the center for storing static data like enums, magic strings, etc.
Or add a Storage Layer at the outermost to manage your storage in case you are using multiple storage solutions.
In short, there is no restriction on the number of layers you can add.
However, there is one principle that you must always follow. That is the Rule of Dependencies.
Rule of Dependencies
The rule of dependencies gives clear instructions about the direction of dependencies. It states:
Source code dependencies can only point from outside towards inside of the circle.
That means that no inner layer can know anything about the outer layers. Anything defined in an outer layer should not be visible to any inner layer.
So, how do the layers interact then?
It's simple. An inner layer defines an abstraction or an interface. The implementation of this interface is then provided by an outer layer.
That way, the inner layer doesn’t have to know about the outer layer and thus becomes independent of the implementation details.
Sounds good. But there is one more question remaining.
How do we transfer data between the layers?
Remember, we can not violate the Rule of Dependencies.
This implies we cannot directly pass data to and from layers using our domain entities.
Doing so would require the inner layer (Domain Layer) to know about the outer layers, violating the Rule of Dependencies.
So, instead of domain entities, we can create special Data Transfer Objects called DTOs to transfer the data between different layers.
DTOs must be simple data structures or objects containing the data required for an inner layer. You can also use immutable types like records for DTOs.
In the end, remember that software architectures are opinionated and very subjective. They are not a set of hard rules that must be followed.
Therefore, experiment with different architectures and feel free to make modifications to best suit your application.
After all, the goal of any architecture is to make clean, maintainable, testable, and scalable applications.
I hope you enjoyed this article. Let me know how you would structure your project for Clean Architecture. Feel free to share any insights!
PS: Check out my implementation of the Clean Architecture on my Github repo.
For now, it’s just the basic structure. Over the next few weeks, I will add different services and features to this project, like logging, dependency Injection, Authentication, CQRS, Emails, and more.
My goal is to make it into a starter template that is configured with all the necessary features that are a must in any modern application.
Feel free to follow along and share your suggestions.