對了順到先說一下,這幾個東西的概念都是從《Agile Software Development, Principles, Patterns, and Practices》裡提到的,其中它是專門用來討論 package、module、component,放正有很多種意思,然後這裡只要想成某一些程式碼的集合就好。
然後今天要談的,就是要如何讓這個程式碼的集合(模組)可以更 cohesion。接下來我們就來談談這三個原則
然後有個重點要先說
聚合這三個原則,都是 base 在解耦的前提,也就是說它希望在不影響其它元件情況下,越聚合越好
這個概念是由 Robert C. Martin 在 《Agile Software Development, Principles, Patterns, and Practices》所提出,內容如下 :
The unit of reuse is the unit of release. Effective reuse requires tracking of releases from a change control system. The package is the effective unit of reuse and release.
我事實上當初在看這個原則的定義時,有點看不太懂,而且這和聚合性有什麼關,後來悟了一下,下面是我自已比較理解的句子 :
要 reuse 的元件,應該要一起 release,所以反過來說,要一起 release 的元件,就應該都放在一起。
因為如果一個開發者寫了一個 class 說它是可以重複使用的,事實上也只是一開始可以用,但是接下來在變更之後的事情,能不能重用就是另一回事。
備註 : 事實上還有一段就是說要 reuse 時不要 copy 原始的程式碼,因為舊有的改了,copy 的就沒辦法跟蹤了,但我自已在想,這不是應該是每個開發者都知道的嗎…
然後這個我在實務上算有看過,但通常比較常發生在為了切而切的地方,例如三不五時就切個 lib 或微服務,然後每一次 release 時發現,要等其它 lib 上完後,才能 release。
所以在設計元件時,通常要確定他是可以被獨立運行與佈署的,以 libary 來說,版控就是一個實踐 REP 的方法,但是如果本來拆分時就和其它服務職責重疊與依賴太多,那就沒救了……
然後最後書中還有提到一句話如下,我自已覺得讓我在拆分時也有個方向。
一個元件中的類別若不是全部都是可重複使用的,那麼就必須全部不是可重複使用的。
The classes in a package should be closed together against the same kinds of changes. a change that affects a package affects all the classes in that package.
這個原則到很好理解,而且實務上也是很實用,它的主要概念為 :
經常一起變化的元件,就應該放在一起,因為他們的變化原因可能很相同
假設我們有兩個元件,分別為 :
這個時後如果你將 order 與 suborder 分開來在兩個元件,或是兩個微服務,那和找死差不多,如果某個商品退款了,然後 order 就要修改某個欄位,接下來如果分 2 個 module 就是 2 個都要動,然後如果是微服務就又需要想分散式事務…。然後順到說一下,這個概念事實上很接近後面 DDD 的 Aggregate 要說明的概念,這個後來在來談談。
那要如何遵守呢 ? 在開發上,我要如何判斷那些東西要放在一起呢 ? 那些不用呢 ?
這裡我先簡單談一下我的想法,詳細後面會說,如果是 domain layer,通常我們會設計 domain model,然後假設我們現在有 2 個 domain model 我們用 A 與 B 來說明,然後在開發初起他們還很獨立,也就是說不會一個一個欄位變了,會去影響到另一個,但開發久了發現,我的 A 欄位變動,同時間也需要去改 B 的,越來越多,那就是該考慮合成一個 Aggregate 了。
The classes in a package are reused together. if you reuse one of the classes in a package, you reuse them all.
這一個原則根據原文來看,他的主要概念如下 :
經常一起被使用的類別應該放在一起,包含依賴的東西。但反過來說不被依賴的就不要包在一起。
就像是我們實務上不是很常有 service 與 repository ,然後通常會透過 service 去 repository 抓資料,所以如果有 userService 與 userRepository 的話,他們就應該被放在同樣的模組中。
但是我這裡想到一點,就是我們通常會依賴一些 common 類的東西,那這個東西要怎麼辦法 ? 如果根據這個原則那就會包含同一個模組中,但這樣其中一個模組就又要自已做一個 common 類的東西 ? 所以這裡我通常會先想一下依賴的東西的特性。
衝突的情境
維護與重複使用: CCP 強調對變更的封閉性,CRP 強調類別之間的重複使用。如果兩個類別經常一起使用,但它們在不同的包中,這可能會違反 CRP。然而,如果這兩個類別對變更的影響是不同的,將它們放在同一個包中可能會違反 CCP。