再讀整潔架構(Clean Architecture)

Rex Wang
7 min readJul 27, 2020

最近因為某些因素,我重讀了Uncle Bob 的 Clean Architecture,找尋解決問題的靈感。大師的書裡總是有微言大義,也許是我的理解力太差,哈。

何謂架構?為什麼需要架構設計?

我對於軟體架構設計的興趣,來自於歷經幾個慘烈的專案後,我開始思考有沒有什麼方式可以讓專案進行得順利一些?系統維護與變更也可以更容易一些?因為長年開發工作的關係,很多機會跟客戶、同事討論到系統設計,總是著重在”如何在時程與預算內完成需求”;敏捷是我其他戰友走的一條路,架構設計則是我覺得可行的另一條路,也成為我這幾年來尋尋覓覓的方向。敏捷當然也要有架構設計,但不是每個人都這樣想,不過,那又是另外一個故事了。

Uncle Bob 在書中定義了軟體架構的目標:軟體架構的目標是最小化建置和維護「需求系統」所需要的人力資源。

以我個人世俗的說法就是,如何以最快的速度、最少的人力與經費負擔完成專案(全新或是需求變更都算),大家可以平安回家,就是軟體架構的目標XD。但通常,我們在有限的時間、資源與人力情況下,僅僅只能想到如何按照規劃準時上線,甚至品質與預算都沒辦法被詳細評估,甚至犧牲,更不可能想到,未來如何發展這個滾燙的山芋。

Uncle Bob提到軟體架構,除了需要考慮設計與開發過程的相關議題,部署、維運,甚至後續的需求變更,都應該被納入思考與規劃。讓我想起,曾經負責的十年系統,每次需求變更的上線工作,都是驚濤駭浪的過程;也想到,如果微服務的部署工作,沒有經過妥善規劃與方便的工具,勢必會是一場災難,這也是另外一個大議題,改天再聊。

Clean Architecture 的目標

Alistair Cockburn開發的六角形架構(或是被稱為 Port 與Adapters),在 Chris Richardson 的 Microservices Patterns 與 Vaughn Vernon 的 Implementing Domain-Driven Design 都有說明,兩位大師都推薦以這樣的架構來安排系統或是微服務;同樣的架構也出現在 Netflix 的 TechBlog。而Clean Architecture 與六角形架構僅有些 少許實作細節上的差異,其目標都是一樣的。

圖片來源:Netflix TechBlog

書中提到這樣的架構,有獨立於框架、可測試、獨立於UI、獨立於資料庫等特徵。Uncle Bob建議系統有四層,內圈為策略,外圈為機制;內圈為核心,外圈為細節;內圈為高層,外圈為低層。開發方向可以由內而外,相依方向則應該是由外而內,也就是系統核心不需要知道在外圈的資料庫、框架與UI,讓軟體可以真正變得更軟,更易於改變。因此轉換層是Clean Architecure的關鍵,也是一般讀者最想理解的實作內容。

大家常見的專案開發方式,通常習慣先確定好報表產出、前端技術,接著開始思考資料庫設計,才開始著手進行開發,不知不覺或是根本就是刻意的把系統核心與週邊綁定。在 Clean Architecture的建議方式:相依的方向是由外而內、由IO而核心;開發與設計則可以用事件風暴(Event Storming) 、使用者故事對照(User Story Mapping)或是OOAD等方式找出 Use Cases 與 Entities。外層的框架、展示層與資料庫則可稍後決定。兩種方式最大的差異,會是在未來系統演進時,Clean Architecture 會獲的極大的彈性與好處,更可保持核心的獨立性,不受到外層增加或變更的影響。

SOLID 設計原則

SOLID設計原則包含:單一職責原則(Single responsibility principle, SRP)、開放封閉原則(Open-Close principle, OCP)、里氏替換原則(Liskov substitution principle, LSP)、接口隔離原則(Interface segregation principle, ISP)、反向相依原則(Dependency inversion principle, DIP)等五個。這個物件導向設計原則並非由Uncle Bob 獨創,但在Clean Code 系列書籍裡,提到 SOLID 設計原則不止一次,且在Clean Architecture裡面扮演著非常重要的角色。

其中,反向相依原則即是讓內外圈解偶的關鍵技巧。過去我們習慣將Entity 與 Repository 放在同一層(或是同一個 package),在 Clean Architecture 則做了一個調整,也運用到GoF提到的”針對介面寫程式”,上層提供了一個 Repository的Interface,再由低層實作真正對應的資料庫存取類別。在資料庫尚未決定前,即可使用程式語言基礎的資料結構,代替資料庫,進行核心功能開發與測試,一旦決定資料庫種類與廠牌,即可進行調整,並不會影響完成的核心功能。也以此達成反向相依。

反向相依

單一責任原則簡單來說就是,一個類別的改變只能有一個理由,換句話說:如果類別A同時被另外兩個類別使用,另外兩個類別的改變,極有可能互相影響,以實務上來說,就是要不斷的測試以避免發生問題;但如果以單一責任原則更是一種釜底抽薪的設計方式。

單一責任原則

但是如果有一些服務就是需要放在同一個類別,該如何處理呢?這時候就需要用到Facade Pattern了。(Design Pattern 部分,我們也留待以後XD)建構微服務的作者 Sam Newman 提出的 Backend for Frontend 的設計模式,則是充分了運用這個概念。

框架的要與不要

身為Spring Framework的熱愛者與Spring 團隊之友,我還是必須認同Uncle Bob的觀點:框架不是架構。雖然在台上表演用Spring Boot ,似乎可以很快開發出微服務,但表演只是強化印象,系統設計還是需要一些深思熟慮。框架不應該深入整個應用的核心,但是如果沒有框架,許多功能要靠自己完成,還要達到一定的品質要求,將會是一個不可能的任務。

很多以Spring Boot建構微服務的Demo 都是從 https://start.spring.io開始,要建立起一個Restful的API就在彈指之間,但如果是我的專案,我不會以這樣的方式開始我的設計。而會確立Entities與Use Cases兩層,也就是實際上系統行為開始,逐步的往外開發;核心與對外的API,則以Adapter Pattern的方式對接,以後如果有更好的通訊方式、應用框架,則保有足夠的彈性進行修改。

結論

我個人非常喜歡且推崇的泰迪曾說過:很多軟體工程或是說敏捷方法和敏捷實務做法都是意圖讓軟體變軟,例如OO、OOAD、DDD、TDD/BDD/ATDD/SBE、Clean Architecture、Patterns、CI/CD、UT、Refactoring、SOLID還有XP、Scrum、Lean、Kanban等。變軟是為了更容易改變,偏偏大家總以為自己手上的系統永遠不會改變;如果想像自己是達文西,手上的系統是聖彼得大教堂,那敲敲打打、修修改改,假裝自己是在追尋”建築的永恆之道”,心情應該會好多了。

Sign up to discover human stories that deepen your understanding of the world.

Free

Distraction-free reading. No ads.

Organize your knowledge with lists and highlights.

Tell your story. Find your audience.

Membership

Read member-only stories

Support writers you read most

Earn money for your writing

Listen to audio narrations

Read offline with the Medium app

Rex Wang
Rex Wang

Written by Rex Wang

職業生涯歷經不同身份與角色,應用開發是我無法忘情的工作之一;工作中的經驗與個人的學習,逐漸對於應用開發、專案執行有一些想法與感觸,因此想藉此園地留下紀錄

Responses (1)

Write a response

很多軟體工程或是說敏捷方法和敏捷實務做法都是意圖讓軟體變軟 這句話受益良多

--