軟件架構(gòu)編年史:整潔架構(gòu)
本文轉(zhuǎn)載自微信公眾號「逸言」,作者覃宇。轉(zhuǎn)載本文請聯(lián)系逸言公眾號。
Robert C. Martin(大名鼎鼎的 Uncle Bob)于2012年在他的一篇博客中發(fā)表了整潔架構(gòu)的觀點,并在一些會議上做了關(guān)于該架構(gòu)的演講。
整潔架構(gòu)借助了許多或熟悉或陌生的概念、規(guī)則和模式,說明了如何將它們?nèi)跁炌óa(chǎn)生出一種構(gòu)建應(yīng)用的標(biāo)準(zhǔn)套路。
站在 EBI 架構(gòu)、六邊形架構(gòu)和洋蔥架構(gòu)的肩膀上
整潔架構(gòu)的核心目標(biāo)與端口和適配器(六邊形)架構(gòu)以及洋蔥架構(gòu)是一致的:
- 工具無關(guān)
- 傳達機制無關(guān)
- 獨立的可測試性
下面這張圖發(fā)表在整潔架構(gòu)的博客中,揭示了該架構(gòu)的總體思路:
Robert C. Martin 2012, The Clean Architecture
正如 Uncle Bob 自己在博客中所說,上面這張圖試圖將最新的架構(gòu)觀點整合成一個可操作的思路。
我們來對比一下整潔架構(gòu)和六邊形架構(gòu)以及洋蔥架構(gòu)的示意圖,看看它們在哪些方面是一致的:
外化工具和傳達機制
六邊形架構(gòu)聚焦于使用接口和適配器將工具和傳達機制從應(yīng)用中外化出去。這也是洋蔥架構(gòu)的核心基石之一,就像圖中呈現(xiàn)的那樣,UI、基礎(chǔ)設(shè)置和測試全部都在示意圖的最外層。整潔架構(gòu)也有完全一致的特征,UI、Web、DB 等等都在最外層。最終,所有的應(yīng)用核心代碼都是獨立于框架/庫的。
依賴方向
六邊形架構(gòu)中并沒有明確地告知我們依賴的方向。然而,我們可以輕易地推測出來:應(yīng)用擁有接口,它們必須由適配器實現(xiàn)或使用。所以適配器依賴接口,依賴位于圓心的應(yīng)用。外部依賴內(nèi)部,依賴的方向就指向圓心。在洋蔥架構(gòu)的示意圖中,也沒有發(fā)現(xiàn)關(guān)于依賴方向的表示,但是,Jeffrey Palermo 在他的第二篇博客中清楚地表明了所以依賴都指向圓心。整潔架構(gòu)則非常明確的指出依賴的方向是指向圓心的。它們都在架構(gòu)層級引入了依賴倒置原則。內(nèi)圈不能知道外圈的任何信息。還有,當(dāng)數(shù)據(jù)跨越界限進行傳遞時,數(shù)據(jù)總是以最方便內(nèi)圈使用的格式提供。
分層
六邊形架構(gòu)示意圖只展現(xiàn)了兩個層次:應(yīng)用內(nèi)部和應(yīng)用外部。而洋蔥架構(gòu)引入了 DDD 中定義的應(yīng)用層次的混合:控制用例邏輯的應(yīng)用服務(wù);封裝了領(lǐng)域邏輯的領(lǐng)域服務(wù),這些邏輯既不屬于實體也不屬于值對象;還有實體、值對象等等...和洋蔥架構(gòu)相比,整潔架構(gòu)保留了應(yīng)用服務(wù)層(用例)和實體層,當(dāng)好像漏掉了領(lǐng)域服務(wù)層。然而,讀過 Uncle Bob 的博客后,我們會發(fā)現(xiàn),他認為任何領(lǐng)域?qū)ο蠖际菍嶓w,而非只有 DDD 中的“實體”才是實體:“一個實體可以是一個擁有方法的對象,或者是一組數(shù)據(jù)結(jié)構(gòu)和函數(shù)”。實際上,他為了簡化示意圖而將最中間的兩層合并了。
獨立的可測試性
三種架構(gòu)風(fēng)格共同遵守的規(guī)則,讓它們將應(yīng)用和業(yè)務(wù)邏輯隔離了出來。這意味著任何情況下我們都可以簡單地 mock 外部工具和傳達機制,獨立地對應(yīng)用的代碼進行測試,而不需要使用數(shù)據(jù)庫或 HTTP 請求。
正如我們所見,整潔架構(gòu)包含了六邊形架構(gòu)和洋蔥架構(gòu)的規(guī)則。截至目前,整潔架構(gòu)好像沒有加入什么新鮮的概念。但是,在整潔架構(gòu)示意圖的右下角,還有一張小圖...
站在 MVC 和 EBI 的肩膀上
整潔架構(gòu)示意圖的右下角的這張小圖說明了控制流是如何工作的。這張小圖并沒還有提供太多信息,但博客中的說明和 Robert C. Martin 的會議演講拓展了該話題。
我們在上圖的左側(cè)看到的是 MVC 中的視圖和控制器。雙實線另一層的所有形狀都是 MVC 中的模型。這些模型也代表著 EBI 架構(gòu)(我們可以清楚的看到邊界、交互器和實體),六邊形架構(gòu)中的“應(yīng)用”、洋蔥架構(gòu)中的“應(yīng)用核心”,以及前面整潔架構(gòu)示意圖中的“實體”層和“用例”層。
假設(shè)有一個 HTTP 請求按照控制流到達了控制器??刂破鹘酉聛頃?/p>
- 拆解請求;
- 使用相關(guān)數(shù)據(jù)創(chuàng)建一個請求模型;
- 執(zhí)行交互器(作為交互器接口的,即邊界的,實例被注入到控制器中)中的方法并將請求模型傳遞給它;
- 交互器會:
- 使用實體網(wǎng)關(guān)實現(xiàn)(作為實體網(wǎng)關(guān)接口的實例被注入到交互器中)查找相關(guān)實體;
- 編排實體之間的交互;
- 用操作的數(shù)據(jù)結(jié)果創(chuàng)建響應(yīng)模型;
- 將響應(yīng)模型交給展示器進行填充;
- 將展示器返回給控制器;
- 使用展示器生成視圖模型;
- 將視圖模型綁定到視圖;
- 將視圖返回給客戶端。
這里只有“展示器”的用法我有些疑問,我在項目中的實際做法和這里不太一樣。我會將某種 DTO 類型的數(shù)據(jù)返回給交互器,而不是注入一個填充了數(shù)據(jù)的展示器對象。
我通常會采用實際上是一種 MVP 實現(xiàn),控制器在其中負責(zé)從客戶端接收數(shù)據(jù)并響應(yīng)它。
總結(jié)
我不認為整潔架構(gòu)是革命性的,因為它實際上并沒有帶來突破性的概念或模式。
但是,我認為它是相當(dāng)重要的成果:
- 它發(fā)掘了某種程度上被遺忘了的概念、規(guī)則和模式;
- 它澄清了一些實用且重要的概念、規(guī)則和模式;
- 它告訴我們?nèi)绾伟阉械母拍?、?guī)則和模式整合起來,形成一種構(gòu)建復(fù)雜應(yīng)用并保持可維護性的標(biāo)準(zhǔn)套路
Uncle Bob 關(guān)于整潔架構(gòu)的工作總會讓我想起牛頓。引力始終是存在的,每個人都知道松手讓蘋果遠離地面的高處落下,它會落向地面。牛頓做的事情“只不過”是寫了一篇論文披露這個事實。這件事請很“簡單”,但卻讓人們開始思考它并基于它創(chuàng)造更新的想法。
換句話說,我認為 Robert C. Martin 就是軟件開發(fā)領(lǐng)域的牛頓[*注] !
引用來源
2012 – Robert C. Martin – Clean Architecture (NDC 2012)
2012 – Robert C. Martin – The Clean Architecture
2012 – Benjamin Eberlei – OOP Business Applications: Entity, Boundary, Interactor
2017 – Lieven Doclo – A couple of thoughts on Clean Architecture
2017 – Grzegorz Ziemoński – Clean Architecture Is Screaming
覃宇,Android開發(fā)者/ThoughtWorks技術(shù)教練//譯者,熱衷于探究軟件開發(fā)的方方面面,從端到云,從工具到實踐。喜歡通過翻譯來學(xué)習(xí)和分享知識,譯作有《Kotlin實戰(zhàn)》、《領(lǐng)域驅(qū)動設(shè)計精粹》、《Serverless架構(gòu):無服務(wù)器應(yīng)用與AWS Lambda》和《云原生安全與DevOps保障》。

























