Key Architecture Principles from Clean Architecture Explained
This article distills the core concepts of the book “Clean Architecture,” outlining software system value, architecture goals, programming paradigms, design principles such as OCP, SRP, DIP, and practical guidelines for component splitting, dependency handling, and boundary design to build maintainable systems.
1. Software System Value
Architecture is part of a software system, so understanding its value requires clarifying the value of the software system itself. The system provides two kinds of value: functional (behavior) value and architectural value.
Functional value covers requirement implementation and usability guarantees such as functionality, performance, and stability, which occupy about 90% of engineers' work. When business is stable, architectural value can be ignored, but in fast‑changing environments architecture becomes crucial because it keeps the software “soft.”
When requirements change, the required software changes should be simple and convenient.
The difficulty of implementing a change should be proportional to the scope of the change, not to its shape.
If we focus only on functional value, we encounter the case described in the book: as the team grows, total lines of code stabilize while the cost per line of change rises, reducing productivity and increasing company costs.
The importance of architectural value is further illustrated by the urgent‑important matrix: urgent‑important tasks (behavioral value) are prioritized first, while architectural work (important but not urgent) should be inserted before coding.
2. Goals of Architecture Work
The goal is to satisfy system lifecycle needs with minimal human cost, making the system understandable, modifiable, maintainable, and easy to deploy. Specific goals per lifecycle stage include:
Development: avoid heavy scaffolding and unnecessary cross‑team collaboration.
Deployment: minimize scripts and configuration files; reduce component count.
Runtime: consider throughput and latency requirements; expose use cases and functions as clear entities.
Maintenance: lower exploration cost and risk when modifying code.
3. Programming Paradigms
Architecture imposes three fundamental restrictions: where source code resides, dependency rules, and communication methods. These correspond to three programming paradigms.
3.1 Structured Programming
Structured programming limits direct control‑flow transfers (e.g., goto) and proves programs using sequence, selection, and iteration structures.
3.2 Object‑Oriented Programming
OOP introduces encapsulation, inheritance, and polymorphism; polymorphism enables safe component communication and underlies dependency inversion.
In non‑OOP languages, function pointers achieve similar decoupling, as shown in the following C example:
struct FILE {
void (*open)(char* name, int mode);
void (*close)();
int (*read)();
void (*write)(char);
void (*seek)(long index, int mode);
}Using function pointers is fragile; OOP replaces them with interfaces and abstract classes.
3.3 Functional Programming
Functional programming emphasizes no side effects and immutable state, which helps avoid concurrency and dead‑lock issues. While a fully immutable system is unrealistic, separating mutable and immutable components can improve stability.
4. Design Principles
Design principles guide how to decompose software into components. Key principles include:
OCP (Open‑Closed Principle)
SRP (Single Responsibility Principle)
LSP (Liskov Substitution Principle)
ISP (Interface Segregation Principle)
DIP (Dependency Inversion Principle)
REP (Reuse‑Publish Equivalence Principle)
CCP (Common Closure Principle)
CRP (Common Reuse Principle)
No Dependency Cycle Principle
Stable Dependency Principle
Stable Abstraction Principle
Each principle is explained in the source text; for brevity they are listed here.
5. Basic Guidelines for Architecture Work
Two guiding rules:
Preserve as many optional choices as possible for as long as possible.
Use the lowest‑level decoupling method that solves the problem; avoid higher‑level solutions when unnecessary.
6. Component Splitting
A component is a set of strategies that transform inputs to outputs, sharing the same change reason, time, and level. Splitting occurs along two dimensions: hierarchy (business entity, use case, interface adapter, framework/driver) and change reason (e.g., order component, chat component).
7. Handling Component Dependencies
Dependencies should flow from lower‑level components toward higher‑level ones, decoupled from data flow. This enables independent swapping of frameworks, databases, or UI layers without affecting business logic.
8. Component Boundary Treatment
A complete boundary includes abstract interfaces for both sides, dedicated input and output data models, and possibly a gateway class. When possible, prefer incomplete boundaries (e.g., omit the final step, use one‑way boundaries, or apply the portal pattern) to reduce maintenance cost.
Boundary decoupling can be applied at source‑code, deployment, or service levels, with increasing cost and isolation.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
Alibaba International Technology
Founded in 1999, Alibaba International is a leading global cross‑border B2B e‑commerce platform serving millions of professional buyers and suppliers. Together with Alibaba Group’s other businesses, it advances the mission of “making it easy to do business anywhere.”
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
