程式碼模型組織方式

微笑刺客D發表於2020-11-22

結構劃分迷霧

Asp.Net Boilerplate中預設專案結構是如下所示(專案代號Gravel),每層都是一個單獨的類庫或是應用程式。

- Gravel.sln
  - Gravel.Web
  - Gravel.Application
  - Gravel.Core
  - Gravel.EFCore

在這種固有分層方式下,ABP沒有指明要採用什麼形式去劃分限界上下文,是採用資料夾隔離形式還是採用類庫隔離形式,並沒有嚴格說明。
注意:具體是在應用層領域層基礎設施層中需要隔離限界上下文。

資料夾隔離

如採用資料夾隔離形式,則解決方案結構如下,在每一層中建立資料夾形式以此來劃分限界上下文的邊界。

- Gravel.sln
  - Gravel.Web
  - Gravel.Application
    - OrderCenter
    - ProductCenter
    - CustomerCenter
  - Gravel.Core
    - OrderCenter
    - ProductCenter
    - CustomerCenter
  - Gravel.EFCore
    - OrderCenter
    - ProductCenter
    - CustomerCenter

類庫隔離

如採用類庫隔離形式(即依照限界上下文拆分類庫),則解決方案結構如下,Gravel作為承載體,其餘三個作為上下文獨立出來,按照上下文的邊界高於分層的邊界(這種劃分也更加合理)。

- Gravel.sln
  - Gravel
    - Gravel.Web
    - Gravel.Application
    - Gravel.Core
    - Gravel.EFCore
  - OrderCenter
    - Application
    - Core
    - EFCore
  - ProductCenter
    - Application
    - Core
    - EFCore
  - CustomerCenter
    - Application
    - Core
    - EFCore

對於Asp.Net Boilerplate,見到的幾個Demo及部落格園內一些作者,都是採用的第一種風格形式,即分層邊界高於上下文的邊界。
而對於第二種形式,在ABP VNext的MicroserviceDemo中採用的是這種形式。並且在ABP VNext中,這種形式的變體是可以從單體切換到微服務的。

注意:這裡的解決方案結構並不是固定如此,因ABP中模組化設計,有些是可以刪除的。

迴歸本質

這樣拆分的目的是什麼?為了劃分限界上下文,為了達到清晰邊界,從而控制住上下文內部。

架構沒有清晰的層次,職責缺乏合理的分配,程式碼變得不可閱讀和維護,最終形成一種無序設計

從分層形式角度出發,分層形式有物理分層和邏輯分層,DDD中提到的分層是屬於邏輯分層,邏輯上劃分了應用層領域層基礎設施層,並沒有規定物理分層的形式,即沒有規定是整個專案劃分成一個類庫還是多個類庫,也沒有規定整個專案是劃分成多個上下文,每個上下文是一個類庫還是多個類庫。

如果不考慮內部類庫的數量,本身其實關注的就是如何組織多個限界上下文,是在一個專案中組織還是一個專案中拆分成多個限界上下文組織。

程式碼模型組織策略

http://www.codingthearchitecture.com/2015/03/08/package_by_component_and_architecturally_aligned_testing.html

按層次劃分

採用資料夾形式劃分本質上是一種按層次劃分,同一層中,依照限界上下文,劃分不同的邊界,這是一種近乎常規化的劃分方式。

按特性劃分

依照垂直劃分方式,將限界上下文垂直物理拆分,每個限界上下文內都是一個獨立的團體。該團體內部仍然可以是分層架構的。

按元件劃分

在特性劃分基礎上再昇華,除去UI部分,組成元件,依照限界上下文形式組合,這也更貼近考慮DDD時不要納入UI層。如此劃分後,其他的Controller可以通過元件形式訪問某個限界上下文中的資料。

結構劃分迷霧消散

給定的AspNet Boilerplate或是AspNet Zero中都是採用的按層次劃分的形式,但並沒有說按照元件劃分不可行,畢竟在一個gitee倉庫中看到過按照元件劃分的形式,而且是可用的。而對於ABP VNext更推薦按元件劃分的形式,主要參考是MicroserviceDemo中的格式。

所以最終迷霧也就解除了,是ABP沒有規定必須要按照哪種格式去組織程式碼,因為對於AspNet Boilerplate來講,模組化的設計,本身可以允許按照層次劃分與按照元件劃分,至於選用哪種方式,更多的是,使用者自身去選擇,也從另一方面看出ApNet Boilerplate本身作為基礎框架,提供了使用者更多的選擇性。

AspNet Boilperlate按層次劃分形式組織程式碼

AspNet Boilerplate按元件劃分形式組織程式碼

總結

對於實際使用中來講,如果按照層次劃分,使用ABP時總有點說不出來的感覺,不知道如何去管理程式碼,寫的爽時,直接把其他上下文中的應用服務,領域服務或是倉儲直接搬到當前的限界上下文中用,這也就導致後期程式碼看起來很凌亂,耦合也嚴重。

想要通過按層次劃分引入防腐層來避免直接依賴,卻要遵循約束,必須強行遵守紀律,通過防腐層去訪問其他限界上下文。

從這一角度考慮,也逐漸理解了為什麼要限界上下文的邊界要高於分層的邊界,按照元件劃分的形式,直接斷絕了限界上下文間的直接呼叫,而是採用防腐層或是其他形式去做中間隔離,類似代理形式解決直接耦合問題,同時也方便往微服務方向拆分時不會拖泥帶水。

2020-11-22,望技術有成後能回來看見自己的腳步

相關文章