工作上事情總是多到做不完,要怎麼把有限的時間花在最關鍵的部分,是每位工程師都得面對的課題。對於後端工程師而言,Clean Architecture(簡潔架構)就是一套幫助我們把「事情擺在對的位置」的設計方針。
Kuma 自承不是擅長架構設計的人,但實際導入 Clean Architecture 之後感受非常明顯:分層整理乾淨後,測試好寫、重構也有依據,這份系列文章想推廣的就是這份體會。
簡介#
Clean Architecture 由 Robert C. Martin(鮑伯大叔)於 2017 年的同名書中提出。在這之前已有 Hexagonal Architecture、Onion Architecture 等多種知名架構,鮑伯大叔觀察到這些架構雖然形式不同,卻共享一些重要的特質:
- 與框架解耦:框架是工具,必須隔離於核心邏輯之外,才不會被工具反過來限制設計。
- 可測試性:核心邏輯應獨立於 UI、資料庫、網路等細節之外,使這些細節可以隨意抽換以利測試。
- 與資料庫無關:把 Oracle 換成 MySQL、MongoDB 或任何儲存方案,業務邏輯都不該感受到變化。
分層#
Clean Architecture 把系統劃分為四層,但不是上下堆疊,而是由外而內排列;越接近 I/O 越外圍,越靠近核心邏輯越裡面。
Entity#
最內層,負責問題領域中最重要的資料與運算。不論有沒有電腦輔助,這些事情都是必須完成的。
Use Case#
包覆於 Entity 之外,定義在何時該如何使用 Entity 的資料與行為。可以視為「自動化流程」的負責人。
Interface Adapter#
系統的邊界。負責把外部請求翻譯成內層認得的格式,找出合適的 Use Case 執行,再把結果轉換回外部理解的型態。Controller、Repository 多半住在這一層。命名為 Adapter,正因其工作多半是「轉換」。
Frameworks & Drivers#
最外層,包含網路、資料庫、檔案、UI 等所有 I/O 細節。
判斷核心或細節的捷徑是:「離 I/O 越近的越細節,離 I/O 越遠的越核心。」
鮑伯大叔強調 Entity 與 Use Case 是支撐生意的主要推手,必須慎重對待;I/O 雖重要,但屬於可以輕易被抽換的細節。
留個思考題給讀者:Data driven 與 UI driven 的開發方式,搭配 Clean Architecture 又會碰撞出什麼火花?
三大原則#
整體 Clean Architecture 可以濃縮為三條核心原則:
- 分層原則:所有元件都要分門別類安置,不能亂放。
- 依賴原則:依賴方向應盡量「由外而內」,內層不應依賴外層。
- 跨層原則:每一層只能認識同一層或內側相鄰一層的元件,不能跨層直接認識「兩層以外」的元件。
依賴原則的挑戰#
依賴原則禁止由內向外依賴,那當 Use Case 需要操作 Entity,但 Entity 的資料卻儲存在外層的 DB 時該怎麼辦?這時候就要請出依賴反轉原則(Dependency Inversion Principle, DIP)。
DIP 主張業務邏輯不應該依賴具體實作,而應讓兩方共同依賴抽象介面。具體做法是:Use Case 自己定義一個 Repository 抽象介面,介面的實作則放在外層的 Interface Adapter;如此既符合 Clean Architecture 的依賴原則,也滿足實際業務需求。
跨層原則的重要性#
跨層原則執行起來其實有點麻煩。例如 Adapter 層只能認識 Use Case 層,對最內層的 Entity 應該一無所知。即使你想回給前端的物件格式跟 Entity 幾乎一樣,也不能直接回傳,要嘛在 Use Case 轉一次格式,要嘛採用 CQRS(Command Query Responsibility Segregation)模式跳過 Use Case,由同層的 Repository 直接回傳客製化物件。
為什麼這樣麻煩?因為要遵守單一職責原則(SRP)。Entity 應該只關心領域模型最重要的運算與資料,不能被外層需求干擾。如果讓 Adapter 直接存取 Entity,那麼前端格式一動,最核心的 Entity 也跟著動,這正是反模式的典型樣貌。
Kuma 的使用心得#
導入 Clean Architecture 後,元件的擺放有了清楚依據,核心運算邏輯不再依附於資料庫或 UI 細節,整個系統的整潔度與彈性都明顯提升。更重要的是排定工作順序時知道什麼該先做、什麼可以延後決定,做事節奏更穩。
原文出處#
- 原書/iThome:https://ithelp.ithome.com.tw/articles/10268953