8

【還少一本書】Get Your Hands Dirty on Clean Architecture

 2 years ago
source link: http://teddy-chen-tw.blogspot.com/2021/09/get-your-hands-dirty-on-clean.html?showComment=1631118110594
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

【還少一本書】Get Your Hands Dirty on Clean Architecture

September 08 20:30~23:34

AM-JKLXOqJbR2PYe8rs4AP2tZ8Id3PD-a387DCNCupY0By4BrFWz43NRzl0AgtHusWZpsiws3TSg5sDHX8LFN5nhglTqYY_pvF6X8H2khyWqhEpis3h_DdQmWWj_skLZl0t1n2tPZz0y5OozKRBZ5LYlmSlJkA=w1776-h1850-no?authuser=0

前言

目前市面上Clean Architecture的書,跟日本進口壓縮機一樣,非常稀少。Teddy在2017年介紹過〈[還少一本書] Clean Architecture〉,事隔多年後,今天要介紹剛讀完的另外一本《Get Your Hands Dirty on Clean Architecture》。

這本書只有薄薄的137頁,書中探討實作Clean Architecture遇到的程式實作問題。Uncle Bob寫的《Clean Architecture: A Craftsman's Guide to Software Structure and Design》雖然多達400頁,但書中的敘述比較抽象,實作的程式碼趨近於0。導致許多人讀完《Clean Architecture》之後,在程式實作的時候形成「一個架構,各自表述」的窘境。而「在乾淨的架構上弄髒你的手」這本書,試圖彌補Uncle Bob留下的實作缺口。

接下來Teddy逐一介紹這本書的優點以及可改善之處。

優點--單一責任的使用案例類別

這本書的前兩章談傳統階層架構所造成的問題,以及如何透過依賴反轉來解決這些問題。作者在前兩章還沒提到程式實作,而這兩章的大部分內容在Uncle Bob的書中已經說得很清楚。Teddy覺得比較值得注意的一點是,書中第15頁提到:

The use cases are what we have called services earlier but are more fine-grained to have a single responsibility, thus avoiding the problem of broad services that we discussed earlier. (使用案例就是我們之前所說的服務,但更細粒度地具有單一職責,從而避免了我們之前討論的廣泛服務的問題。)

Clean Architecture的使用案例,有兩種常見的實作方式。第一種就是上述所說的broad service,一個service物件身上包含好多方法,每一個方法代表一個使用案例。DDD紅皮書《Implementing Domain-Driven Design》的書中範例就是典型的broad service寫法。

另一種方式就是將使用案例提升為類別,一個使用案例類別只會做一件事,也就是上述符合單一責任原則的fine-grained service。

Teddy自己是採用一個類別代表一個使用案例(fine-grained service)的做法。

優點--程式結構

在Uncle Bob書中由Simon Brown所寫的第34章The Missing Chapter,談四種程式碼結構的方式:package by layer、package by feature、ports and adapters、package by component。雖然這個章節畫了好幾張圖來解釋這四種方法,但Teddy覺得書中的描述還是少了一些重要的細節,導致在實作上有太多的可能性。

這個問題其實很容易釐清,講那麼多還不如給一張圖畫出程式目錄結構就搞定了。

……為什麼不給code哩?

而本書第3章則是以實際的程式結構範例重點說明package by layer與package by feature的優缺點,最後給出作者的建議方式:先package by feature再package by layer。

雖然作者沒有針對Uncle Bob原本書中的四種目錄結構方式詳細比較,但至少給了一個還算是非常具體的實作建議。

優點--具體的使用案例實作程式範例

本書第4章談使用案例的實作,以實際的程式碼對應到Uncle Bob書中所說的use case input、use case與use case output。本書把use case input稱為input model,並將其包裝成Command物件(可參考書中第37頁SendMoneyCommand程式碼)。

將input包裝成Command是很常見的作法,但這一點與Teddy的慣用做法不同,Teddy使用UseCaseInput類別來實作input。

Teddy在實作Clean Architecture的時候同時套用DDD與Event Storming,在Event Storming中藍色便利貼代表Command,也就是使用者對系統下的命令。有人將Event Storming的Command當成use case input,Teddy則是直接將Command用使用案例實作,而執行該Command所需的輸入參數當成use case input。所以Teddy把Command這個概念保留給使用案例,而不是使用案例的輸入參數。

儘管書中的實作方式與Teddy慣用方式有所差異,但概念上還是一致。

本章另外還有四個亮點:

  • 輸入參數驗證與商業邏輯驗證的差異,以及應該在哪個軟體架構階層中去做驗證。
  • 貧血模型(anemic model)和豐富模型(rich model)對於使用案例的實作有何影響?
  • 使用案例的輸出
  • 唯讀的使用案例實作

優點—跨層的物件映射(Mapping)

Teddy讀完Uncle Bob的《Clean Architecture》之後將其重點歸納為三個原則,細節請參考〈再談Clean Architecture三原則〉。其中有一個原則叫做〈跨層原則〉,書中關於此原則的實作著墨甚少,只提到當物件跨層傳遞的時候,會使用Mapper設計模式將物件映射成另一種型別。

實務上,也有不少開發人員反對跨層映射,覺得太麻煩,不但沒效益還產生許多類似的重複程式碼。

本書第8章詳細說明No Mapping、One-Way Mapping、Two-Way Mapping與Full Mapping(《Clean Architecture》書中建議的做法)這四種做法的優缺點。作者建議對於web controller layer採用full mapping,但在persistence layer就不建議使用,因為作者覺得開銷太大,不划算。

但這一點Teddy並不同意作者的看法,在ezKanban中,不管是web controller layer還是persistence layer,都採用Full Mapping。雖然一開始需要花時間寫mapper程式,但在後來Teddy不斷重構entity layer的過程中幫了極大的忙。不管entity layer實作如何修改,persistence layer與web controller layer幾乎完全不受到影響。

優點—Main Component的實作

Clean Architecture》第26章The Main Component也是有點抽象的一章,書中提到Main Component是「最髒」的元件,而且每一種系統配置都需要用一個Main Component來代表,在實作上有不少讀者不知如何具體落實這個Main Component。

Get Your Hands Dirty on Clean Architecture》第9章則是以具體的程式碼說明Main Component的實作,又彌補了一個《Clean Architecture》書中的一個實作缺口。

可以更好

提了這麼多優點,最後談談可以做得更好的地方。

第一點雖然Teddy把它列為缺點,但也可以說是優點。因為這本書很薄,雖然可以很快一窺Clean Architecture的實作面貌,但對於完全沒有學過Clean Architecture的鄉民而言,如果要光靠這本書就「徹底學會」Clean Architecture,恐怕有點難度。Teddy建議搭配Uncle Bob的《Clean Architecture》一起服用,一本學理論,另一本學實作,學習效果更佳。

第二點Teddy覺得比較嚴重,書的標題雖然是「Get Your Hands Dirty on Clean Architecture」,但作者在實作上滿多地方參考六角形架構(Hexagonal Architecture)並使用六角形架構的術語。例如,在第三章程式結構中使用inoutport這些六角形架構的術語,而非Clean Architecture書中採用的術語。雖說Clean Architecture與Hexagonal Architecture大同小異,但兩者所用的術語還是略有不同。所以在一本標榜Clean Architecture實作的書中採用「鄰國術語」,Teddy還是覺得略有不妥。

此外,硬是要用in、out來區分adapter,Teddy也是略有疑慮。作者提到in adapter代表由外部呼叫系統,out adapter代表有系統呼叫外部。例如,web controller是in adapter,repository或persistence adapter是out adapter,這沒問題。那麼Event Bus呢?它有時候是in,有時候是out,要把它放在那個目錄裡面?還是把接收資料的event bus adapter放在in,傳送資料的event bus adapter放在out?Teddy沒有這樣設計過,所以對於這種區分adapter的方法還需要思考一下。

第三點,書中第6章:Implementing a Persistence Adapter的實作建議Teddy不太認同。書中建議在這裡也套用單一責任原則,讓一個Persistence Adapter就只做一件事,例如將Account物件的載入、更新、建立設計成以下三個介面:LoadAccountPort、UpdateAccountStatePort、CreateAccountPort。Teddy比較建議在這裡套用DDD的Repository設計模式,讓一個Aggregate對應一個Repository來處理儲存的問題。

以上述的Account為例,若採用event sourcing來保存物件狀態,根本不會有書中建議的UpdateAccountStatePort與CreateAccountPort介面,只需要save與load這兩個介面。

最後一點,這是一本介紹Clean Architecture實作的書,程式範例理應很乾淨。但書中有部分範例卻「不太乾淨」,例如下圖書中第35頁的SendMoneyService,它應該位於Clean Architecture的Use Case層。直接在它身上貼上@Transactional似乎有跟框架產生耦合的嫌疑。

AM-JKLXL_RMLN1Vysq-gO7eYxYEXtD1eDLhHM_RsWlNCbEtbKJBSBF4eCFhuuv4lJIrCPpNOCmpkUTJB_aEHLAF7hCKwFLezynJYzAYr8k4hD0bBmlPZNiVHG_52238zSlJBGbApMT9dqQn62d689W-_f4ZCog=w2216-h468-no?authuser=0

友藏內心獨白:值得一讀。


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK