任務分派需要一個明確的判斷基準:哪些任務屬於同一層、哪些必須依序完成、哪些可以並行。

Clean Architecture 除了是架構模式,同時是一套責任分層的語彙——它讓人與 AI 代理人用同一組詞討論誰負責哪個部分、什麼時候可以動手。

核心原則:依賴只能由外向內

Clean Architecture 最核心的一句話是「依賴只能由外向內」。內層不知道外層的存在,外層依賴內層定義的介面。業務邏輯因此得以獨立,換資料庫、換 UI 框架都不需要動到核心規則。

架構由內到外分為四層:

Entities(核心業務規則) 封裝核心業務概念,例如書籍、訂單、使用者。定義實體屬性和業務不變量的驗證,不依賴任何框架或資料庫。

Use Cases(應用業務邏輯) 協調 Entities 之間的互動,定義系統功能。同時定義 Input Port、Output Port、Repository Port,只依賴 Entities 和這些自己定義的介面。

Interface Adapters(介面轉接層) 橋接業務邏輯和外部技術。Controller 接收外部請求並轉換為 Use Case 輸入,Presenter 格式化 Use Case 輸出,Repository 實作在這一層開始成形。

Frameworks & Drivers(框架與外部系統) 包含所有技術細節——資料庫、UI 框架、第三方服務。可以隨時替換,完全不影響內層。

依賴反轉原則(DIP)讓這一切成立

Use Case 需要存取資料,但不能直接依賴 SQLite。正確做法是:在 Use Cases 層定義 Repository Port(抽象介面),Use Case 只依賴這個介面。真正的資料庫實作在最外層,它去實作這個介面。

依賴方向因此被反轉:資料庫實作依賴 Use Case 定義的介面,而非 Use Case 依賴資料庫。最後在 Composition Root 把具體實作注入進去,這就是依賴注入的本質。

設計從內到外,實作從外到內

兩個階段的順序相反,這是分層架構在執行面最容易被漏掉的一點。

設計階段由內到外

  1. 設計 Entities:識別業務實體、定義 Value Objects(ISBN、Title 這類有驗證規則的值物件),在建構子中驗證業務不變量。
  2. 設計 Use Cases:定義 Input Port、Output Port、Repository Port。確定業務邏輯需要什麼,但不決定如何實作。
  3. 設計 Interface Adapters:Controller 如何轉換外部請求、Presenter 如何格式化輸出。
  4. 設計 Frameworks:選擇資料庫方案,實作 Repository。到這步才碰具體技術。

實作階段由外到內

  1. 先定義所有 Ports。在寫任何實作之前,確立 Use Case 介面和 Repository 介面,這是系統的骨架。
  2. 外層用 Mock 介面開發和測試。Controller 在 Use Case 還沒真正實作前就能測試,因為它依賴的是抽象介面。
  3. 補完內層實作:Interactor 實作業務邏輯,Repository 存取真正的資料庫。
  4. Composition Root 組裝依賴注入,系統就能真正執行。

設計階段確保業務邏輯不被技術細節污染,實作階段讓每一層都能獨立開發和測試。

驗證架構是否正確

每個 Phase 完成後對照四個方向確認。

依賴方向

  • Entities 沒有任何外層的 import
  • Use Cases 只 import Entities 和自己定義的介面
  • Frameworks 層實作的是 Interface Adapters 定義的介面

介面契約

  • Repository Port 定義在 Use Cases 層(不是 Frameworks 層)
  • Repository 回傳的是 Entity 而不是資料庫 DTO
  • Input/Output Port 沒有洩漏框架的型別(例如 HTTP Request、SQLite Row)

業務邏輯位置

  • 業務不變量的驗證在 Entity 建構子
  • 應用層邏輯在 Use Case Interactor
  • Controller 只負責轉換和呼叫,不包含業務判斷

Interface-Driven Development

  • 所有 Ports 在設計階段就定義完成
  • 外層真的用 Mock 介面在開發測試
  • 組裝注入在 Composition Root 統一處理

為什麼這對 AI 協作特別有價值

架構邊界的維護若依賴經驗判斷,它在時間壓力下的執行率會下降。AI 代理人執行的是明確規則:規則寫得夠清楚,遵守的一致性就跟壓力無關。

分層邊界就是這樣的規則。告訴代理人「這個 class 屬於 Use Cases 層,所以不能 import 任何 Framework 層的東西」,代理人就能機械性地驗證和維護這個邊界。

這套語言也讓任務拆分有了清楚的依據。「這個功能需要修改 Entity 和 Use Case,但不涉及 Repository 實作」是一個清楚的任務描述,對應到具體的修改範圍,不會模糊。

引入分層之後,實作結果的可預測性來自邊界明確:每個任務的修改範圍事先就限定在一層。代價落在設計階段——Ports 要在寫任何實作之前定義完成。

Ticket 怎麼按層拆、按什麼順序執行,走 層級隔離;分層規則怎麼在 commit 階段自動驗證,走 架構合規交給機制