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're going to see what it is and at the end I'll share my opinion.

 

 

Note: The code linked here is not mine. It's a very popular Github project that's often used as a template for clean architecture.

 

1 - What is clean architecture?

To understand what clean architecture is, we first have to understand that it is an architecture focused on the domain. In other words, all dependencies point towards the domain.

 

clean architectureImage credit: Robert C Martin.

What this graphic shows is that your application is composed of layers, and any actions or changes happening in the outer layers do not affect the inner layers.

 

1.1 - How are layers divided in clean architecture?

For example, imagine you have a REST API and you want to migrate to gRPC, you would simply change the presentation layer (blue), and this wouldn’t affect the inner layers. That’s because the outer layer is always the entry point to your application, whether it’s an API, a desktop app, or a web app, it’s the entry point.

 

The second layer we see is identified as “interface adapters” (green), which is basically the data access layer, the layer that reads/writes to the database, the file system, or external services, for example via an API call, etc.

 

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

 

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

By the way, in this layer you can add rules. For example, imagine you have a to-do list app and you want to allow only one task per day, this rule can live in the domain layer without any issue.

 

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

 

 

1.2 - Dependencies in Clean architecture

But the most important part are the arrows you see, which indicate that the outer layers can reference the inner layers, but not the other way around. That’s why, as I said earlier, you can switch from REST API to gRPC by only modifying the outer layer.

 

And to me, this is the most important thing about clean architecture, especially the domain layer, because it’s our innermost layer and doesn’t depend on any other. This is really important, because as I mentioned, the domain layer is typically the entity framework entities (in .NET), but the layer actually interacting with the database is the application layer, which is a higher level and outside the business logic, as you can see here:

clean architecture in detail

What we do is define an interface in the application layer, which is then implemented by the infrastructure layer, which decides whether that means making a database call or calling an external service.

 

Although, in the case of .NET with Entity Framework, it’s very likely that you introduce an IDbContext and reference Entity Framework inside the application layer, which, in my opinion, isn’t really the best practice.

And why? Well, the idea of the interface is to abstract the implementation, but if we look at the sample code, you can 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... Theoretically we are abstracting the data layer away from the application layer, but even though we aren’t directly referencing it, we’re still importing the Entity Framework library into the application layer, which kind of defeats the purpose of the 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 might seem like it solves all problems. The first thing to keep in mind is that there’s no silver bullet, and that’s something we always need to remember.

The reality of clean architecture is that if your project is small, you're overengineering. Just look at the linked GitHub project as an example.

 

Inside each layer we have sublayers. For example, if we use MediatR, which is very common with clean architecture (I could write another post just about that), you'll have your command, your query, and your handler, and the structure of files and folders could look like this:

If the application is small, at first you don’t need all this and all you’re doing is creating folders, layers, and abstractions for the sake of being "clean architecture."

This is especially alarming when the app you’re building is 90% basic CRUD operations, and yet someone has decided to use clean architecture, especially in microservices, where most of them are just inserting what comes from the API after some basic validations.

 

Another very important point is that EVERYTHING goes behind an interface. Look, I’m the first one who uses interfaces, but not every type needs an interface (I could write another post just about that). Having so many interfaces means our tests depend too much on mocks (and the work that comes with them). And the abstraction behind the interface doesn’t really fix the issues, it usually just moves them elsewhere or creates new ones.

 

These problems also impact the most inexperienced team members, because clean architecture comes with a more or less steep learning curve. When you open a project and ask yourself, "What does it do? What are the features?" you don’t know right away, because everything is hidden behind folders like "services," "interfaces," "data,", everything is organized technically. And often, when a new person joins, the system can be hard to understand, and if it’s a big project, even a small change can be difficult to figure out where to implement.

 

My personal opinion is that, with so many layers, when a project grows it never remains as easy to maintain. (I’m sure someone will mention skill issues.) As I said, this is just my opinion based on my experience.

 

 

2.1 - When to use clean architecture?

When your project has a "rich domain," in other words, when you have a lot of logic in the business logic layer, when that logic is more than just grouping information and displaying it to the user, or just passing the request between layers and checking if one field is greater than X.

 

Domain rules are the key, since as mentioned earlier this is a domain-centric architecture.

That’s why, when I see "by the book" clean architecture in microservices systems, I lose my mind a little, because most of the time it really is just overengineering.

 

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

Uso del bloqueador de anuncios adblock

Hola!

Primero de todo bienvenido a la web de NetMentor donde podrás aprender programación en C# y .NET desde un nivel de principiante hasta más avanzado.


Yo entiendo que utilices un bloqueador de anuncios como AdBlock, Ublock o el propio navegador Brave. Pero te tengo que pedir por favor que desactives el bloqueador para esta web.


Intento personalmente no poner mucha publicidad, la justa para pagar el servidor y por supuesto que no sea intrusiva; Si pese a ello piensas que es intrusiva siempre me puedes escribir por privado o por Twitter a @NetMentorTW.


Si ya lo has desactivado, por favor recarga la página.


Un saludo y muchas gracias por tu colaboración

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

Buy me a coffee Invitame a un café