乾淨架構核心原則
SOLID 原則
S — 單一職責原則 (Single Responsibility)
每個 class 只有一個改變的理由。
// ❌ 錯誤:一個 class 做太多事
class UserService {
createUser() { ... }
sendEmail() { ... }
logActivity() { ... }
}
// ✅ 正確:各司其職
class UserService {
constructor(
private userRepo: UserRepository,
private emailService: EmailService,
private logger: Logger
) {}
createUser() { ... }
}
class EmailService {
sendWelcome() { ... }
}
O — 開放封閉原則 (Open/Closed)
對擴展開放,對修改封閉。
// ✅ 新增支付方式不需修改現有程式碼
interface PaymentProcessor {
process(amount: number): Promise<Result>;
}
class CreditCardProcessor implements PaymentProcessor { ... }
class LinePayProcessor implements PaymentProcessor { ... }
class ApplePayProcessor implements PaymentProcessor { ... }
L — 里氏替換原則 (Liskov Substitution)
子類別必須能替換父類別。
// ✅ 所有 Repository 都能互換使用
interface UserRepository {
findById(id: string): Promise<User>;
save(user: User): Promise<void>;
}
class PostgresUserRepository implements UserRepository { ... }
class InMemoryUserRepository implements UserRepository { ... } // 測試用
I — 介面隔離原則 (Interface Segregation)
不要強迫客戶端依賴不需要的介面。
// ❌ 錯誤:太大的介面
interface Repository {
findById(): any;
save(): any;
delete(): any;
findByEmail(): any;
generateReport(): any;
}
// ✅ 正確:拆分小介面
interface ReadableRepository<T> {
findById(id: string): Promise<T>;
}
interface WritableRepository<T> {
save(entity: T): Promise<void>;
delete(id: string): Promise<void>;
}
D — 依賴反轉原則 (Dependency Inversion)
高層模組不應依賴低層模組,兩者都應依賴抽象。
// ❌ 錯誤:高層依賴低層
class OrderService {
constructor(private db: PostgresDatabase) {} // 硬性依賴
}
// ✅ 正確:依賴抽象
class OrderService {
constructor(private orderRepo: OrderRepository) {} // 依賴介面
}
依賴規則 (The Dependency Rule)
源碼的依賴關係只能從外向內,不能從內向外。
Presentation → Application → Domain
↑ ↑ ↑
└──────────────┴───────────┘
依賴方向只能向內
實際含義
- Domain 層:不 import 任何東西(除了標準庫)
- Application 層:只能 import Domain
- Infrastructure 層:可以 import Application + Domain
- Presentation 層:可以 import 所有層
其他重要原則
DRY (Don't Repeat Yourself)
重複的程式碼要抽成共用函數或類別。
KISS (Keep It Simple, Stupid)
簡單的方案通常是最好的方案。
YAGNI (You Aren't Gonna Need It)
不要為「可能」的需求寫程式碼。
组合優於繼承
優先使用 composition 而非 inheritance。
// ✅ 組合
class OrderService {
constructor(
private validator: OrderValidator,
private pricing: PricingService
) {}
}
// ❌ 繼承
class OrderService extends BaseService { ... }