Clean Architecture is Screaming

Welcome to the fifth installment of little architecture series! So far we have covered layers, hexagons, onions and features. Today, we’ll look at a close friend of all four – Uncle Bob’s Clean Architecture, initially introduced here.

What is Clean Architecture?

Clean Architecture builds upon the previously introduced four concepts and aligns the project with best practices like Dependency Inversion Principle or Use Cases. It also aims for a maximum independence of any frameworks or tools that might stay in the way of application’s testability or their replacement.

The Clean Architecture divides our system into 4 layers, usually represented by circles:

  • Entities, which contain enterprise-wide business rules. You can think of them as about Domain Entities a la DDD.
  • Use Cases, which contain application-specific business rules. These would be counterparts to Application Services with the caveat that each class should focus on one particular Use Case.
  • Interface Adapters, which contain adapters to peripheral technologies. Here, you can expect MVC, Gateway implementations and the like.
  • Frameworks & Drivers, which contain tools like databases or framework. By default, you don’t code too much in this layer, but it’s important to clearly state the place and priority that those tools have in your architecture.

Between the circles, there is a strong dependency rule – no code in the inner circle can directly reference a piece of code from the outer circle. All outward communication should happen via interfaces. It’s exactly the same dependency rule as we introduced in the Onion Architecture post.

Apart from the layers, Clean Architecture gives us some tips about the classes we need to implement. As you can see in the picture below, the flow of control from the Controller to the Use Case goes through an Input Port interface and flows to the Presenter through an Output Port interface. This ensures that the Use Case and the user interface are properly decoupled. We’ll see an example of this later in the implementation section.

The Essence of Clean Architecture

I see two things that make Clean Architecture distinct and potentially more effective than other architectural styles: strong adherence to Dependency Inversion Principle and Use Case orientation.

Strong Adherence to DIP

Similarly to its Onion cousin, Clean Architecture introduces the Dependency Inversion Principle at the architectural level. This way, it explicitly states the priorities between different kinds of objects in your system. In a way, Clean Architecture does a better job at this, as it leaves no doubt about the tools like frameworks or databases – they have a dedicated layer outside all others.

Use Case Orientation

Similarly to what we’ve seen in Package by FeatureClean Architecture promotes vertical slicing of the code and leaving the layers mostly at the class level. The major difference between the two is that instead of focusing on a blurry concept of a feature, it reorients the packaging towards Use Cases. This is important as, ultimately, in any application that has some sort of GUI, one could identify real Use Cases. It’s also important to note that entities sit in a different layer as in complex systems, one Use Case can orchestrate several entities to cooperate and categorizing it by the type of the entity would be artificial.

Implementing Clean Architecture

We can’t be 100% sure about how Uncle Bob would implement a Clean Architecture today, as his book about it comes out in July (I preordered it already and will do a review or rehash of this post then), but we can look at the GitHub repository of his Clean Code Case study:

Packaging

As you can see, the Entities and Use Cases layers have their own separate packages, while the other layers can be identified only conceptually. The  socketserver , http and view packages can be considered a part of the Frameworks & Drivers, while gateways package is a little bit ambiguous – their implementation is surely the Interface Adapters layer, but their interfaces conceptually belong to Use Cases. My guess is that the interfaces are extracted to a separate package so they can be shared between different Use Cases. But it’s just a guess!

By looking at the usecases.codecastSummeries, we can get more insight into how a complete Use Case package looks like. As you can see, it accommodates all classes related to the execution of a particular Use Case: the view, controller, presenter, boundaries, view and response models, and the Use Case class itself.  This might be a lot more classes than you usually see in your projects when you execute an Application Service, but that’s what it takes to go perfectly Clean.

Internals

If you dug deeper into the implementation of the project’s classes, you’d see no annotation there other than @Override. That’s because of the frameworks being at the very outer layer of the architecture – the code is not allowed to reference them directly. You might ask, how could I leverage Spring in such a project? Well, if you really wanted to, you’d have to do some XML configurations or do it using @Configuration and @Bean classes. No @Service, no @Autowired, sorry!

My Extra Advice

Pulling off a Clean Architecture might be a demanding task, especially if you worked with a Package by Layer, fat controllers kind of project before. And even if you get the idea and necessary skills to implement it, your colleagues might not. They might want to do this anyway, but simply forget to add interfaces or work around framework annotations when necessary. One way to prevent some of these issues could be to create a Maven module for each of the layers so that breaking a rule won’t even compile. At the same time, if you don’t have these already, introducing Pair Programming or Code Reviews will help you to prevent people from messing up with the dependency declarations (circular dependencies would not work, but adding Spring both to the Use Cases and Adapters module would!).

Benefits of a Clean Architecture

  • Screaming – Use Cases are clearly visible in the project’s structure
  • Flexible – you should be able to switch frameworks, databases or application servers like pairs of gloves
  • Testable – all the interfaces around let you setup the test scope and outside interactions in any way you want
  • Could play well with best practices like DDD – to be honest, I haven’t seen it so far, but I also don’t see anything stopping you from making an effective mix of DDD’s Strategic and Tactical Patterns with Clean Architecture

Drawbacks of Clean Architecture

  • No Idiomatic Framework Usage – the dependency rule is relentless in this area
  • Learning Curve – it’s harder to grasp than the other styles, especially considering the point above
  • Indirect – there will be a lot more interfaces than one might expect (I don’t see it as necessarily bad, but I’ve seen people pointing this out)
  • Heavy – in the sense that you might end up with a lot more classes than you currently have in your projects (again, the extra classes are not necessarily bad)

When to use Clean Architecture

Before I say something, let me note that I haven’t tried implementing it in a professional context yet, so all of it is a gut feeling. We will probably get some more knowledgeable advice from Uncle Bob himself in his upcoming book.

If we consider Clean Architecture‘s biggest drawbacks and it’s essence, I would derive the following criteria to consider:

  • Is the team skilled and/or convinced enough? One might consider this lame, but if people just don’t get it or they don’t want to do this, imposing the rigor of Clean Architecture on them might be counter-productive.
  • Will the system outlive major framework releases? Since we’re talking about heavy technology flexibility here, it’s important to consider if we’ll ever capitalize on this benefit. My experience so far suggests that most systems will, even if the developers won’t be in the company by then.
  • Will the system outlive the developers and stakeholders employment? Since Clean Architecture is so sound and makes Use Cases so clearly visible, systems that follow its principles will be much simpler to comprehend in the code, even if those who wrote it and asked for it are already gone.

Summary

Clean Architecture looks like a very carefully thought and effective architecture. It makes the big leap of recognizing the mismatch between Use Cases and Entities and puts the former in the driving seat of our system. It also gives a clear place for Frameworks & Drivers in our system – a separate layer outside all other layers. This, combined with the dependency rule might give us a plethora of benefits, but also might be way harder to pull off. In the end, it boils down to the question whether the system will live long enough so that the investment returns.

About the Author Grzegorz Ziemoński

King of Tidy Java, nerd that thinks about producing perfect software all the time and proud owner of 2 cats.

follow me on:
  • Sandor Agafonoff

    Nice post on this great pattern. I am currently undertaking the implementation of this into a ‘fat’ controller application where I have begun working. I am also responsible for setting the example for the other 3 developers, and I have had both keen willingness and reluctance from my colleagues. For the same reasons as you pointed out, the increased number of interfaces and classes. My argument for this is simply that it is not bad, and is the core factor which will allow the decoupling of the business code from the frameworks which it currently derives from.

    One ‘when to use this style’ I think you missed, is one of my main driving factors, testing. You mentioned it in the benefits though. If you can write more tests, you can automate your testing, and if you can automate your testing, you can get better at continuous integration and if you can do that, you can start practicing continuous delivery, meaning the time it takes you to get features into production will rapidly decrease.

    In our current application state, it is impossible to test the code without running the web server and database etc… so essentially, there are no unit tests, only integration tests, and while some would argue this is better, they are slow to execute, and will only get slower over time. This means with complex controller logic, and only partial tests, that bugs are prevalent, as you would expect. So this means more time debugging!

    While on the other hand, when switching to the Clean style, I am actually able to write the entire functionality, using a mocked database and presenter without even opening a web browser, the tests I can write, tell me it’s working, so I can write functionality much faster, regardless of writing 4 extract interface classes (whats that, 20 lines of code? really only 4 lines to write since the IDE generates everything except the method signature.) and I spend less time debugging. In the end, it’s not about saving time, but its about changing the things you spend time doing. I’d rather be creating value than chasing bugs.

    Anyway, great post. Thanks again.