Story of Clean Architecture

vencheang heng
6 min readOct 17, 2023

--

Problem:

Upon joining Prudential insurance, My manager presents me number of challenges our team were facing, My initial task was to understand and determine areas for improvement in our development process.

For context we are a multi regional team, There’s 4 regions of software engineers that contributes to the whole code base ( Cambodia, Lao, India and Singapore). I spend months studying and observing our development process.

Whenever we aimed to launch similar products in different markets, or when updates to our infrastructure were necessary, our confidence plummeted. The key factors contributing to these issues were:

Standardization: When people work in the same office or in a small team, I think it’s easier to just come up to someone and have a friendly talk with them or you can discuss an idea over lunch, But as everyone works in different place and time, It becomes a barrier, Communication will be missed, Things start to get very disorganized, Some developer will have their own way of writing, or practice. So without a set of principles or specific guidelines that we all understand and follow. The code base easily becomes a mess.

Reusability: As the project grows chances are newly add features also need a piece of code that we have implemented, But since we mostly have it in one file. We often taking the pain of rewritten the same thing over and over again.

Flexibility: Imagine if we have 5 controller that directly initiate httpClient, Now for some reason, we need to add new configuration to this httpClient, we will have to go back and rewrite all 5 file. And plus the time to re tests everything, Since we don’t have unit test, Manually test can be a pain in the ass.

Scalability: With the challenges above, scaling our system to meet increasing business demands became Chistopher Nolan’s Tenent spy mission.

Journey:

After identifying these issues, It was evident that we needed a better architectural approach, we don’t just need a freshly solution but something that back by a strong community. Luckily we’re living in area where every information is just a click away from our fingers. So upon joining I set out to get my hands on articles, podcast and books about Software Architecture as much as I could. I get to learn stories from other engineer about how a specific architecture solved their specific problem, what’s the benefits or drawbacks.

The one that came across and got a wide support of community and resonate with my team the most is Clean Architecture by uncle bob. I think it check all the box of problems we’re facing.

What is Clean Architecture?

Clean Architecture is a set of design principles that aims at creating systems that are both robust and maintainable. These principles guide the organization of code in such a way that it remains decoupled, testable, and independent of external agents like UI, Databases, And frameworks. This architectural approach is largely driven by the Dependency Rule, which ensures that dependencies always point inwards, towards the core business logic.

https://blog.cleancoder.com/uncle-bob/images/2012-08-13-the-clean-architecture/CleanArchitecture.jpg

Layers in Clean Architecture

In the Clean Architecture, the system is organized into layers, each with its own set of responsibilities. These layers form a concentric circle pattern, with the most fundamental and high-level rules in the center and more detailed and low-level details towards the outer circles.

1. Domain (Entities, Models, Enterprise Business Rules )

2. Application Business Rules (Use Cases)

3. Interface Adapters (Controllers, Presenters, Gateways)

4. Infrastructure (UI, Web, Database, External Interfaces, HTTP, API)

https://www.ezzylearning.net/wp-content/uploads/Clean-Architecture-1.png
Overall Structure

Domain

These represent the core business rules and are the most crucial part of the system. They should be independent of any external influences, which means they shouldn’t be affected by changes in the database, UI, or any external systems.

Responsibilities:

- Define the core business operations.

- Capture the most high-level rules applicable to the business domain.

- Typically do not involve any kind of I/O operations.

Example: If we’re building an Hotel Booking system, an entity could be an “Room” with core business operations like “Number of bed” and “Air Conditioner or Fan”

Domain

Application Business Rules (Use Cases)

These define specific use cases or scenarios for the system. They coordinate and sequence the flow of control, and they can depend on entities but must not rely on any external elements like databases or external api call.

Responsibilities:

- Handle specific application operations.

- Orchestrate the flow of data between entities and the outer layers.

- Should remain free from any framework or UI-specific code.

Example: “MakeReservation” would be a scenario where we might check for if the room has already occupied, or Date is pasted etc

Application

Presentation (Controllers, Presenters, Gateways)

This layer sits between the use cases and the outermost layer. It translates data between the two, serving as an adapter.

Responsibilities:

- Convert data from the format most convenient for use cases and entities to the format most convenient for some external agency like the web or a database.

- Include things like controllers, APIs, presenters, and database operations.

Example: A “UserController” might accept an HTTP request, extract the necessary data, and then call the appropriate use case.

Infrastructure (Frameworks, Web, Database, External Interfaces)

This is the outermost layer and is responsible for handling the interfaces to external systems.

Responsibilities:

- Handle interactions with external systems or frameworks (e.g., web servers, databases, HttpClient, API Call).

- Implement the actual input/output operations, like calling to external API or database access.

- Any changes in this layer should not affect the inner layers.

Example: This can include the code for a web-based user interface, a SQL database driver, or a third-party API integration.

Infrastructure

Responsibilities and Primary Purpose of Each Layer

In summary, each layer has a distinct purpose:

1. Domain: Capture the core business logic and rules.

2. Application: Define specific application scenarios and coordinate interactions.

3. Presentation: Translate and adapt data between the inner and outer layers.

4. Infrastructure: Interact with external systems, tools, or frameworks.

Principles of Clean Architecture

Clean Architecture revolves around several foundational principles. These principles aren’t new, and they have been the bedrock of good software design for decades. Together, they ensure that the software remains flexible, scalable, and maintainable.

  • Single Responsibility Principle (SRP)
  • Open-Closed Principle (OCP)
  • Liskov Substitution Principle (LSP)
  • Interface Segregation Principle (ISP)
  • Dependency Inversion Principle (DIP)

Reconciliation:

As engineers, we understand that no single solution fits all scenarios perfectly. One potential drawback of this architecture is its inherent complexity, even for seemingly simple endpoints. A junior developer or intern might struggle with it, leading me to believe that this architecture might be best implemented by a team of experienced developers. For smaller teams, this complexity could pose more of a hindrance than a benefit, slowing down the development process rather than accelerating it. Even for experienced developers like us, determining the correct placement for various components can spark lengthy debates. The time required to add new components or features is another factor to consider. Nonetheless, I am satisfied with our results so far, and I remain hopeful and curious about identifying potential flaws as we continue to use and understand this architecture in our future work.

--

--