在五彩石項目啓動伊始,就決定採用領域驅動模型來設計業務框架,可是因爲當時好多人對該模型的不熟悉,以及對一些設定的難以理解,致使第一版的代碼仍是存在很多mvc的影子的。隨着你們對該模型的逐漸瞭解,一致認爲須要對業務代碼作一些優化,因而組內在8月份啓動了二次DDD改造的內部迭代,通過不斷的灰度放量,近期已經全量放開了新版業務邏輯。數據庫
關於對DDD的理解,每一個人均可以是不一樣的,而且依據不一樣的理解所寫的業務框架也是不一樣的,只要在必定的範圍內可以邏輯自洽,那是沒問題的。在啓動DDD改造前,組內也作過一些分享,制定了一些規範,本文就是對組內這些規範的一個總結。編程
流量請求入口。
用戶接口層負責向用戶顯示信息和解釋用戶指令。這裏的用戶多是:用戶(H5/APP)、程序(API)、消息隊列(MQ)、超時中心回調,自動化測試和批處理腳本等等。緩存
在最初的設計中,只有用戶的調用是放在這一層的,其餘調用是放在了application,這樣致使了兩個結果,分層不明確和入口分散。架構
因此本次將全部的流量入口所有放在了interfaces作收口。mvc
應用層鏈接用戶接口層和領域服務層,它是很薄的一層,主要職能是協調領域層多個聚合完成服務的組合和編排。
應用服務層是很薄的一層,理論上不該該有業務規則或邏輯,主要面向用例和流程相關的操做。但應用層又位於領域層之上,由於領域層包含多個聚合,因此它能夠協調多個聚合的服務和領域對象完成服務編排和組合,協做完成業務操做。app
應用層也是微服務之間交互的通道,它能夠調用其它微服務的應用服務,完成微服務之間的服務組合和編排。框架
在設計和開發時,不要將本該放在領域層的業務邏輯放到應用層中實現。由於龐大的應用層會使領域模型失焦,時間一長你的微服務就會演化爲傳統的三層架構,業務邏輯會變得混亂。dom
舉個精簡的例子,假設出價分四步,
一、調用商品接口校驗商品是否上架,
二、出價規則校驗,
三、數據落地,
四、調用庫存接口生成庫存;微服務
那麼應用層的主要功能就是編排這四步,不作業務處理。其中第1步和第4步放到基礎層處理(基礎層封裝外部RPC),第2步在規則域執行,第3步在出價域執行。性能
在第一版的設計討論中,有過一個定義是查詢業務能夠穿領域層,直達基礎層,理由是純查詢的業務沒有複雜的邏輯,僅僅是拿數據而已。但這也只是一個想法而已,通過實際的業務實踐可知查詢仍是有不少的業務邏輯組裝,而基礎層是不處理業務邏輯的,拿到數據後只能在應用層作封裝,致使了應用層過於厚重。同時也考慮到一個合理的規範性,約定一樣的流程之後,會更好的推動DDD。
領域服務層是由多個業務職責單一的聚合構成,實現核心的領域邏輯。
領域層的做用是實現領域核心業務邏輯,經過各類校驗手段保證業務的正確性。領域層主要體現領域模型的業務能力,它用來表達業務概念、業務狀態和業務規則。
領域層包含聚合根、實體、值對象、領域服務等領域模型中的領域對象。領域模型的業務邏輯主要是由實體和領域服務來實現的,其中實體會採用充血模型來實現全部與之相關的業務功能。
什麼是充血模型與之對應的是貧血模型,咱們常用的MVC模型中,實體類只定義屬性,並無定義實體行爲。這種將數據與業務邏輯分離,實際上是違反了 OOP 的封裝特性,其實是一種面向過程的編程風格。任意代碼均可以修改實體的屬性,那麼實體的屬性值就不受限制了。這實際上是自下而上的設計思想,是SQL 驅動(SQL-Driven)的開發模式。
而充血模型則是將該實體全部行爲也進行了定義(好比save,modify,remove等操做)。任何想要修改實體屬性的操做,必需要經過實體自己來實現。這是一種自上而下的設計思想,由具體的業務驅動開發,不須要關心底層的SQL實現。
實體和領域服務在實現業務邏輯上不是同級的,當領域中的某些功能,單一實體(或者值對象)不能實現時,領域服務就會出馬,它能夠組合聚合內的多個實體(或者值對象),實現複雜的業務邏輯。
聚合根是一種更大範圍的封裝,把一組在業務上不可分隔的實體和值對象聚合在一塊兒,經過根實體的惟一標識對外提供能力。
實體是領域中須要惟一標識的領域概念。相同的兩個實體,若是惟一標識不同, 那麼即使實體的其餘全部屬性都同樣,咱們也認爲它們兩個是不一樣的實體,好比同一個用戶對同一個sku同價格的兩個庫存實體,除了主鍵ID外,其他均相同,但這仍然是兩個實體。
同時,不該該給實體定義太多的屬性或行爲,而應該尋找關聯,將一些屬性或行爲轉移到其餘關聯的實體或值對象上。 好比Inventory實體,會存儲一些商品信息(sku、spu等),因爲商品信息是一個完整的有業務含義的概念,因此,咱們能夠定義一個Commodity對象,而後把Inventory實體中商品相關的信息轉移到Commodity對象上。若是沒有Commodity對象,而把這些商品信息直接放在Inventory對象上,而且若是對於一些其餘的好比費用信息、倉庫惟一碼等信息也放到進去,會致使Inventory對象很混亂,結構不清晰,最終致使它難以維護和理解。
值對象就是上面所說的Commodity對象,並非每個值對象都必須有一個惟一標識,也就是說咱們不關心對象是哪一個,而只關心對象是什麼。以Commodity對象爲例,若是有兩個Commodity的spuId是同樣的,咱們就會認爲這兩個Commodity是同一個。也就是說只要spuId同樣,咱們就認爲是同一個商品。
基礎設施層是數據封裝層,在這裏獲取各種數據,好比數據庫,緩存,外部領域,外部接口等。
基礎層是貫穿除領域層外全部層的,比較常見的功能仍是提供數據庫持久化和外部領域服務調用的。
基礎層包含基礎服務,它採用依賴倒置設計,封裝基礎資源服務,實現應用層、領域層與基礎層的解耦,下降外部資源變化對應用的影響。
好比說,在傳統架構設計中,因爲上層應用對數據庫的強耦合,不少的架構演進中最擔心的可能就是換數據庫了,由於一旦更換數據庫,就可能須要重寫大部分的代碼,這對應用來講是致命的。那採用依賴倒置的設計之後,應用層就能夠經過解耦來保持獨立的核心業務邏輯。當數據庫變動時,咱們只須要更換數據庫基礎服務就能夠了,這樣就將資源變動對應用的影響降到了最低。
Domain 層再也不直接依賴 Infrastructure 層,而是引入了一個適配器模式(Port/Adapter),使用DIP(Dependency Inversion Principle,依賴倒置)反轉了 Domain 層和 Infrastructure 層的依賴關係,其關係如上圖所示Domain 層以接口的方式開放端口,讓Infrastructure層去實現,這樣設計的有點是 Domain 層的演變和進化徹底是獨立的,向上不受 Application 層影響,向下不受 Infrastructure 層影響。
舉個例子,領域層是經過倉儲接口(repository)獲取基礎資源的數據對象,倉儲接口會調用倉儲實現,具體的基礎資源的數據處理過程是在倉儲實現中完成的。這樣作的好處是,避免將倉儲實現的代碼混入上層業務邏輯中。若是之後替換數據庫,因爲作了基礎資源的個性的代碼隔離,因此實現了應用邏輯與基礎資源的解耦。在更換數據庫時只須要更換倉儲相關的代碼就能夠了,應用的邏輯不會受太大的影響。
分層是爲了各層獨立演進的,上層使用下層定義的服務,而下層對上層一無所知,另外每一層對上層隱藏細節實現,依賴契約交互,獨立層在技術方案調整時只要遵照契約則能夠作到上層無感知遷移,這樣也方便各層的維護和標準化工做。DDD 有兩種架構,嚴格分層架構和鬆散分層架構。優化後的 DDD 分層架構模型就屬於嚴格分層架構,任何層只能對位於其直接下方的層產生依賴。而傳統的 DDD 分層架構則屬於鬆散分層架構,它容許某層與其任意下方的層發生依賴,建議使用嚴格分層架構。
interfaces 層: request、response
application 層:DTO(data transfer object)
domain 層:entity、VO(value object)
infrastructure 層:PO(persist object)
首先用戶接口層經過 request/response 對象來進行跨進程間的交互數據;應用服務層使用(DTO)來進行數據交互;在領域內部,咱們經過領域對象(entity/VO)做爲領域內部的數據和行爲載體;在基礎設施層,咱們使用持久化對象(PO)進行數據庫資源的交互。
也被稱適配層或者轉換層
在一個上下文中,有時須要對外部上下文進行訪問, 一般會引入防腐層的概念來對外部上下文的訪問進行一次轉義。
有如下幾種狀況會考慮引入防腐層:
領域事件是領域模型中很是重要的一環,領域事件將會致使進一步的業務操做,有助於實現業務的解耦,並完成業務閉環。
舉例來講,領域事件是業務流程的一箇中間步驟,好比出價領域出價成功後將通知庫存域添加庫存動做;也多是批處理過程發生的事件,好比求購域批處理程序掃描求購業務表判斷是否要的羣體觸發基礎服務域的push服務告知求購用戶最新的求購進展。
領域事件能夠切斷領域模型之間的強依賴關係,事件發佈完成後,發佈方沒必要關心後續訂閱方事件處理是否成功,這樣能夠實現領域模型的解耦,維護領域模型的獨立性和數據的一致性。經過領域事件+補償機制來達到最終一致性,提升系統的穩定性和性能;
在一致性要求不高時,能夠經過領域事件訂閱器直接向消息隊列發送事件。
對一致性要求高時,須要先將事件存儲,而後經過後臺線程加載並分發到消息隊列。
以上就是出價組在二次DDD改造中的一些總結,下面以一個例子作結尾吧。
應用服務層主要是作流程編排等輕量邏輯,領域服務層完成領域內實際邏輯並持久化數據。
文|CJ BOYSCJ 是出價的拼音首字母縮寫,因爲組內都是Boy,因而團隊起名CJ BOYS。關注得物技術,攜手走向技術的雲端