Uncle Bob, We've Failed You!
Ten years past, and are we still failing to understand Uncle Bob's "Clean Architecture" idea.
Introduction
In 2012, Robert C. Martin, or simply “Uncle Bob”, put together ideas from different resources and books of the time and he came up with a diagram that represented his idea of “clean architecture”:
(diagram by Robert C. Martin on his personal blog)
Since then, his diagram has been used many times by various tech writers and conference speakers. Some of the original ideas were slightly changed or enhanced, leading to different names for the resulting designs: For instance, you might find it labeled as “Hexagonal Architecture” or “Ports and Adapters”.
In his picture, we can see the big diagram with the colorful concentric circles that steals the show and is presented in every talk and article. Though, if we look carefully, we can notice the other, small, diagram in the bottom right corner. I believe that this small diagram, which is often overlooked is the missing piece of the puzzle, now, 10 years later.
Let’s discuss each of the two diagrams, in part, and explain why, in my opinion, focusing too much on the first one while ignoring the other is a problem.
The Dependency Rule
The first diagram is a visual representation of the “Dependency Rule”. This rule states that all the source code dependencies should point inwards. As a result, the Controllers will depend on our Domain Services, and they will depend on our Entities — which will sit at the center of our application.
In other words, our Entity objects do not know anything about the use cases, which, in turn, do not know about the framework. As a result, we will decouple the business rules and use cases from the framework and delivery mechanisms. I wrote a small article about it some time ago: if you want to dive deeper into this separation by layers, feel free to read through it.
This idea was largely accepted and adopted: we can see everywhere this Controller — Service — Repository layer separation. There is a small difference though: maybe you have noticed that the “Use Case” classes from the original diagram are replaced here by “Services”.
Unfortunately, this is not a simple change in the naming: the problem with the Services is that they make us focus on the data and not on the use case. And here is where the second diagram comes into play.
The “Screaming” Rule
I couldn’t really find a name for the second diagram, so I called it “The Screaming Rule”, but I believe this is pretty accurate — let me explain!
Uncle Bob stated on multiple occasions that the architecture of an application should scream at you what the application is all about. He even has a nice metaphor for it, saying that, when you see the blueprints of a building you can easily tell if the building is a church, a house, or a library. Similarly, the design of our software should shout banking, retail, or gaming, rather than Spring, .NET, or Flask. I highly encourage you to read his article where he goes as far as calling this design “The Screaming Architecture”.
The only way of achieving this expressive design is to put the use cases in front of the implementation details.
architecture should effectively convey intent— Photo by iam_os on Unsplash
The Common Approach
Let’s consider this simple example: we are building the backend application of a rock climbing gym and we need to support the following functionalities:
Create an account.
Create a climbing route.
View the climbing routes.
Attempt a route.
(Photo by Sabrina Wendl on Unsplash)
If we follow the common practices, we’ll probably end up with two controllers, two services, and two repositories. I believe everybody will be familiar with this structure:
If we’ll take a look at the RouteController we’ll notice that it is using the same RouteDto object for creating a new route and for retrieving the list of routes for the UI:
Let’s think about this: what are the implications? The endpoint for creating routes will be used by users who are part of the staff of the climbing gym. Meanwhile, the endpoint for viewing and filtering routes will be used by amateur climbers who are paying the membership to train in the gym.
What’s wrong with this? Different groups of users mean different responsibilities. Therefore, we are violating the Single Responsibility Principle.
Use Case Driven Approach
The mistake should be quite evident — we concentrated solely on layer separation and overlooked the use cases. Let’s revisit the diagram and determine the areas that require improvement.
copy of Robert C. Martin’s original diagram, from his personal blog
We can discern several key distinctions between Uncle Bob’s approach and our original method:
Each use case will have its own distinct Request and Response model.
Use cases may employ multiple entities.
We can have different use cases even if they utilize the same entity or group of entities.
Next, let’s restructure our project to align with these changes. Given that this is a small and straightforward application, rather than a large-scale enterprise project, I’ll simplify the concept by eliminating the additional interfaces:
Let’s examine how the CreateRoute and ViewRoute use cases would appear within this revised structure, compare them to the initial implementation, and evaluate the advantages that this approach offers:
As we can observe, each use case will now utilize its unique request and response model. This will enable us to append distinct attributes to specific requests and conceal particular fields from responses. For example, we can include pagination attributes within FindRoutes.Request without any impact on other use cases:
Conclusion
This article delved into the two primary aspects of Uncle Bob’s concept of clean architecture. We discovered that the “Dependency Rule” is widely embraced and implemented, while the “Screaming Rule” — which emphasizes the importance of placing use cases at the forefront — is not as popular.
We learned that implementing both rules results in more coherent code that conveys intent clearly and avoids the coupling of unrelated use cases.
Resources
If you want to dive deeper into what each of the components from the diagram is doing, I’ve got a video for you. In this talk, Uncle Bob provides an in-depth explanation of boundary objects, interactors, use case handlers and other interesting technical details:
Furthermore, here are the original blog posts about clean and screaming architecture:
https://blog.cleancoder.com/uncle-bob/2012/08/13/the-clean-architecture.html
https://blog.cleancoder.com/uncle-bob/2011/09/30/Screaming-Architecture.html