Is Clean Architecture solely a Concentric Layered Architecture with an Inward Dependency Rule?
Let's delve deeper to understand the intent.
Clean architecture is appreciated for the separation of concerns & preventing complex software from becoming a big ball of mud. While the separation of concerns is the primary driver for clean architecture, it is done to switch the focus to higher-level software which is the business use cases — the reason why the application exists in the first place.
This intention is often overlooked, leading to the misconception of low use-case cohesion & additional complexity. In case you have also heard a similar opinion, read on as we delve into the history of Clean Architecture and clarify it.
Clean Architecture
Robert C Martin (Uncle Bob) has consistently mentioned the importance of slicing software as per features/use cases in his talks, blogs and the book — “Clean Architecture”. This aspect, however in my view, is often overlooked or misunderstood.
In the book “Clean Architecture”, chapter 22 — “The Clean Architecture” presents the architecture as a wedding cake with 4 concentric circular layers, where inner circles represent core business policies and outer circles represent mechanisms.
- Entities — This layer is core business rules. These rules would still exist if a clerk did it manually using a calculator or Excel.
2. Use Cases — This layer implements the use cases supported by the application & its the orchestration layer.
3. Interface Adapters — This layer isolates use cases from external mechanisms. For example, an ORM like EF Core for databases, controllers for APIs, or proxies for external services.
4. Frameworks & Drivers — These are mechanisms. For example database is a mechanism to store data, Kafka is a mechanism of async messaging, web API to deal with HTTP.
It is not necessary to have exactly 4 circles. But there is the dependency rule that must be honoured — which states that source code dependencies should point inward towards higher-level business.
i.e. The inner policies (higher-level business rules) should not be aware of the mechanisms.
The entire chapter 22, is also published in his blog — https://blog.cleancoder.com/uncle-bob/2012/08/13/the-clean-architecture.html
Having refreshed Clean Architecture, let's now address the misconception about use cases in clean architecture.
Overlooked aspect — Slicing by Usecase & Intention
Before publishing the book (or the article mentioned above), Uncle Bob published an article about Screaming architecture, emphasizing that the architecture should scream about the intention or use case — giving the analogy that a library architecture would be much different from a family house. And that by looking at the architectural blueprint this should become obvious.
In this article, he points out that good architecture emphasises the use case & decouples it from peripheral concerns. And that Frameworks are like bricks and materials but these are secondary concerns.
In the book, this screaming architecture is introduced in Chapter 21, just before presenting the clean architecture. The importance of slicing by use-case is introduced in Chapter 16.
So if we go by the book, and take a holistic view, clean architecture is not only about concentric layers & inward dependency rule but also about slicing layers as per use-cases/features. Similarly, in his talks clean architecture is preceded by screaming architecture.
Code Example
As an example, if we see Steve Smith’s Clean Architecture template https://github.com/ardalis/CleanArchitecture it does a great balancing job, it has code organized as per use-case within layers.
Conclusion
The clean architecture is all about shifting the focus to business & use cases (the reason why the application exists in the first place). It does so by separating infrastructure concerns from business logic & forcing the rule of depending inwards, towards the business core.
However, to appreciate the intent one needs to take a holistic view, looking only at Chapter 22 (or the blog) in isolation may create the misconception of technically oriented layers with low use-case cohesion.
As far as additional complexity is concerned, its contextual, but in software that lasts decades, it creates more robust boundaries. Without robust boundaries, it's easier for developers to do things wrongly & mix them up under constraints of time/knowledge.
When implemented correctly, it promotes high use-case cohesion by organizing the code in a way that each use-case is clearly defined and independent of other concerns. The separation of concerns helps maintain a clean and organized codebase, making it easier to manage and evolve over time.
Of course it has an overlap with “vertical slice architecture”. Practically, both “clean architecture” & “vertical slice architecture” can go hand in hand (they are not mutually exclusive), so it is of limited relevance from where the final architecture got its characteristics. And I’ll write another article on this.
References & Further Study
Screaming Architecture — https://blog.cleancoder.com/uncle-bob/2011/09/30/Screaming-Architecture.html
Clean Architecture — https://blog.cleancoder.com/uncle-bob/2012/08/13/the-clean-architecture.html
Clean Architecture template — https://github.com/ardalis/CleanArchitecture
Clean Architecture talk — https://www.youtube.com/watch?v=SxJPQ5qXisw