Clean Architecture 實作篇 (八)

架構層之間的對應策略

elliot
Feb 17, 2024

架構層之間的對應到底該怎麼做呢? 我相信這是大家多多少少都會遇到的問題,就像最近公司同仁提及到底 Request 的驗證到底該如何歸屬,該驗證哪些範圍,而哪些不屬於 Request 的驗證又該如何歸屬呢?

我想,這和 “模型” 非常有關,意思說 我們應該先對於不同層級之間的 “模型” 應該要有所了解,才能去定義 “驗證的歸屬”

而該如何區分層級之間的模型? 是否共用? 是否對應?

讓我們看看 對應不對應 會發生什麼事

對應:每一層級的對應關係會產生大量差不多的程式碼,尤其只是運用在單純的CRUD身上顯得多餘。

不對應:架構層之間都共用相同的模型,這會導致耦合在一起,意思是說這個模型同時要對多層級(多角色)去負責,明顯違反 SRP,當某一層級改變時就會影響到其他層級。

因此不論是對應或是不對應都有情境上的考量,不適用於 萬用解

因此可以區分成 四種對應方式,分別是 不對應策略、雙向對應策略、全部對應策略、單向對應策略

不對應策略

也就是上面提及的,不同架構之間都是共用相同的模型

在只有非常單純的CRUD情境,且確保每一層都需要相同的資訊、相同的資料結構,那麼大可以選擇這種方式,But 通常隨著時間,會演變成具有多樣行為、各種驗證、並且需要更複雜對應策略。

雙向對應策略

架構層各自有一份模型,對於輸入轉接埠來說,就是把網頁層模型 (WebModel) 轉換成 領域層模型 (Account) ; 相對的當透過輸入轉接埠將 領域層模型(Account)傳回時,也需要對應回網頁層模型(WebModel)

這樣的做法的好處是,符合單一職責,且概念上相對單純。不過壞處就是因為這種做法會大量的採用領域模型,不論是輸入轉接埠 或是 輸出轉接埠 都會需要領域物件當作輸入參數 及回傳值,這也間接的導致領域層的模型容易受到外層架構的需求影響而改變,但是實際理想上,領域模型只應該基於領域邏輯而變動。

全部對應策略

意思是說對應的策略是依據 作業 為單位,每一種作業都有各自的模型,意思是說模型是不會共用的,但也也讓樣貌非常的明確,可以直接看得出來不同使用案例有不同的模型,有哪一些驗證的規則。

從網頁層和領域模型層之間的對應相比,這也意味著,從某一層要對應到更多不同的命令,也代表需要更多的程式碼。但是實質上因為程式碼是集中在一處的,維護上還是輕鬆。

而最大的好處是 可以在網頁層與應用程式層之間,明確的將 會變化的狀態使用案例表達出來;但是對於應用程式層 和 儲存層之間,就不適合這模做,成本太高了。

單向對應策略

所有架構層級的模型都實做統一介面,以 getter 去存取 attribute的方式,不同層級可以透過這個介面單向對應回該架構層所需的模型,也不用擔心改到領域物件的狀態(因為修改行為不在介面上)

這樣的好處是,對於外層架構來說,可以決定需不需要轉譯、直接操作介面操作、單向的對應為自身所需的模型。

對於應用層來說,領域模型可以實作各種操作,再透過服務取回。當需要傳遞到外層時,可以不做對應就傳出去,因為內外都已經實作了介面。

不過,由於對應的轉譯工作會落在各架構層,已概念上來說相對複雜;通常只有在各層架構模型差異性不太大的情境下,才能發揮這種對應策略的最大用處,例如:在唯獨的情境下,通過界面就能取得所需的資訊了不用特地轉譯。

總結

應該依據實際情況去決定對應的最佳策略,不該限定只使用某限定方式,然後套用到全部的 code base 裡,這樣只是滿足心裡層面的整潔,而強迫套用不適合的對應策略在各情境。

這是需要團隊共識的,應該先了解各對應策略,才能取得 何時 何種 的對應策略,進而產出一份 決策指引(guideline)

而決策指引中應該要能夠 為何這個策略會是首選,以供未來回頭檢視當初採用的理由是否依舊存在。 且應該要依據使用案例是 [修改 / 查詢] 類型, [網頁層<-> 應用程式層 / 應用程式層 <-> 儲存層] 來訂製不同的決策指引

例如:如果使用案例是屬於 [修改類型] 的,那 [應用程式層與儲存層] 之間應該優先考慮不對應策略,原因是可以加快程式開發,不把時間心力花在儲存層的對應上,但如果儲存層會有對應上的需求就應該考慮 雙向對應,才不會讓儲存層影響到 應用程式層

… etc

--

--