Clean Architecture

πŸ—“οΈ
β€’
πŸ”„
β€’
⏳ 3 min

This is part of a series, start here!



This is Uncle Bob’s attempt at synthesize previous architectural patterns and concepts.

Based on a common thread between Ports & Adapters, Onion, EBI, he wrote an article as β€˜an attempt at integrating all these architectures into a single actionable idea’.1

High level

The original article starts with a diagram similar to this:

diagram

Project structure

At face value, the diagram seems to suggest a project structure as such:

Entities
β”œβ”€β”€ Tenant
β”œβ”€β”€ Landlord
β”œβ”€β”€ Rent
Repositories
β”œβ”€β”€ TenantRepo
β”œβ”€β”€ LandlordRepo
β”œβ”€β”€ RentRepo
UseCases
β”œβ”€β”€ PayRent
β”œβ”€β”€ RequestRent
β”œβ”€β”€ RequestRepair
β”œβ”€β”€ CalculateRent
...

There are however a couple of shortcomings here:

Borrowing some key concepts like Bounded Context from DDD, the previous system can be represented as such:

Tenant
β”œβ”€β”€ Tenant
β”œβ”€β”€ TenantRepo
β”œβ”€β”€ PayRent
β”œβ”€β”€ RequestRepair
Landlord
β”œβ”€β”€ Landlord
β”œβ”€β”€ LandlordRepo
β”œβ”€β”€ RequestRent
Rent
β”œβ”€β”€ Rent
β”œβ”€β”€ RentRepo
β”œβ”€β”€ CalculateRent
...

Low level

There’s a pretty useful diagram in the slides Bob uses in his conferences.

bobs-flow

Cool, but a bit overwhelming. Let’s start with Entity and Interactor2 and build the diagram with concepts from other notable architectures.3

diagram-1

Think of the Interactor as the implementation of a use case of the application.

Thanks to Ports & Adapters, we know that a use case should be defined as an abstraction to ensure inwards dependency.

diagram-2

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 will happen’.

Entities usually require some sort of persistence, we can use a Driven Port/Adapter pair for that.

diagram-3

Let’s also represent the actor that will use the Driver Port from before, as well as the data structure (DTO) that will be shared between it and the Interactor.

diagram-4

The controller could just as well be a CLI or a GUI.

Using a DTO here allows us to avoid exposing the Domain Entities outside the boundaries of the application. Speaking of boundaries.

diagram-5

The red line marks the limit of our application logic and separates it from the pieces of the system that are necessarily coupled to the Infrastructure.

Now suppose that, when something happens in the system, we want to notify the user or update a UI element.

diagram-6

Or using Uncle Bob’s terminology:

diagram-7

With this, we are back to his original diagram.

Let’s review how the flow of execution would go for 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, triggers the Interactor
  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 first image on the original post might help visualize what’s going on.

flow

Swap β€˜Use Case Output/Input Port’ for β€˜Boundary’.

Footnotes

  1. From the original article ↩

  2. From the EBI architecture ↩

  3. Start here ↩


Other posts you might like