Getting Started with Clean Architecture using ASP.NET Core – 01

As we know, the maintenance operation is always more expensive than building the actual software. Whatever we do, the only thing, that never changes, is maintenance cost, isn’t it?

One of the most important things that will affect the cost is to choose software architecture. Based on past my experiences, as a series of two articles, I will try to mention some topics like “what we should consider in order to design a good architecture” and “what clean architecture is“.

Well,

Robert C. Martin describes a good architecture in the Clean Architecture book as follows;

Good architecture makes the system easy to understand, easy to develop, easy to maintain, and easy to deploy. The ultimate goal is to minimize the lifetime cost of the system and to maximize programmer productivity.

These are our main goals when designing an architecture, right? I think the importance of clean architecture begins with these goals. In my opinion, there are two basic concepts, that we should pay attention, in order to design a good architecture. These are “Coupling” and “Separation of Concerns“.

Let’s recall…

Coupling

Let’s briefly recall the definition of coupling. Coupling is a measure of the degree of dependence between modules. Modules are either loosely or tightly coupled to each other.

If we want to develop an application with good architecture, we should develop our application/modules as loosely coupled.

In a nutshell, modules should not be “tightly” coupled with each other. They must be easily “extendable” and “replaceable”.

Separation of Concerns (SoC)

Another important concept is the separation of concerns(SoC). The main goal here is to prevent handling different concerns, in one place. Actually this topic is highly related to the “Single Responsibility” principle.

For example, we might be handling data access operations or UI representation operations in the business logic. After a while, god classes that contain thousands of lines codes, and spaghetti codes come up.

I guess spaghetti is a good thing when we are able to eat it.

Such operations violate SoC. Remember, good architecture should be easily “maintainable”, “less coupled”, and easily “extendable”.

SoC is an important concept especially to be able to design a layered architecture. We should make sure that our modules are loosely coupled and as cohesive as possible, that is, the responsibility relation within a module should be as high and relevant as possible. They shouldn’t deal with different concerns.

Layered Architecture

I guess the layered architecture has a great place in the life of many software developers. At least for me, it really is.

One of the main principles behind the layered architecture is SoC. The goal is to prevent the database, domain or UI codes from getting mixed up and to separate their responsibilities.

Layered architecture usually comes in a form like the one above. The dependency flow here is from the presentation to the data access layer. In fact, although we try to provide SoC and loosely coupling, there is a hierarchy/dependency between layers.

One of the main principles behind clean architecture is Dependency Inversion principle. With this principle, it is possible to make components in our architecture more decoupled from each other and abstracted from certain technologies.

Let’s look at the picture from this point of view.

The concept that Uncle Bob calls “Clean Architecture” or the design that Alistair Cockburn calls “Hexagonal Architecture” is as above. It is a domain-centric design on which dependency inversion is applied.

Instead of a hierarchical flow from top to bottom, it places the application domain, which contains business logic and domain models, in the middle of the architecture as the core. It also reverses the dependencies of all modules. Dependencies always point inwards (core layer). We can think of it as a plug-in-based structure. Plug it, out.

This approach gives us the ability to easily extend, test and replace any part as we wish.

Why Clean Architecture?

  1. Hard to change: Usually, business needs never end. We always need to add new features to our application. If we don’t design a good architecture, it will be difficult for us to implement new features and changes and it could make the project more complex. In addition, our project becomes more fragile and harder to maintain.
  2. It is hard to test: In a poorly designed architecture, testability is also difficult. Either business logic is duplicated everywhere or intertwined with the UI, or the components are tightly coupled to each other. When the fragility is too high, extensibility becomes more difficult, and also it is difficult to see and test what is the impact of the changes on the project.
  3. Independent of databases, frameworks, and external libraries: Another important topic is to keep the core application domain layer as isolated from databases, frameworks or external libraries as possible. This approach will give us the ability to move forward with a different method and a different framework at any time.

Can you imagine we are trying to replace the scissors with a knife?

What is a well designed architecture?

We usually expect a well designed architecture to cover the following concerns.

  1. Testability: Each code/component parts, that we develop, must be easily tested individually.
  2. Maintainability: First of all, the sustainability of an application is more important. We should be able to perform maintenance operations easily.
  3. Extendability: We should be able to easily extend existing modules/components without breaking/modifying them.
  4. Reusability: The modules we have developed must be reusable.
  5. Readability: When a new developer joins the team, it is as important as the other elements that he/she can easily adapt to the project.

If we look at the above picture again, we can see it how it is more easy to replace the scissors with the knife without affecting the other tools.

Clean Architecture Concept

Well, now let’s look at the details of the clean architecture concept.

First, the Hexagonal architecture that we have seen below is an applied instance of clean architecture concept.

The “Application Domain” is the innermost core layer. The heart of the architecture. It doesn’t have any dependencies. It is located in the middle of the architecture and is isolated from other frameworks, databases, UI, etc. It mainly contains domain entities, use-cases and external interfaces.

There are also “input” and “output” ports around it. Implementations which are around it are called “adapter”. These adaptors implement ports.

Entities

  • Business objects of an application.
  • Should not be affected by anything.

Use-Cases

  • Each use case represents business actions.
  • They implement and encapsulate business rules.
  • Each use-case follows the single responsibility principle.
  • If a data needs to be accessed in a use-case, “input” ports should be used for it. Use-cases do not care where the data comes from.
  • In order to persist or send a data to anywhere, “output” ports should be used for it.

For example, if we look at the above project structure, there is a “MovieService” class under the “Services” folder. Well, what responsibilities are this service performing? Do you think is it clear enough?

Now let’s look at these services which are applying the single responsible use-case approach.

Under the “MovieUseCases” folder, there are “CreateMovieHandler” and “GetBestMoviesForKidsHandler” use-cases. Now their responsibilities are much more clear, right? God classes vs single responsible classes.

Interfaces/Adapters

  • These are implementations of interfaces that we define in the core layer.
  • It can be a part that will be responsible for persisting or retrieving a data. We can think it like a translator between “Domain” and “Infrastructure“.

Let’s take a look at the above picture again. We can see ports are interfaces that are defined in the domain layer in order to invert dependency.

The ones around are implementations of ports, called adapters. It can be a SQL Server in the “Infrastructure” part or a NoSQL implementation. It can be a Web UI in the “Presentation” part or a REST API.

As we can see the core domain layer locates the middle of the architecture completely as isolated and decoupled from the other modules and technologies. The whole dependency flow points to inward.

Last words…

At this point, I have tried to explain the “why clean architecture” topic and I tried to mention the general concept of it. I know this article a bit abstract, that the reason is in the next part of this article, I will mention about the implementation of clean architecture in .NET Core.

References

https://blog.cleancoder.com/uncle-bob/2012/08/13/the-clean-architecture.html
https://pusher.com/tutorials/clean-architecture-introduction
https://docs.microsoft.com/en-us/dotnet/architecture/modern-web-apps-azure/architectural-principles?WT.mc_id=DT-MVP-5003382

https://www.freecodecamp.org/news/a-quick-introduction-to-clean-architecture-990c014448d2/
https://slides.com/gokgokalp/aspnet-core-clean-architecture#/

Gökhan Gökalp

View Comments

  • Harika bir yazı olmuş. Uzun zamandır bu konuda bilgi ihtiyacı olan bir kişi olarak yazının tamamını bir solukta su içer gibi okudum. En sonunda en heyecanlı kısmında bitti :( Bir sonraki yazıyı sabırsızlıkla bekliyorum elinize sağlık. Ayrıca böyle bir konuda Türkçe kaynak kazandırdığınız için ayrıca tebrik ederim.

  • Türkçe kaynak bu konuda sıkıntılıydı, uzun zamandır yeni başlayacağımız bir proje için bu mimariyi inceliyorum. Sizin anlatımınızla bakmak da bloğunuzu takip eden ben açısından güzel oldu. Github'da Steve Smith'e sorduğum soruyu size de sormak isterim. Bu mimari db bağımsız diyoruz, okuyoruz ancak gerçek bir kullanım veya örneği yok. Yani hem redis, hem mssql hem de mongo kullanacaksak ne yapacağız? Teoride bir çok şey yerine oturmasına rağmen, pratikte herşeyi ayırmak adına birbirinin aynısı olmayan ancak birbirine aşırı benzer kodlar çıkmıyor mu?

    • Merhaba, öncelikle güzel yorumunuz için teşekkür ederim. Evet, eğer farklı ihtiyaçlar karşısında farklı service'ler kullanacaksak, onları da bir bir implemente etmek gerekiyor. En azından ben öyle yapıyorum. Dediğiniz gibi benzer kodlar/kod tekrarları ortaya çıkabiliyor, oradaki o ince ayrımı iyi yapmak gerekiyor bence. Hiç kod tekrarına düşmemek adına abstract yapa yapa bu seferde mimariyi over engineering yoluna doğru da itebiliyoruz açıkcası. Yer yer bu tradeoff'u seçmek gerekiyor sanırım. Independency vs Reusability? Kesin bir cevabı yok bence. :) Sizce?

  • Thank you very much for the nice and clean article. It's a good entrance to a very important subject, "clean architecture". We're waiting for the next part of this series. Don't make us wait too long :)

  • Çok yararlı bir kaynak kazandırmışsınız, tek solukta okudum. Çok teşekkürler. İkincisini beklemedeyim.

  • Paylaşım için teşekkürler, 2. makaleyi okumadan önce bunu yeniden okumak iyi oldu.
    Emeğine sağlık

Recent Posts

Securing the Supply Chain of Containerized Applications to Reduce Security Risks (Policy Enforcement-Automated Governance with OPA Gatekeeper and Ratify) – Part 2

{:tr} Makalenin ilk bölümünde, Software Supply Chain güvenliğinin öneminden ve containerized uygulamaların güvenlik risklerini azaltabilmek…

5 months ago

Securing the Supply Chain of Containerized Applications to Reduce Security Risks (Security Scanning, SBOMs, Signing&Verifying Artifacts) – Part 1

{:tr}Bildiğimiz gibi modern yazılım geliştirme ortamında containerization'ın benimsenmesi, uygulamaların oluşturulma ve dağıtılma şekillerini oldukça değiştirdi.…

8 months ago

Delegating Identity & Access Management to Azure AD B2C and Integrating with .NET

{:tr}Bildiğimiz gibi bir ürün geliştirirken olabildiğince farklı cloud çözümlerinden faydalanmak, harcanacak zaman ve karmaşıklığın yanı…

12 months ago

How to Order Events in Microservices by Using Azure Service Bus (FIFO Consumers)

{:tr}Bazen bazı senaryolar vardır karmaşıklığını veya eksi yanlarını bildiğimiz halde implemente etmekten kaçamadığımız veya implemente…

2 years ago

Providing Atomicity for Eventual Consistency with Outbox Pattern in .NET Microservices

{:tr}Bildiğimiz gibi microservice architecture'ına adapte olmanın bir çok artı noktası olduğu gibi, maalesef getirdiği bazı…

2 years ago

Building Microservices by Using Dapr and .NET with Minimum Effort – 02 (Azure Container Apps)

{:tr}Bir önceki makale serisinde Dapr projesinden ve faydalarından bahsedip, local ortamda self-hosted mode olarak .NET…

2 years ago