Clean Architecture | Explanation and Opinion

Since I've been asked quite a bit, in this post we're going to see what clean architecture is, today we'll discuss what it is and at the end I'll give my opinion.

 

 

Note: the code linked is not mine; it's a very popular GitHub project often used as a template for clean architecture.

 

1 - What is clean architecture?

To understand what clean architecture is, we first need to understand that it’s an architecture focused on the domain. Or in other words, all dependencies point toward the domain.

 

clean architectureImage from Robert C Martin.

What this chart aims to show is that your application is composed of layers, and actions or changes happening in the outer layers don't affect the inner layers.

 

1.1 - How are the layers divided in clean architecture?

For example, imagine you have a Rest API and you want to migrate to grpc. You simply change the presentation layer (blue), and this doesn't affect the inner layers. The outer layer is always the entry point to your application, whether that's an API, a desktop app, or a web app; it's the entry point.

 

The second layer is called "interface adapters" (green), which is just the data access layer. It's what will query/insert into the database, the file system, or external services, for example through an API call, etc.

 

The third layer is the use cases layer. For example, in a typical application, it’s very common to use mediatr in these projects, so commands, queries, and handlers will be found there. Basically, it's where the logic for each scenario is.

 

The central (yellow) layer is the domain layer, which in most cases will be the database entities. In the case of .NET, these are the entities of entity framework.

By the way, in this layer we can put rules. For example, imagine you have a to-do app, and you only want to allow one task per day. That business rule can be enforced in the domain layer, no problem.

 

This means that the business logic layer, when using clean architecture, is the two innermost layers: the application layer and the domain layer.

 

 

1.2 - Dependencies in Clean architecture

But the most important part is the arrows you can see, because this means that outer layers can reference inner layers, but inner layers must not reference outer layers. That's why, like I said before, you can change your rest API to grpc by only modifying the outer layer.

 

And for me, this is the most important part of clean architecture, especially where the domain layer comes in, because it is our inner layer, and depends on nothing else. This is important to keep in mind, because as I mentioned, the domain layer contains the entity framework entities (in most .NET cases), but the layer that actually makes the database calls is the application layer, which is a higher layer and actually outside of business logic, as you can see in this other diagram:

clean architecture in detail

What you do is, in the application layer you define an interface, which will then be implemented by the infrastructure layer (which is responsible for deciding whether it’s a database call or an external service call).

 

Well, in the .NET case with entity framework, it's very likely you'll put an IDbContext and have entity framework referenced within the application layer, which, in my opinion, isn't best practice.

Why? Well, the idea of the interface is to abstract implementation, but if we look at the code example, we see the following interface:

public interface IApplicationDbContext{    DbSet<TodoList> TodoLists { get; }    DbSet<TodoItem> TodoItems { get; }    Task<int> SaveChangesAsync(CancellationToken cancellationToken);}

 

And what does it contain? A DbSet... In theory we are abstracting the data layer from the application layer, but even though we're not referencing it directly, we're importing the Entity Framework library into the application layer, which, well, kind of defeats the purpose of abstraction.

clean architecture breaking abstraction

 

 

2 - Do I need clean architecture in my application?

Quick answer: Probably NOT.

 

Now let’s see why.

 

In practice, clean architecture may seem like it solves all problems. The first thing we have to keep in mind is that there is no solution that solves everything, and that's something we always need to remember.

The reality of clean architecture is that if your project is small, it’s just over-engineering. To prove it, look at the linked GitHub project.

 

Within each layer we have sublayers. For example, if we use mediatr, which for some reason is very common in clean architecture (and that’s material for another post), we’re going to have commands, queries, and handlers, and the structure of the files and folders may look like this:

If the application is small, you really don’t need all of this, and all you do is create folders, layers, and abstractions for no other reason than to justify the use of "clean" architecture.

This is especially alarming when the app you’re building consists 90% of basic CRUD operations, and for some reason, someone has decided to apply clean architecture. This is especially relevant in microservices, where many are just inserting what comes in from the API after doing some basic validations.

 

Another very important point is that EVERYTHING is behind an interface. Look, I am the first to use interfaces, but not every type needs an interface (another topic I could dedicate a post to). Having so many interfaces causes our tests to depend too much on mocks (and the work that entails). On top of that, the abstraction we have behind the interface doesn’t solve the problems; usually, it either moves them somewhere else or creates new ones.

 

These problems also get passed on to less experienced team members, because deep down, clean architecture has a relatively high learning curve. When you open a project and you ask yourself what does it do? What are the functionalities? Well, you don’t really know at first, because everything is hidden behind folders named “services”, “interfaces”, “data”, that is, everything is organized technically. And many times when someone new joins the system, it can be hard to understand, and if it’s a big project, a small change can be hard to know where to make it.

 

My personal opinion is that with so many layers when a project grows, it never stays as maintainable as promised. (I'm sure someone will mention skill issues.) As I said, this is my opinion based on personal experience.

 

 

2.1 - When to use clean architecture?

When your project has a “rich domain,” or in other words, when you have a lot of business logic in the business logic layer(s), when the logic goes beyond simply grouping information and displaying it to the user, or when updating is more than just passing requests between layers and checking if a field is greater than X.

 

Domain rules are what matter most since, as I mentioned earlier, it’s a domain-centric architecture.

That’s why, when I see "by the book" clean architecture in microservice systems, it really bothers me, because the majority of the time it’s just over-engineering.

 

This post was translated from Spanish. You can see the original one here.
If there is any problem you can add a comment bellow or contact me in the website's contact form

© copyright 2025 NetMentor | Todos los derechos reservados | RSS Feed

Buy me a coffee Invitame a un café