This post is part of The Software Architecture Chronicles, a series of posts about Software Architecture. In them, I write about what I’ve learned on Software Architecture, how I think of it, and how I use that knowledge. The contents of this post might make more sense if you read the previous posts in this series.
Robert C. Martin (AKA Uncle Bob) published his ideas about Clean Architecture back in 2012, in a post on his blog, and lectured about it at a few conferences.
The Clean Architecture leverages well-known and not so well-known concepts, rules, and patterns, explaining how to fit them together, to propose a standardised way of building applications.
Standing on the shoulders of EBI, Hexagonal and Onion Architectures
The core objectives behind Clean Architecture are the same as for Ports & Adapters (Hexagonal) and Onion Architectures:
- Independence of tools;
- Independence of delivery mechanisms;
- Testability in isolation.
In the post about Clean Architecture was published, this was the diagram used to explain the global idea:
As Uncle Bob himself says in his post, the diagram above is an attempt at integrating the most recent architecture ideas into a single actionable idea.
Let’s compare the Clean Architecture diagram with the diagrams used to explain Hexagonal Architecture and Onion Architecture, and see where they coincide:
Externalisation of tools and delivery mechanisms
Hexagonal Architecture focuses on externalising the tools and the delivery mechanisms from the application, using interfaces (ports) and adapters. This is also one of the core fundaments of Onion Architecture, as we can see by its diagram, the UI, the infrastructure and the tests are all in the outermost layer of the diagram. The Clean Architecture has exactly the same characteristic, having the UI, the web, the DB, etc, in the outermost layer. In the end, all application core code is framework/library independent.
In the Hexagonal Architecture, we don’t have anything explicitly telling us the direction of the dependencies. Nevertheless, we can easily infer it: The Application has a port (an interface) which must be implemented or used by an adapter. So the Adapter depends on the interface, it depends on the application which is in the centre. What is outside depends on what is inside, the direction of the dependencies is towards the centre. In the Onion Architecture diagram, we also don’t have anything explicitly telling us the dependencies direction, however, in his second post, Jeffrey Palermo states very clearly that all dependencies are toward the centre. The Clean Architecture diagram, in turn, it’s quite explicit in pointing out that the dependencies direction is towards the centre. They all introduce the Dependency Inversion Principle at the architectural level. Nothing in an inner circle can know anything at all about something in an outer circle. Furthermore, when we pass data across a boundary, it is always in the form that is most convenient for the inner circle.
The Hexagonal Architecture diagram only shows us two layers: Inside of the application and outside of the application. The Onion Architecture, on the other hand, brings to the mix the application layers identified by DDD: Application Services holding the use case logic; Domain Services encapsulating domain logic that does not belong in Entities nor Value Objects; and the Entities, Value Objects, etc.. When compared to the Onion Architecture, the Clean Architecture maintains the Application Services layer (Use Cases) and the Entities layer but it seems to forget about the Domain Services layer. However, reading Uncle Bob post we realise that he considers an Entity not only as and Entity in the DDD sense but as any Domain object: “An entity can be an object with methods, or it can be a set of data structures and functions.“. In reality, he merged those 2 innermost layers to simplify the diagram.
Testability in isolation
In all three Architecture styles the rules they abide by provide them with insulation of the application and domain logic. This means that in all cases we can simply mock the external tools and delivery mechanisms and test the application code in insulation, without using any DB nor HTTP requests.
As we can see, Clean Architecture incorporates the rules of Hexagonal Architecture and Onion Architecture. So far, the Clean Architecture does not add anything new to the equation. However, in the bottom right corner of the Clean Architecture diagram, we can see a small extra diagram…
Standing on the shoulders of MVC and EBI
The small extra diagram in the bottom right corner of the Clean Architecture diagram explains how the flow of control works. That small diagram does not give us much information, but the blog post explanations and the conference lectures given by Robert C. Martin expand on the subject.
In the diagram above, on the left side, we have the View and the Controller of MVC. Everything inside/between the black double lines represents the Model in MVC. That Model also represents the EBI Architecture (we can clearly see the Boundaries, the Interactor and the Entities), the “Application” in Hexagonal Architecture, the “Application Core” in the Onion Architecture, and the “Entities” and “Use Cases” layers in the Clean Architecture diagram above.
Following the control flow, we have an HTTP Request that reaches the Controller. The controller will then:
- Dismantle the Request;
- Create a Request Model with the relevant data;
- Execute a method in the Interactor (which was injected into the Controller using the Interactor’s interface, the Boundary), passing it the Request Model;
- The Interactor:
- Uses the Entity Gateway Implementation (which was injected into the Interactor using the Entity Gateway Interface) to find the relevant Entities;
- Orchestrates interactions between Entities;
- Creates a Response Model with the data result of the Operation;
- Populates the Presenter giving it the Response Model;
- Returns the Presenter to the Controller;
- Uses the Presenter to generate a ViewModel;
- Binds the ViewModel to the View;
- Returns the View to the client.
The only thing here where I feel some friction and do differently in my projects is the usage of the “Presenter“. I rather have the Interactor return the data in some kind of DTO, as opposed to injecting an object that gets populated with data.
What I usually do is the actual MVP implementation, where the Controller has the responsibility of receiving and responding to the client.
I would not say that the Clean Architecture is revolutionary because it does not actually bring a new groundbreaking concept or pattern to the table.
However, I would say that it is a work of the utmost importance:
- It recovers somewhat forgotten concepts, rules, and patterns;
- It clarifies useful and important concepts, rules and patterns;
- It tells us how all these concepts, rules and patterns fit together to provide us with a standardised way to build complex applications with maintainability in mind.
When I think about Uncle Bob work with the Clean Architecture, It makes me think of Isaac Newton. Gravity had always been there, everybody knew that if we release an apple one meter above the ground, it will move towards the ground. The “only” thing Newton did was to publish a paper making that fact explicit*. It was a “simple” thing to do, but it allowed people to reason about it and use that concrete idea as a foundation to other ideas.
In other words, I see Robert C. Martin is the Isaac Newton of software development! 🙂
2012 – Robert C. Martin – Clean Architecture (NDC 2012)
2012 – Robert C. Martin – The Clean Architecture
2012 – Benjamin Eberlei – OOP Business Applications: Entity, Boundary, Interactor
2017 – Lieven Doclo – A couple of thoughts on Clean Architecture
2017 – Grzegorz Ziemoński – Clean Architecture Is Screaming
17 thoughts on “Clean Architecture: Standing on the shoulders of giants”
Great post, I have a question…
The one thing annoying me is the lack of an arrow between the Controller and the Presenter. In your list of points, from The controller will…. starting at #5 Uses the presenter, the controller is the coordinator now of the remainder of the interaction.
So why is there no arrow? is the Controller somehow not dependant on the Presenter? Does it not also have to have knowledge of the view?
Also, without using DI of some kind…. where are we wiring up the the (injected) concrete interactor? There must be something in the system which is at the outermost layer which instantiates this controller… but most often you see the controllers are instantiated directly from the framework layer.
Hi, tkx for your comment.
Yes, you are correct, there is a connection missing. I think its because the slides that Uncle Bob uses only shows a piece of the puzzle at a time so whoever put those pieces together (it wasn’t me, I was gonna do it but found it on the internet) didn’t add that connection.
I think what is missing there is a dependency from the controller to the interface/boundary implemented by the presenter. If the presenter encapsulates the template/view then the controller doesn’t need to know about it, but it depends on the implementation.
The way the wiring of these code artifacts is not really a direct concern of this visualization. But yes that orchestration needs to be done somewhere, and I always do it with a DIC through some configuration.
I appreciate your response! I never thought about the presenter encapsulating the view, but that’s an interesting implementation. It would require the output boundary interface contained a method which could be implemented by the presenter and called by the controller, but I really like the concept, so thanks.
Yes, DI container is almost a pre requisite. However I have toyed with the idea of each endpoint of a rest API as a special type of main method to wire everything together without a container.
In what language do you do it and what type of applications? (Microservices, enterprise monolith, …)
In his book “Clean Architecture” Uncle Blob also writes about the “Main component” which is doing all the wiring. he also shares a picture which explains the missing arrows. in that picture the “Main component” injects the view into the presenter, the presenter into the interactor (via output port interface) and the controller gets the interactor … at least this is how i read the picture …
Great post. Nice summary of Uncle Bob’s architecture and comparison to similar ones. After having read his book recently I decided to try it out in one of my projects and to blog about my learnings here: https://plainionist.github.io/Implementing-Clean-Architecture/ I would be interested in your feedback. Thx
Cool that u are also writing about it, I have the book but I’m currently quite busy, didn’t have the time to read it yet.
I will put your blog on my reading list and will let you know when I get to it. 🙂
Cool 🙂 thx
maybe u can also help me to understand one point for which I couldn’t find any answer yet: https://stackoverflow.com/questions/48589192/dependency-from-gateway-to-framework-in-clean-architecture
Thx a lot again for the discussion. I finally found the time to discuss this aspect in detail in my recent post:
Hopefully this is of interest for others as well
I have one question, let suppose I have an entity (I understand entity as objects that retain domain rules) and it is not managed by a persistence layer. How should I create it inside a use case given that it is not managed by EntityGateway.
Should I :
1 – Inject this domain object into use case;
2 – Create a factory to it;
3 – Instantiate inside use case;
Each alternative above has pros and cons.
How do you proceed?
To answer your question, i need to clarify that i understand entities as objects that retain domain rules and state. If it has domain rules but no state, i call it a domain service, and if it contains use case logic and no state, then i call it an application service.
Back to your question, if it is a domain service, i would inject it into the use case (application service), if it is what i call an entity i would create it in the use case.
Usually i only use a factory (to instantiate a new object), or a resolver (to get something out of the container), when i need to decide what object to use at run time, for example based on a user profile options.
Does this answer your question? 🙂
LikeLiked by 1 person
It does, thanks. 🙂