Key Takeaways from Clean Architecture: A Practical Summary
This article distills the core concepts of Robert C. Martin’s Clean Architecture, covering layered design, SOLID principles, component cohesion and coupling rules, boundary strategies, the onion model, and why databases are merely infrastructure, all illustrated with concrete code examples and diagrams.
1. Book Overview
Book: Clean Architecture by Robert C. Martin (Uncle Bob), published in 2017. The core theme is how to build simple, maintainable, and testable software architectures.
2. Core Idea: Layered Architecture
2.1 Layer Diagram
┌─────────────────────────────────────────────────┐
│ Presentation Layer │
│ (Controllers, Gateways, UI) │
├─────────────────────────────────────────────────┤
│ Use‑case Layer │
│ (Application Business Rules) │
├─────────────────────────────────────────────────┤
│ Domain Layer │
│ (Enterprise Business Rules) │
├─────────────────────────────────────────────────┤
│ Infrastructure Layer │
│ (Frameworks, Drivers, DB) │
└─────────────────────────────────────────────────┘2.2 Core Principles
The dependency direction is always inward:
Presentation layer depends on the Use‑case layer; the Use‑case layer does not know about the Presentation layer.
Use‑case layer depends on the Domain layer; the Domain layer does not know about the Use‑case layer.
Domain layer has no dependencies on any other layer.
Key point: Dependencies may only point inward; outward dependencies are prohibited.
3. SOLID Principles
3.1 Single Responsibility Principle (SRP)
Definition: A class should have only one reason to change.
Bad example:
// Violates SRP: class has multiple reasons to change
class User {
void saveUser() { /* database operation */ }
void sendEmail() { /* email sending */ }
void generateReport() { /* report generation */ }
void calculateSalary() { /* salary calculation */ }
}Correct example:
// Each class has a single responsibility
class UserRepository { void saveUser() { } }
class EmailService { void sendEmail() { } }
class ReportGenerator { void generateReport() { } }
class SalaryCalculator { void calculate() { } }3.2 Open/Closed Principle (OCP)
Definition: Software entities should be open for extension but closed for modification.
Bad example: Adding a new payment method requires modifying existing code.
// Bad: modify code to add new functionality
class PaymentService {
void pay(String type) {
if (type.equals("alipay")) { /* Alipay logic */ }
else if (type.equals("wechat")) { /* WeChat logic */ }
// Add new payment? Change here!
}
}Correct example: Extend via new classes that implement a common interface.
interface Payment { void pay(); }
class Alipay implements Payment { void pay() { } }
class WechatPay implements Payment { void pay() { } }
class NewPay implements Payment { void pay() { } }3.3 Liskov Substitution Principle (LSP)
Definition: Subtypes must be replaceable for their base types.
Bad example: A Square class inherits from Rectangle and overrides setWidth in a way that breaks the rectangle contract.
// Square violates LSP
class Rectangle { void setWidth(double w); void setHeight(double h); }
class Square extends Rectangle {
void setWidth(double w) { this.width = w; this.height = w; // violates LSP
}
}Solution: Use an interface that represents the shape.
interface Shape { double getArea(); }3.4 Interface Segregation Principle (ISP)
Definition: Clients should not be forced to depend on interfaces they do not use.
Fat interface example:
interface Worker {
void work();
void eat();
void sleep();
void code();
void attendMeeting();
}
class Robot implements Worker {
void work() { }
void eat() { } // Robot does not need to eat
void sleep() { } // Robot does not need to sleep
void code() { }
void attendMeeting() { }
}Correct approach: Split the interface into focused ones.
interface Workable { void work(); void code(); }
interface Manageable { void attendMeeting(); }
interface Sustainable { void eat(); void sleep(); }
class Robot implements Workable { void work() { } void code() { } }3.5 Dependency Inversion Principle (DIP)
Definition: High‑level modules should not depend on low‑level modules; both should depend on abstractions.
Bad example: OrderService directly uses a concrete MySQLDatabase.
class OrderService {
private MySQLDatabase db; // direct concrete dependency
void saveOrder(Order order) { db.save(order); }
}Correct example: Depend on a Database interface.
interface Database { void save(Object obj); }
class MySQLDatabase implements Database { void save(Object obj) { } }
class MongoDatabase implements Database { void save(Object obj) { } }
class OrderService {
private Database database; // depends on abstraction
void saveOrder(Order order) { database.save(order); }
}4. Component Principles
4.1 Component Cohesion Principles
REP (Reuse/Release Equivalence Principle): Component granularity equals reuse and release granularity.
CCP (Common Closure Principle): Classes that change together should be packaged together.
CRP (Common Reuse Principle): Do not force users to depend on unnecessary things.
4.2 Component Coupling Principles
ADP (Acyclic Dependencies Principle): Components must not have cyclic dependencies.
SDP (Stable Dependencies Principle): Dependencies should point toward stable components.
SAP (Stable Abstractions Principle): Stable components should be abstract.
5. Boundary Definition
5.1 What Is a Boundary
A boundary separates software elements.
┌────────────┐ ┌────────────┐
│ Business │ │ Database │
│ Rules │←→│ │
└────────────┘ └────────────┘
↑
Boundary line5.2 Boundary Types
Source‑code level: module/package boundaries (e.g., Java package).
Deployment level: component boundaries (e.g., JAR/DLL).
Process level: service boundaries (e.g., micro‑service).
Physical level: system boundaries (stand‑alone system).
5.3 Boundary Strategy
“Draw early, bind late”. Define boundaries early, defer concrete implementation decisions. Avoid premature micro‑service or technology choices; first define clear boundaries, then decide the implementation.
6. Clean Architecture Onion Model
6.1 Model Diagram
┌─────────────────────┐
│ Presentation │
│ Controllers │
│ Presenter │
└──────────┬──────────┘
│
┌──────────▼──────────┐
│ Use‑case │
│ Use Cases │
│ Interactors │
└──────────┬──────────┘
│
┌──────────▼──────────┐
│ Domain │
│ Entities │
│ Domain Objects │
└──────────┬──────────┘
│
┌──────────▼──────────┐
│ Infrastructure │
│ Interfaces │
│ External Systems │
└─────────────────────┘6.2 Core Points
The domain layer is at the core and does not depend on anything.
The use‑case layer orchestrates domain objects to implement scenarios.
The presentation layer handles external input and output.
The infrastructure layer implements interfaces and connects to external systems.
7. Database Is Just a Tool
7.1 Wrong View
Database = Architecture7.2 Correct View
Database is just one kind of infrastructure.
Architecture should be driven by the business domain.
Database serves the architecture, not the other way round.7.3 Implementation Example
// Domain model (core)
class User { private String name; private String email; }
// Repository interface defined in the domain layer
interface UserRepository {
void save(User user);
User findById(String id);
}
// JPA implementation in the infrastructure layer
class JPAUserRepository implements UserRepository {
@Override
public void save(User user) { /* JPA code */ }
@Override
public User findById(String id) { /* JPA code */ return null; }
}8. Web Is Not the Center
8.1 Wrong Architecture
Web → Business Logic → Database
Is Web the center? No!8.2 Correct Architecture
┌──────────┐
│ Web │ ← one kind of presentation layer
├──────────┤
│ CLI │ ← also possible presentation layer
├──────────┤
│ API │ ← also possible presentation layer
└──────────┘
↓
┌──────────────────┐
│ Use‑case layer │
└──────────────────┘
↓
┌──────────────────┐
│ Domain layer │
└──────────────────┘8.3 Key Points
Presentation layer is only a way of input/output.
Core business logic should not know about the presentation layer.
The same domain model can be attached to different presentation layers.
9. Summary of Clean Architecture
Separate concerns by layering responsibilities.
Dependencies point inward, toward abstractions.
Clear boundaries are defined.
Domain layer is the most stable.
Business logic is testable because it does not depend on external details.
Clean Architecture is not a silver bullet, but it is a proven method for building maintainable, testable, and extensible software.
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.
IT Learning Made Simple
Learn IT: using simple language and everyday examples to study.
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.
