Clean Architecture

🗓️
🔄
6 min

This is no revolutionary idea per se, but rather Uncle Bob’s take on the similarities within existing architectural patterns. He saw a common thread between Ports & Adapters, Onion, EBI, plus a couple others and thought he would write an article as ‘an attempt at integrating all these architectures into a single actionable idea’.

Be Warned

I’ll take for granted you are familiar with the previously mentioned architectures going forward. If that’s not the case you’ll probably have a bad time.

High level

The original article starts with a diagram that can be simplified into this:

diagram

We can already see a couple of key points:

The diagram could drive some to structure the project directories like so:

Entities
├── Tenant
├── Landlord
├── Rent
Repositories
├── TenantRepo
├── LandlordRepo
├── RentRepo
UseCases
├── PayRent
├── RequestRent
├── RequestRepair
├── CalculateRent
...

However, as pointed out in this post, there are two glaring issues with this approach:

The following approach should solve these issues and is actually more in line with Uncle Bob’s Clean Architecture as a whole (you’ll see why in a bit):

Tenant
├── Tenant
├── TenantRepo
├── PayRent
├── RequestRepair
Landlord
├── Landlord
├── LandlordRepo
├── RequestRent
Rent
├── Rent
├── RentRepo
├── CalculateRent
...

Cool, let’s get to the actionable part of the idea.

Low level

To fully understand that’s going on, we’ll need more than the diagram presented in the original blog post. There’s another really useful one you can see in the slides Bob uses in his conferences.

bobs-flow

Again, really cool but a bit overwhelming. Let’s tone it down and build it back up bit by bit.

We’ll start from our entities and an Interactor. You should be familiar with this concept from what Bob calls ebi architecture.

base-diagram

In this context you can think of the Interactor as the core of a Use Case. So if a Use Case is an abstract concept of ‘what needs to be done’, the Interactor is the concrete implementation of ‘how exactly it should be done’.

Once our Interactor is done managing its use case, we’ll probably want to persist our entities.

add-persistence-port

I’m taking for granted you know what a Port is, why it implies an Adapter and the difference Driving and Driven ports (if not, click here). Since this one is driven, it’ll have blue borders.

Our Interactor will need some signal to tell it to do it’s thing.

add-input-port

This signal will come through some kind if input port (green borders mean it’s a driving Port). I don’t care much what that input is: the web, a cli or another piece of software.

Now we probably want to establish some sort of output as well. After all, whoever (or whatever) is using our system probably wants some feedback.

add-output-port

Lovely! So far we’ve got the basic I/O for our system. This includes what in the original diagram is described as the business logic and the application logic, so the two inner circles are taken care of.

Let’s make explicit what we already know.

arrows

We are slowly (but surely) completing the image!

Orange lines indicate inheritance while black ones indicate basic interaction.

Speaking of which, whatever input we receive through the Adapter will wind up interacting with our domain. This requires some kind of agreement between Interactor and Port regarding what sort of model (as in data structure, DTO, POJOs, etc) they’ll be passing around.

Same goes for the outbound side.

models

Let’s make the names more descriptive and clearly mark the edge of our domain.

final-diagram

I’m leaving the upper right part open on purpose, since for the same entities there might be any given number of Interactors (one per Use Case, sometimes more, sometimes less).

Let’s review how the flow of execution would go. Say we have an incoming HTTP request:

  1. The Request reaches the Controller.
  2. The Controller:
    1. Dismantles the Request and creates a Request Model with the relevant data.
    2. Through the Boundary, it executes a method in the Interactor, passing it the Request Model.
  3. The Interactor:
    1. Finds the relevant Entities through the Entity Gateway.
    2. Orchestrates interactions between entities.
    3. Creates a Response Model with the relevant data and sends it to the Presenter through the Boundary.

The diagram in the lower right corner of the diagram from the original post might help you visualize what’s going on.

Just swap ‘Use Case Output/Input Port’ for ‘Boundary’:

flow

You can get the feel now that, as far as Uncle Bob is concerned, a Use Case is made up of an Interactor and its Boundaries.

Speaking of Uncle Bob, hopefully you should now be able to better grasp the diagram we started from.

bobs-flow

Only thing we missed are the View and View Model.

The View Model is a part of whatever front-end/framework we are working with that is only in charge of basic logic regarding how to display the data it receives from the presenter.

The View here is nothing more than the raw data visualization. Html and css in your typical web facing API.

Now we can see the remaining key points not explicitly clear in the first diagram:

Conclusion

The original intent for this architecture was, as stated in Uncle Bob’s post, to create a system:

This is (hopefully) achieved by ‘standing on the shoulders of giants’, adding, clarifying and improving on some of the most important concepts in software architecture.


Other posts you might like