Clean Architecture 實作篇 (五)
首先回到熟悉的六角架構圖,對於最外層 Web 可以認知是一個透過瀏覽器互動的 使用者介面,而接著進入的是與外部溝通的 Adapter 轉接器 (Controller),透過 轉接埠 (Port) 來與 應用程式層(Service) 的 使用案例 互動
而之所以 轉接器 與 使用案例 之間,需要增加一層介面的原因是 明確的建立起 外部 與應用程式核心 互動時的規格。 意思是說對於使用案例來說,不論轉接器是由 Web端 或是 Message Bus端 都能呼叫,抑或是當我們的使用案例有時候需要回傳外部 或是儲存需求時,因為不能直接呼叫外部的低層級細節,所以這時候就需要一個介面提供 反向依賴。
這樣可以降低耦合度,可以更容易地替換不同的轉接器,提高可測試性,簡化維護。
一個網頁層轉接器的職責
將 HTTP 轉成對應的 Request Object -> 驗證授權 (OAuth, Middleware) -> 輸入檢查 -> 轉換成對應的使用案例輸入模型 -> 呼叫使用案例 -> 將使用案例輸出對應為 Response Object -> 透過 HTTP 回傳
對於MVC架構來說,我們通常把這些職責交給了 Controller,那我們是否該依據每個使用案例不同,而將 Controller 也拆成單一控制器呢?
讓我們先了解如果都不拆,都聚焦在同一隻 Controller 上會帶來哪些影響
- 維護性差 (因為很難找到正確的使用案例)
- 可測試度差 (因為需要建構子注入每一個 輸入轉接埠,很難針對單個使用案例進行測試)
- 變相地促使重複利用資料結構 (因為新增和修改可能都需要 同個輸入模型,只不過新增的不需要id,導致輸入模型不在乾淨 可能有欄位因此變成了 nullable,那我該如何驗證資料模型正不正確? 當我為了某個使用案例去調整輸入模型時,是不是也會影響到其他使用案例)
而好處就是部署成本較低,當異動時,可以只單純抽換該檔案。
而對於拆分的方式,可以把 各項作業從 套件結構 和 控制器類別 上切開,並盡量使用 與 使用案例相關的名稱來命名那些方法和類別。
意思就是說 依據使用案例去規劃套件結構
user/
├── register/
│ └── RegisterUserController.php
└── update/
└── UpdateUserController.php
雖然這樣做會建立很多不共用模組,產生許多小型規模類別,但這樣做能使 更好的尋找使用案例、測試、平行開發