The concept of Clean Architecture was introduced by Uncle Bob in 2012.
The Clean Architecture is a practical architecture template developers can apply to many different application domains. All it takes is following some basic rules.
In this post, I explain the key elements of the Clean Architecture and show why they’re beneficial to Python developers.
What is the Clean Architecture?
Here are some defining characteristics of the Clean Architecture to help you understand what it is and why it’s worth your attention:
- Independent of frameworks - if you use Django, you probably realize how dependent your code is on the framework. The idea behind the Clean Architecture is that architecture shouldn’t depend on the existence of software libraries.
- Testable - your business rules can be tested independently of the interface, database, web server, or any other external element.
- Independent of UI - developers can change the UI quickly without changing the rest of the system. For example, a Web UI can be replaced with a console UI without changing the business rules. It would be even possible to switch to a different platform without changing the business rules, for example: from a mobile app to backend side application.
- Independent of Database - the Clean Architecture enables developers to switch from PostgreSQL to Mongo, CouchDB, or others. That way your business rules are never bound to the specific database. Moreover, it hides the fact you can have multiple sources of data, for example, two different databases and an external API.
- Independent of any external agency - don’t forget that your business rules ultimately don’t know anything about the outside world.
Here’s a diagram that illustrates different areas of software in the Clean Architecture scheme:
The closer you get to the yellow circle, the higher level the code becomes. Uncle Bob describes the inner circles as mechanisms and the outer circles as policies.
The general rule that makes the Clean Architecture work is The Dependency Rule. According to this rule, source code dependencies can only point inwards.
Elements located in the Entities circle (the enterprise business rules) should not refer to any elements outside of it (such as application business rules, interface adapters, frameworks, and drivers).
Data formats used in an outer circle should never be used by an inner circle, especially if they are generated by a framework in an outer circle. The Clean Architecture prevents anything in an outer circle to impact the inner circles.
Here’s a Breakdown of the Diagram
Entities - enterprise-wide business rules that reflect the highest level of business logic.
Use Cases - application-specific business rules, that’s the point where we focus on developing the functionalities of the application that support the rules contained in Entities.
Interface Adapters - a set of adapters that convert data from the format most convenient for the Use Cases and Entities to the format most convenient for an external agency such as a database.
Frameworks and Drivers - a combination of various frameworks and tools such as the database, web frameworks, etc. In general, that layer puts together code that communicates to the next circle inwards.
Naturally, these 4 circles are just schematic. The number of layers depends on many factors, (for example, the application type).
These layers need to communicate with each other. Look at lower right corner hand corner of the diagram - it describes how the communication between these different layers should look like.
How to Cross Circle Boundaries?
The flow of control begins with the Controller and then moves through the Use Case only to end up executing in the Presenter. Each source code dependency points inwards, toward the Use Cases.
When coding in a language like Java, developers aim to arrange interfaces and inheritance relationships in a way that the source code dependencies are in opposition to the flow of control, at the right points of the boundary.
But don't forget about the Dependency Rule (no name in an outer circle can be used in an inner circle) – that's why we see the Use Case call an interface and have the Presenter located in the outer circle implement it.
When passing data through these boundaries, developers should take extra care to make sure that the data structures are simple and isolated. They can't have any dependency that violates the Dependency Rule.
Why Implement the Clean Architecture?
Separating software into layers and following the Dependency Rule is in the interest of every developer who wants to create a robust, testable system that doesn't depend on external parts like frameworks and databases. When these become outdated, you can just replace them and have your system running in no time.
Getting familiar with these principles can help you avoid falling into the trap of blindly choosing the framework that breaks the Dependency Rule by design.