Sponsor: Do you build complex software systems? See how NServiceBus makes it easier to design, build, and manage software systems that use message queues to achieve loose coupling. Get started for free.
You’ve probably noticed many videos and blogs that somewhat explain what Clean Architecture is and show you how to use it. So its Clean Architecture is popular, but should it be? Should you be using it? Here’s why I think it’s popular, the problems it addresses, and some aspects that almost nobody ever mentions.
Check out my YouTube channel, where I post all kinds of content accompanying my posts, including this video showing everything in this post.
As a quick primer, what is clean architecture? Well, it’s a way to manage coupling. Specifically, in this diagram, you can see how the outer parts of the circle reference the inner parts of the circle. The dependencies between layers are pointing in a single direction inward.
It’s about managing coupling.
As an example, with the Clean Architecture template for .NET/C#, the project structure and dependencies are as follows.
The top (outer layer), called WebUI, is ASP.NET Core. It references an Infrastructure project that contains the entity framework DBContext and other concerns. The WebUI and Infrastructure reference the Application project, which contains the interfaces for implementations in the infrastructure and any application-level code, such as commands, queries, and handlers. Finally, the application project references the Domain project, which contains (or should) your domain models and business logic.
Sounds great. Separation of technical concerns. But why?
degree of interdependence between software modulesISO/IEC/IEEE 24765:2010
Systems and software engineering — Vocabulary
There are two forms of coupling Clean Architecture addresses. Afferent and Efferent.
Efferent Coupling: Who do you depend on? From the perspective of the Domain project, who does it depend on? Nothing.
Afferent Coupling: Who depends on you? From the same perspective of the domain project, which projects depends on it? The Application Project.
This is about stability. Because the Domain project has no dependencies, nothing can force it to change. All our business logic is isolated and cannot be forced to change because of a change within the infrastructure project or any other project. The reverse is true for WebUI. Changes we make in the infrastructure or Application could force us to make changes in the WebUI.
Do you need Clean Architecture?
It would be best if you asked yourself a few questions. What is the size of the application? Do I have complex domain logic? Do I need to control coupling?
Clean architecture is about forcing a direction of dependencies. In .NET, projects were used in the template above to force the separation. However, you do not need separate projects. Coupling is the dependence between types. If you merged the template into one project, you still have the same degree of coupling.
Do not use Clean Architecture as a prescription or template. Understand that you’re trying to manage coupling. It doesn’t need to be by projects. However, it can be to help with physical separation. It doesn’t need to be those exact layers. It’s not a prescription.
You should consider decomposing it into logical boundaries if you have a large system. What’s a large system? Something that takes a team of developers, possibly years to develop. I’ve covered this in many different blog posts and videos. Check out my post Microservices gets it WRONG defining Service Boundaries and Should you use Domain Driven Design? where I talk about logical boundaries. Logical boundaries are about grouping a cohesive set of capabilities within your system. It allows you to decompose a large system into smaller subsystems.
Why does this matter? When you break up a large system into smaller parts, you’ll realize that not all parts provide the same value. While all the boundaries are important, some are more in a supporting role and often built around CRUD (Create-Read-Update-Delete). This is also very similar if you’re creating a smaller app that may take a couple of weeks or months to develop.
If you have no domain logic, do you need to all the same layers as another part of your system that is at the core of the solution space and contains complex business logic? No.
This is why it’s not a prescription or template. Each boundary within a system has different concerns. If you don’t have any business rules, you have an underlying data model. Or perhaps you only have a dozen or so routes/endpoints that have data access. Do you need to add an abstraction to data access in that case? What if your database changes? Then change the 12 or so routes/endpoints!
Clean architecture is about coupling. There’s no prescription for the layers you define or how you define the coupling. You don’t need to define layers by projects. It’s about the direction of dependencies between types. Afferent and Efferent coupling are what define the stability of each layer. Do you need stability in a particular layer? Then maybe consider isolating it.
Developer-level members of my YouTube channel or Patreon get access to a private Discord server to chat with other developers about Software Architecture and Design and access to source code for any working demo application I post on my blog or YouTube. Check out my Patreon or YouTube Membership for more info.
- Microservices gets it WRONG defining Service Boundaries
- SOLID? Nope, just Coupling and Cohesion
- Should you use Domain Driven Design?