蒼時弦也
蒼時弦也
資深軟體工程師
發表於

讀 Clean Architecture 學習依賴管理

教召一直是讀書的好時機,因此我利用五天的時間把 Clean Architecture 讀完。讓我覺得意外的是,以往我聽到在討論一些主題時會提到這本書的內容,其實大多跟這本書想傳達的資訊不太一致,除此之外我認為有很多值得討論的地方也沒有被大家討論。

元件與依賴

書中 Uncle Bob 提倡以「元件」的方式來思考我們如何能單獨更新一部分的系統而不影響到其他元件,而這就跟「依賴管理」的技巧有所關聯。

在附錄的部分 Uncle Bob 分享他的經歷,其中有一段故事是他設計了一套運行在單晶片的軟體(韌體)在一系列的改進後,能夠透過遠端(撥號)修正錯誤,或者替換這組硬體中的其中一個晶片來修正問題,因此「元件」的概念逐漸成形。

「依賴」這個概念幾乎是貫穿整本書的,在書中我們不斷的用各種角度去思考依賴的問題。舉例來說,一個畫面的修改會影響到行為嗎?假設我們沒有仔細思考架構的規劃,那麼「行為」需要知道「畫面」的資訊,並且將結果輸出給畫面物件。

然而我們可以透過「定義介面」將這個資訊抽象化進而將依賴反轉成「畫面物件具備輸出行為」的狀態,那麼行為物件只需要知道有個物件能夠提供「輸出」的行為,就不需要知道畫面物件的存在,同時也能夠利用這個方式實作不同類型的輸出介面,來提供不同的使用者互動方式。

在 Ruby 這類語言就相對彈性的多,因為型別的推斷是在執行期間(Runtime)去判斷的,除了比較容易抽換之外,還有著不一定要定義介面的特性,像是 Ruby 的 Duck Typing 機制只需要具備特定的方法即可(然而這還是約定了介面)

邊界

要劃分出依賴的關係,就需要思考「邊界」的概念,也就是兩個物件是否該互相耦合,或者他們是屬於不同的概念,因此雙方不應該知道對方。

在 Clean Archiecture 中你會找到很多在學習 Domain-Drive Design 不太清晰的概念的解釋,以 Layered Archiecture 作為例子,我在網路上不少文章會看到說他是不好的因此要用 Clean Archiecture 來替代。

然而,在書中實際上提到的是以 Layered Archiecture 來劃分時,我們會將不同領域的物件放在一起,像是 Domain Layer 裡面有著多個不同領域的物件一起被部署,然而以「元件」的角度來看,假設是一個會員模組,那麼包含他的介面、商業邏輯等一起被部署是更加合理的。

也就是說,我們在規劃的時候會思考水平(Layer)、垂直(Domain)兩種不同類型的依賴界線,如何適當的進行元件的分組就會是架構師需要去思考的問題之一。

舉例來說,假設是一個處於 Infrastructure Layer 的物件用於存取資料,這個物件在部署的元件來看可能是單一的一個單位,因此不一定是完全的水平或者垂直劃分,而「邊界」就是這些劃分的界線。

未知

大多數時候在設計系統的時候是不太可能馬上了解所有資訊,因此會有許多未知的地方存在,而我們需要盡可能的將「可以延後」的決定盡可能的延後來減少對系統的影響。

舉例來說,操作介面是經常被修改的然而幾乎不會有其他物件去依賴操作介面,因此我們去修改的成本是相對低的,那麼我們先實作這類型的物件影響就不會太過於巨大。然而像是核心的商業邏輯只要有微小的改動,就可能引響後續的流程、操作、呈現方式,在實作的過程中我們就需要盡可能的推遲這些決定,多利用操作介面、流程的資訊了解更多這些核心資訊,再來做出決定。

這類型的物件通常會有非常高的依賴,以字串(String)物件為例子幾乎是所有人都會使用,那麼他就不會經常地被改動,而我們的核心商業邏輯也應該是如此的,即使流程、操作、呈現不斷改變,這些商業邏輯「本質上」是不會有太多變化,一但有所改變就會有巨大的影響。

我用「本質」去形容是因為他有點類似事物的「基礎」可能是類似於地基、原子這類的概念,一但要改動勢必會影響建構在這之上的一切事物,因此 Clean Archiecture 用 Entity(實體)來描述並且將其保護在最核心的地方。

然而,從 Domain-Driven Design 的角度來看這些事物就是 Domain Model 的存在,但並沒有著墨太多,也因此從 Layered Archiecture 的方式去看是無法清晰看出「依賴」的影響,只能從 Bounded Context 的分析稍微觀察到,我猜這也是為什麼一但邊界確立後難以調整的原因之一。

雖然 Clean Archiecture 並未偏好任何一種測試方式,然而我認為 ATDD(Acceptance test-driven development,驗收測試驅動開發)的探索式實作,是非常接近這種「推遲決定」的技巧,也因此我們先決定結果,在陸續的深入到 Domain Model 中,即使是「資料如何取得」也能在最後才決定,這也讓我們在過程中改變架構時保有更大的彈性。

架構師

這幾年似乎比較少人討論「架構師」這個職位,然而從書中的描述我們可以更清晰的了解到這個職位扮演著一個怎樣的角色。

過去我對架構師的認知停留在像是「了解很多技術」「知道很多工具」「對商業很了解」「非常資深的工程師」等等的條件中,然而根據書中所描述的「架構」來思考,其實架構師更多的是「管理依賴」與「保護彈性」這兩件事情。

軟體的定義是「容易修改的產品(ware)」也就是說一但我們失去的改變的彈性,那麼就會變為韌體(Firmware)甚至是硬體(Hardware)的狀態,韌體因為是跟硬體綁定的因此改變會受限,至於硬體本身被製造出來後就失去變化的能力,我們去製作軟體就是為了能夠最大限度的獲得改變的彈性。

為了要具備極大的彈性,我們就需要去「管理依賴」也就是避免我們撰寫出來的程式與其他元件高度的耦合,最後變成一團大泥球(Big ball of mud)的狀態,那們我們不論修改哪裡都都會互相影響,那麼就會極度不穩定而且難以改變。

也因此,架構師之所以了解「商業」是為了區分出整個商業邏輯的本質適當的規劃、對工具、技術的熟悉是為了在需要做決定的時候能夠給出恰當的決定,並且在需要改變的時候能有不同的方案去對應,而這些技能都仰賴一個工程師的實力是否足夠,以及是否持續的撰寫程式。

透過這本書我更加了解「架構」的本質,也讓以往在技術上的實踐有了比較「清晰」的認知,我想之後會有非常多可以練習的地方在等待我。

有跟我一起工作過的朋友大多知道我非常追求可讀、設計良好的程式,然而我一直不清楚自己的職涯會怎樣發展,只覺得朝向 IC(Individual Contributor,獨立貢獻者)是個不錯的方向。不過透過 Clean Architecture 對架構師的了解,也許我在職涯上的追求更接近架構師所做的事情。