Clean Architecture

Software Engineer at heart. Tech Lead by craft. With 16+ years in software engineering, I solve complex problems and enable the delivery of a continuous and efficient flow of value.
Search for a command to run...

Software Engineer at heart. Tech Lead by craft. With 16+ years in software engineering, I solve complex problems and enable the delivery of a continuous and efficient flow of value.
No comments yet. Be the first to comment.
The promotion we didn't expect

A reflection on my leadership journey

The art of crafting clean repositories

I've worked in unstructured, Waterfall, and Agile software processes since 2009. One I found ineffective is 'Waterfall in sprints', confused as Agile. When I saw a meme about it, I realised it's a common Agile anti-pattern. Here, I'll unpack what I m...

Architecture is the art of drawing lines. A cheeky definition. I think of architecture as how concerns are separated and the rules that govern them. The lines we draw tend to depict this perspective. Clean Architecture is my go-to for source code. Here, I explain the gist of it and how I've made it my own.
There may be many clean architectures (in lowercase) out there. The one I'm referring to is Uncle Bob's Clean Architecture. Hence the capitals.
Ivar Jacobsen's ideas (Object-Oriented Software Engineering: A Use Case Driven Approach) influenced it. And it resembles Alistair Cockburn's Ports & Adapters (Hexagonal) Architecture.
Fun fact: Uncle Bob and Alistair Cockburn are two of the Agile Manifesto's seventeen authors. Legends. Let's explore their architectures.
Clean Architecture is about the separation of concerns. In particular, the separation of business rules from I/O concerns.
Business rules may not know about (depend on) I/O concerns. I/O concerns may know about the business rules.
Input/Output (I/O) concerns are how your application gets and outputs data. It's the delivery mechanism of the data.
API endpoints, database integrations, integration to downstream systems or services (APIs), and user interfaces are all I/O concerns. Ways data flows into and out of your application.
Think of business rules as what the system must do, independent of I/O (data delivery) details.
Business rules include the code for use cases.
For example, consider a use case that says: 'A user must enter their email and password to register'. Notice it doesn't include I/O details — like capturing it in a React frontend, sending it to a .NET API, or saving it in a SQL database.
Very demure.
Let's look at some lines.

A prominent architectural boundary separates the business rules and I/O concerns. Notice how the source-code dependencies only cross the boundary in one direction: from the I/O side to the business rules.
How can a business-rule service call a class in an I/O layer if it's not allowed to depend on it? By inverting source code dependencies such that it points against the flow of control.
Instead of making a business rule service call an I/O class, we make it call a business rule interface. An I/O class implements that interface. Notice how the 'DbService' class implements the 'Repository' interface.
At runtime, an Inversion of Control (IoC) framework will 'plug' an instance of the I/O class into the interface, which acts as a port.
Ports & Adapters (Hexagonal) Architecture works the same. It also has an interface at the point where an I/O concern calls a business-rule service.

There are two types of ports:
Adapters are the classes in the I/O layers that implement the ports.
Suppose the database needs to be replaced by a downstream API. In this architecture, we let a class in the integration (to downstream APIs) layer implement the secondary port instead. No other code changes needed!

The business rules are the central organising principle. It drives the design.
Suppose you add a feature that'll include multiple layers. I recommend you start at the business rules layer. Develop and unit test it completely, first. Thereafter, add the other layers.
Try not to start at the I/O layers. Especially the database one! Its internal structure (such as a SQL database's relational model) may 'peer pressure' the business rules into looking and acting like it.
Clean Architecture reduces the long-term cost of software by making code easier to understand and change.
Here's the logic:
Clean Architecture does this with how it separates concerns.
My Millennial and Gen Z peers and I built MonoLISA on the principles of Clean Code and Clean Architecture. MonoLISA guides how we do Clean Architecture in our backend monorepos.
Not only did we solve our problems. But we contributed to this school of thought, too. We understood the assignment!
Clean Architecture. Ports & Adapters. MonoLISA. It's how we enable ourselves and our AI tooling to quickly understand and change code, with precision.