戲說領域驅動設計(十三)——核心架構

SKevin發表於2022-03-14

  在做了兩章鋪墊後本章再續寫第九章。我們之前介紹過了好幾種架構模式,那麼本章只挑一種往死了整,這個架構其實就是在DDD書中所介紹的經典四層的變更版。這裡面需要注意一點,四層架構是洋蔥架構的一部分,儘管洋蔥型已經是微服務架構系統中一種事實上的標準,但我們不會對各類介面卡做重點介紹,那些東西一般都是開源的元件或者沒有業務邏輯的元件比如DAO。再說了,您都已經學習DDD了還需要我再講解什麼是DAO嗎?所以我們只介紹下面圖形中綠色邊界內部的東西。

一、基於CQS的ODD風格分層架構

  四層架構實際上更多的用於物件導向(也可稱之為物件驅動式)程式設計,如果是程式導向其實經典三層就夠了。下面圖展示了一個典型的四層架構的構成及各層間的訪問限制。如果您看過DDD相關的經典書籍會發現此圖和書上的並不一致,主要原因有兩點:1)省略了檢視層,那個不是我們的重點;2)資源庫實現理論上屬於基礎設計層,而我們在這裡進行分開是因為這個元件比較核心,我見過較多的案例都是把資源庫誤當DAO用,所以需要在此重點提出來講解。本來我這個系列文章就充滿了個性,我們們直面開發中的各類痛點會提供大量的乾貨而不是和其它文章一樣都含糊的帶過去。

  上圖,如果將“資源庫”和“基礎設施”二合一,您再根據依賴關係就能推匯出來這是一個典型的洋蔥架構。再加上比如RESTful、MQ等介面卡就是六邊型架構。這回您知道為什麼我說洋蔥和六邊型其實是一個東西的不同叫法了吧?除了層的結構資訊,訪問順序也是您需要重點關注的內容,如果違反了約束所謂的洋蔥也就不成立了(比如讓領域模型轉而依賴基礎設施,那領域模型就不再是架構中的核心了)。還有一點需要說明,在一個服務中(Service)通常會包含兩種不同的架構模式:查詢模式架構和命令模式架構,上圖屬於命令模式,查詢請參考下圖。一般來說查詢架構相對要簡單的很多,使用經典三層開發模式即可。

 

  根據上面兩圖所示:在同一個服務中使了兩種不同的架構模式,分別為Command端(簡稱C端)和Query端(簡稱Q端)),這種方法可稱之為命令查詢分離(CQS,請注意與CQRS作好區分)模式,這樣的區分會大大提升系統的開發效率和執行效率。由於查詢操作並不會修改資料也不會包含業務邏輯,所以工程師只需要面向“系統執行效能”即可,也就是查詢怎麼快怎麼來,層數少自然開發的速度也快,也可以把一些優化手段應用於查詢相關的程式碼中而不用考慮事務、一致性、物件封裝等各種條條框框的約束。而命令模式中,其要考慮的內容多、程式碼更加的嚴謹。不說別的,僅引數驗證就夠喝一壺的了(我也見過有些開發從不做引數驗證,依賴於前端的正確性判定。我跟你說,別說前端了,各包之間的呼叫都是不可信任的,所以驗證每個引數的合法性是必需甚至是強制的)……。

  C端架構圖中還標識了序號,表示設計的先後順序或編寫程式碼的順序。由於我們使用的是洋蔥架構,領域模型層必然要最先設計;緊接著自然是應用服務層,包引數驗證、組織業務流程控制、存取領域模型、釋出命令或事件等操作。注意,雖然此時尚沒有設計資料持久化等功能,但您別忘了資源庫的介面是在領域模型層定義出來的,所以是可以直接在應用服務中引用的,如果用的是Spring框架則可直接注入進來;第三個要做的工作是資料訪問層的設計包括DAO和資料模型,這一層您需要根據領域模型的特性和當前系統的基礎設施條件來決策使用什麼樣的後端儲存。最後要設計的是資源庫實現層,這東西負責把領域模型與資料模型互轉及領域模型的事務化儲存。Q端的設計順序正好與C端相反,先設計DAO再考慮應用服務,也就是先著重查詢效率再考慮資料出去前的加工。這兩個設計模型的順序限制目前並無現成的理論作支撐,應該是一種個人的最佳實踐,您可以考慮在專案中實驗一下,這個順序其實也符合了上一章說的先模型後服務的建議原則。

  雖然C端和Q端兩個圖並不是很精確,但仍然突出了厚度的不同。C端的領域模型層佔比較大,Q端的應用服務層則更為厚重一點(厚重不代表要先設計,只表示其會組織查詢邏輯比如資料的合併等,並非和DAO一樣只單純的關注資料的查詢)。

二、再續六邊形架構

  很多DDD強調了六邊形架構,但到目前為止我們在這方面並未投入過多的講解,主要是因為時機不成熟,而有了4層架構作為基礎則是最好的機會。我先貼一張《實現領域驅動設計》中關於六邊型的示意圖。同原圖不同,我在這個圖的上面畫了一條橙色的豎線,作用後面說。參照我們們前面的內容相信就可以揭開這個架構的神祕面紗了。繼續閱讀前請您注意,這裡的六邊型是針對每一個限界上下文而不是整個系統。

  首先,我們使用橙色的線把這個圖分成了兩部分,豎線左邊是應用程式的輸入端,右邊當然就是輸出了,而所有用於輸入和輸出的都稱之為介面卡。

  分割後,應用程式這個小六邊結構不變,是系統的核心。左邊的介面卡是應用程式的輸入埠,如果是微服務架構自然就是RESTful、gRPC等介面層;如果是微前端就是UI層;如果需要接收MQ,自然就是訊息監聽元件。右邊介面卡是為應用服務提供輸出能力,如果使用了資料庫,當然就是DAO元件;如果需要傳送MQ就是訊息傳送元件。六邊型架構在現在的系統中其實非常常見,您現在系統可能就是這個架構只是不知道它名字罷了。而基於微服務架構的系統,甚至可以認為其中的每一個服務都是六邊型的。講到此處有一點需要說明:DDD書中的六邊型強調了領域模型部分,而我認為這一部分是可選的,要視業務的複雜度而定。

  作為六邊型的核心,應用程式不能一筆帶過。如果使用了物件驅動的方式,其架構自然就是上面我們所講的四層模式;如果是事務指令碼,一般無業務模型的概念,因為您的業務已經集中於應用程式服務之中了。實際上現在有很多人反對事務指令碼,認為使用了事務指令碼其架構就不能稱之為六邊型。 但我個人認為六邊型是一種思想,它強調了業務應居於系統的核心,事務指令碼不代表業務是分散的。此外,我們應該從業務的角度來決策架構選型而不是過份的強調技術,這個思想會貫穿本系列文章。還有一點您記住了,不論書中寫的多麼天花亂墜,給的永遠只是參考和指導,具體哪些可以用到工作中需要進行取捨。

  相信通過上面的講解,您就會發現所謂的六邊型也沒什麼了不起的,也搞不好會感嘆一下:就這 ?

總結

  本章詳細介紹了4層架構的結構、訪問順序以及設計順序;同時,對六邊型架構(也就是洋蔥架構)做了補充性說明,相信您已經明白書上和網上常說的六邊型是什麼意思了。後面我們繼續對4層架構進行深入講解包括各類領域模型的作用以及一些程式碼案例。

相關文章