在做了兩章鋪墊后本章再續寫第九章。我們之前介紹過了好幾種架構模式,那么本章只挑一種往死了整,這個架構其實就是在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層架構進行深入講解包括各類領域模型的作用以及一些代碼案例。