“The universe is built on a plan the profound symmetry of which is somehow present in the inner structure of our intellect.” – Paul Valery
Clean Architecture is great! Let’s try that again…Clean Architecture is beautiful! Clean Architecture is symmetric! Clean Architecture is natural! Clean Architecture should really be common sense!
If you’re thinking about Uncle Bob’s wonderful collection of wise principles in the “Clean Code – A handbook of agile software craftsmanship” book then no, I’m not talking about that…I’m talking about (still Uncle Bob’s) Clean Architecture pattern.
It should be mentioned right up front that even if the pattern could somehow be stretched to the system architecture level (multiple tiers involving a physical separation of components running on different processes and/or different machines) it applies best to application architecture level (single process).
As good old Uncle Bob explicitly states, this pattern is a combo of all the positive aspects taken from Hexagonal Architecture (Alistair Cockburn), Onion Architecture (Jeffrey Palermo) and Screaming Architecture. (Uncle Bob).
All these patterns are largely based on DIP (Dependency Inversion Principle) and so is Clean Architecture. In fact, you can safely say that Clean Architecture is the structure that naturally emerges when truly applying DIP.
High level modules, low level modules…
DIP: “High level modules should not depend on low level modules. Both should depend on abstractions”
In the general business jargon “high level” refers to something more abstract, more general. By contrast “low level” means something more concrete, more detailed.
That’s exactly what DIP also means by “high level modules” and “low level modules”.
“High level modules” is about the most important part of an application implementation. It’s about the policies of the application, the general abstractions that govern the entire application; it’s about the truths that do not vary when the details are changed. It’s the implementation of application use cases, domain logic and even generic presentation logic and structure (view models).
By contrast, “low level modules” is about the details. These are generic technical mechanisms that support the high level modules: logging, OOM, ORM, email, sms…
Among the “high level” modules some are higher than others. E.g. the domain logic implementation is more abstract than application-specific use cases implementation (orchestration) which is more abstract than the generic presentation logic.
What’s wrong with Layers?
Layers violates DIP and by doing so it involves some unfortunate consequences.
For decades we have been structuring applications using Layers. For decades Layers have been synonym with good application architecture – you either had layers or you had the BBOM (Big Ball of Mud anti-pattern)
For decades we have claimed to fully apply SOLID but the truth is we did not. At most, we have been applying SOLI.
At least in the .NET world, Layers violates DIP by imposing a reference from the high level assemblies to the low level assemblies which are part of the Infrastructure layer:
Say I want to use Log4Net framework for logging in my application. Even if the code in my Application layer doesn’t use the Log4Net types directly but rather I provide an abstraction and a Log4Net specific implementation in my Infrastructure layer, my Application layer assemblies need to hold a reference to the Infrastructure assemblies which in turn need to hold a reference to Log4Net.dll. By doing so, my Application assemblies depend on Log4Net.dll even if not directly. Dependency is transient.
Once I have an abstraction in place I can of course change the logging technology by providing a new implementation of the abstraction without having to change the client code in my high level assembly (so no rigidity in this case) but reusing the high level assembly for multiple applications involving different details is always awkward.
How is Clean Architecture different?
Simply put, Clean Architecture conforms to DIP, Layers does not.
Clean basically concentrates the most important part of an application implementation in the core while it externalizes all the details.
The first three circles starting with the central Domain define the application core. Each of these is a collection of high level modules.
The outer-most blue circle is about the details. This is where everything that’s less important goes. This includes all the tools, frameworks and models that support the application core: a logging framework, an OOM mapping framework, a database, the file system, an ORM, a delivery framework such as ASP.NET MVC, WCF or Window Forms, the Web…If your app uses an ORM framework on top of a relational DB then the ORM is your detail in the blue circle. If you consume the DB engine directly through user code then the DB is your detail.
The green circle is the glue that connects the application core to the details that support it. Adapters are user code implementations that are specific to various details in the blue circle and that hide these away from the inner core circles.
If you look closer at the original description of this pattern you will notice four circles while I included five in the diagram above. That’s because I like to consider an extra circle in the core that is the generic Presentation layer.
This is about presentation logic and models that are not specific to any delivery technology. It includes various view models (data model that should be rendered to clients in various formats according to some delivery technology) and logical services that should forward calls to the use cases implementation in inner Application layer and convert the data from the format returned from Application layer to the appropriate view model.
The dependency rule
The powerful principle that makes this pattern work is called the dependency rule: “Source code dependencies can only point inwards”.
This is in fact a more pragmatic definition of DIP.
Say you’re application is using ASP.NET MVC as the delivery technology. This is a detail that is specific to a delivery model (html over Web) which is also a detail. Everything is part of the blue circle.
You define some controllers that subclass Controller class from ASP.NET MVC. This is an adapter that is specific to ASP.NET MVC and is part of your green circle. Your controller calls a Presentation service from the inner yellow circle. Source code dependencies do point inwards. That’s simple as the delivery framework is a detail that calls your app core.
But imagine your app also needs to use Log4Net for logging. This is a detail that your app core needs to call. How could your code call some service without holding a reference to some assembly where those types are defined? (Directly or indirectly) Same as any framework that your app uses can call your code without knowing it. That’s Inversion of Control and is the main characteristic that generally distinguishes a true framework from a class library.
Every piece of code in the core that needs some external service defines an abstraction for that service. The code for that abstraction belongs in the core, usually in the same assembly and same namespace with the code using it (maybe even in the same file). This abstraction is called a port.
Later, an adapter for the port is defined in the green circle. This is a class that implements the core abstraction and forwards the calls to the specific technology in the blue circle. (GOF – Adapter pattern – Object form) The assembly where the adapter is defined holds references to both the core assembly where the abstraction is defined and to the detail assembly in the blue circle. A concrete instance of the adapter type is injected at runtime using Dependency Injection in the core type that needs it. Core assemblies no longer need to hold references to anything but other core assemblies.
Dependencies have been inverted as compared to traditional layers model. In the true IOC spirit, your app core becomes a framework that’s being called and calls back various technologies through your adapters without knowing it.
Is it just about the dependency rule?
If you imagine an asymmetric model derived from classical Layers but conforming to DIP it would look something like the following:
The arrows represent source code dependencies not call chains.
The fact that Clean Architecture representation is symmetric using the concentric circles is not a coincidence. It may not be so obvious but it hides a very powerful principle: all the details are just details!
Clean Architecture focuses on the most important part of an application implementation. This is the application core and this is what DIP has been referring to as “high level modules” for over a decade. And from the point of view of the application core, the delivery framework is nothing more special than the database or the logging framework.
This is why Clean Architecture drives development towards a “domain out” approach and feels like a more comfortable house for Domain Driven Design in general. This is why delaying the decisions on technologies feels more natural when using the Clean Architecture. It’s the very mental model imposed by the concentric circles that makes you see the forest for the trees.
OK now what’s with the weird title?!
In my view, Cone Architecture is just a better metaphor for this type of software structure.
And yes, I came up with that term and no, it’s not popular.
It involves two different perspectives: if you look at it from above, you see some concentric circles governed by the dependency rule that source code dependencies can only point inwards. That’s a pure technical view.
But if you look at it from aside you can clearly see what DIP means by “high level modules” and “low level modules”. You can now clearly infer the layers hierarchy by their level of abstraction. The inner circles are higher level than the outer circles.
Volatility increases top-down while reusability decreases in the same direction.
In the context of this view, the dependency rule could be rephrased to something like “Source code dependencies should only point upwards”.
My initial mental model was that of a layered conical frustum since I liked the consistency of the shape of every layer but lately realized that a full cone is better for two main reasons: First of all it’s mnemonic. Secondly, the Domain layer is a special layer: it’s the heart of every application. It should really be sharp…