Clean Architecture Explained: Building Software That Lasts
As software systems grow, they often become harder to change, test, and maintain. Features take longer to ship, bugs become riskier to fix, and simple changes ripple across the entire codebase.
Clean Architecture addresses these problems — not as a specific framework or blueprint, but as a set of principles and practices for designing long-lasting software.
This article is based on “Clean Architecture: A Craftsman’s Guide to Software Structure and Design” by Robert C. Martin (Uncle Bob) and aims to explain the core ideas in a practical and accessible way.
What Is Clean Architecture?
Despite its name, Clean Architecture is not really an architecture in the traditional sense. Instead, it is a philosophy of software design focused on managing complexity and change.
At its core, clean architecture promotes systems that are:
- Easy to change and maintain
- Built from reusable components
- Highly testable
- Independent of frameworks, UI, databases, and external tools
In other words, your business logic should survive even if you replace your web framework, database, or user interface.
At the code level, clean architecture is deeply connected to clean code and the SOLID principles.
Clean Architecture and SOLID Principles
Clean architecture relies heavily on the SOLID principles, which guide how classes and modules should be designed:
- SRP — Single Responsibility Principle
A class should have only one reason to change. - OCP — Open/Closed Principle
Software entities should be open for extension but closed for modification. - LSP — Liskov Substitution Principle
Derived classes must be substitutable for their base classes. - ISP — Interface Segregation Principle
Clients should not be forced to depend on interfaces they do not use. - DIP — Dependency Inversion Principle
Code should depend on abstractions, not concrete implementations.
These principles keep code flexible, understandable, and resistant to change — key goals of clean architecture.
Components: The Building Blocks
In clean architecture, a component is the smallest unit that can be:
- Independently built
- Independently tested
- Independently deployed
Components are units of deployment, not just folders or namespaces. Designing good components requires clear rules about how they change, depend on each other, and get reused.
Component Principles
Clean architecture defines several principles that operate at the component level, much like SOLID does at the class level.
Common Closure Principle (CCP)
Classes that change together should be packaged together.
This is essentially SRP applied to components: a component should have one reason to change.
Common Reuse Principle (CRP)
Classes and modules that are reused together should live together.
If a consumer uses one part of a component, it should not be forced to depend on unrelated parts.
Reuse/Release Equivalence Principle (REP)
If something is reusable, it must be released as a unit.
Reusable components should:
- Be independently versioned
- Have clear release notes
- Be released as a whole
Grouping code together means releasing it together.
Acyclic Dependencies Principle (ADP)
The dependency graph of components should not contain cycles.
In other words, component dependencies must form a Directed Acyclic Graph (DAG). Cycles make systems hard to build, test, and reason about.
Stable Dependencies Principle (SDP)
Components should depend only on components that are more stable than they are.
Stability here refers to the likelihood of change, not runtime reliability.
A component that many others depend on is harder to change and therefore more stable.
Stable Abstractions Principle (SAP)
Stable components should be abstract.
The more stable a component is, the more it should rely on:
- Interfaces
- Abstract classes
This allows behavior to change without modifying the stable core.
Understanding Stability
A component is considered stable when many other components depend on it.
- More dependents → harder to change
- Harder to change → more stable
This has nothing to do with uptime or performance — it’s about change resistance.
Architectural Boundaries
Architectural boundaries separate components so that one side knows nothing about the internal details of the other.
Get Software Engineer Notes’s stories in your inbox
Join Medium for free to get updates from this writer.
They are achieved by:
- Independent compilation
- Independent deployment
Crossing boundaries (for example, calling another component) is considered an expensive operation and should be done intentionally.
A partial boundary exists when components are logically separated but still physically coupled in the same deployment unit.
What Is Architecture, Really?
Architecture is:
The way components are organized and interact with each other.
Good architecture:
- Makes development easier
- Makes maintenance cheaper
- Protects business rules from change
Its main purpose is to preserve options and delay irreversible decisions.
Architectural Patterns
Clean architecture does not replace existing architectural patterns. Instead, it can work with many of them, such as:
- Layered architecture
- Hexagonal (Ports & Adapters)
- Microservices
- Monoliths
- MVC
- Event-driven systems
- CQRS, Event Sourcing, SOA, and more
Clean architecture is about boundaries and dependencies, regardless of the chosen pattern.
Decoupling Modes
There are different levels of decoupling in a system:
- Source code decoupling
Changes in one module don’t require recompiling others. - Deployment decoupling
Changes don’t require redeploying the entire system. - Service decoupling
Independent services communicate over the network and can evolve separately.
Each level provides more flexibility but comes with higher operational cost.
The Clean Architecture Model
Clean Architecture is often visualized as concentric circles:
- Entities — Core business rules (most stable and abstract)
- Use Cases — Application-specific business logic
- Interface Adapters — Controllers, presenters, gateways
- Frameworks & Drivers — UI, database, frameworks, external tools
Outer layers are mechanisms.
Inner layers are policies.
The Dependency Rule
The most important rule in clean architecture:
Source code dependencies must always point inward.
- Inner layers know nothing about outer layers
- Business rules are protected from infrastructure changes
- Frameworks become replaceable details
Higher-level components must not depend on lower-level ones.
Testing and Clean Architecture
Clean architecture makes testing easier by isolating business logic from external systems.
A key concept here is the Humble Object Pattern.
Humble Object Pattern
It separates code into:
- Hard-to-test parts (UI, frameworks, external resources)
- Easy-to-test parts (logic, rules, calculations)
For example:
- Views are humble objects and should be simple
- Presenters or use cases contain logic and should be fully testable
As Uncle Bob famously said:
A program can be proven incorrect by a test, but never proven correct.
Final Thoughts
Clean architecture is about discipline, boundaries, and respect for change.
It helps you build systems that:
- Outlive frameworks
- Resist unnecessary rewrites
- Are easier to test and evolve
It’s not about perfection — it’s about designing software that can grow without collapsing under its own weight.
Let me know in the comments what do you think about the clean architecture nowadays. Is is outdated or state-of-the-art architecture to follow? 👇
References & Further Reading 📚
- Clean Architecture — Robert C. Martin
- https://blog.cleancoder.com/uncle-bob/2012/08/13/the-clean-architecture.html









