DDD:指領域驅動設計,是domain driven design的縮寫。
介紹DDD基礎知識的相關文章很多,本文就不普及相關的基礎知識了,基礎理論知識可參考如下文章:
- 《DDD基礎知識與總結》
- 《DDD與分層架構》
1. 初識DDD
腳本式編程(dao+service)與DDD領域驅動模式區別如下:
其每一層的作用范圍和含義如下:
1)展現層(Presentation Layer):負責以Restful的格式接受Web請求,然后將請求路由給Application層執行,并返回視圖模型(View Model),其載體通常是DTO(Data Transfer Object);
2)應用層(Application Layer):主要負責獲取輸入,組裝上下文,做輸入校驗,調用領域層做業務處理,如果需要的話,發送消息通知。當然,層次是開放的,若有需要,應用層也可以直接訪問基礎實施層;
3)領域層(Domain Layer):主要是封裝了核心業務邏輯,并通過領域服務(Domain Service)和領域對象(Entities)的函數對外部提供業務邏輯的計算和處理;
4)基礎實施層(Infrastructure Layer)主要包含Tunnel(數據通道)、防腐層,Config和Common。這里我們使用Tunnel這個概念來對所有的數據來源進行抽象,這些數據來源可以是數據庫(MySQL,NoSql)、搜索引擎、文件系統、也可以是SOA服務等;Config負責應用的配置;Common是通用的工具類。
常見的領域驅動業務調用鏈過程如下圖所示:
調用過程大致如下:
- 業務調用方基于網關傳入DTO數據,為了便于區分業務場景,將DTO數據又細分為CQE三種模式的數據。
- 業務數據傳入后,基于Spring Validation等模式做基礎數據驗證(如必填,格式,大小等基礎驗證);
- 數據進入到Controller層,并調用應用層相關的應用功能;
- 應用層不做具體的業務實現,只做編排處理,做業務的流程處理。應用層可做如下操作:
- 應用層調用防腐層查詢其他系統的數據;
- 應用層調用倉庫層查詢本系統相關的數據;
- 應用層調用工廠創建實體(簡單實體,可在應用層直接生成);
- 應用層調用第三方領域服務,實體或聚合根的方法處理業務邏輯;
- 應用層調用倉庫層保存數據;
- 工廠創建實體,簡單的實體可不基于工廠創建;
- 領域層處理實體的行為,核心業務邏輯處理放在領域層,領域層可調用基礎層的所有模塊處理業務(領域層原則上不直接調用倉庫層保存數據,保存數據應該放在應用層調用);
- 倉庫實現層最終落地數據,進行數據存儲(其他層不能直接與Tunnel(數據通道)交互,必須基于倉庫層才可以);
- 一個業務行為結束后,若產生副作用,再應用層發出事件通知,其他模塊再監聽處理。(事件歸屬應用層還是領域層,網上各有不同的方案,本例是放在應用層。領域層本身只是內存化操作。等一個實體行為真正數據存儲成功后,再發出事件,便于理解和維護。)
2. 巨人的肩膀
作者接觸DDD相關知識,是從一篇名為《一文教會你如何寫復雜業務的代碼》的文章開始的。帶著好奇,越看越有共鳴,初步發現了DDD的神奇之處并一發不可收拾,開始入坑DDD領域驅動設計。在查看DDD各種教程博客時,綜合對比并摒棄一些低質量的博客,強烈推薦以下兩位老師的系列教程。
阿里-張建飛:張老師的新書《代碼精進之路》。
阿里-殷浩:
- 《DDD系列第一講》
- 《DDD系列第二講:應用架構》
- 《DDD系列第三講:Repository模式》
- 《DDD系列第四講:領域層設計規范》
- 《DDD系列第五講:如何避免寫流水賬代碼》
3. 為什么要寫DDD系列博客
在初步了解了DDD的相關知識后,作者的第一感受是:DDD概念很多,各種專業術語,一堆下來還有點復雜,看了理論知識,還是云里霧里。看了諸多理論博客,總結一句就是:“聽君一席話,如是一席話”。似乎明白了,又似乎還是什么都不懂。
經過第一輪的理論知識打擊后,作者決定還是繼續學習。既然理論知識太多,那就在實踐中去尋找真理。
DDD到底應該怎樣落地?
網上介紹DDD理論知識的相關文章很多,但真正介紹DDD如何應用在項目中的高質量技術文章就鳳毛麟角了,更別提有完整示例的項目了。在這個探索的過程中,作者發現了殷浩的系列DDD教程,張建飛的COLA 4.0開源項目。
為了更透徹地掌握DDD相關的知識細節,并考慮落地DDD模式到公司的項目,還是沒有采用開源項目COLA 4.0。作者選擇通過殷浩老師的系列教程,一步一步開始DDD的探索之路。
適逢公司剛好存在一個老項目急需改造,老系統是基于(dao+service)腳本式編程開發的。由于時間較遠且不同時間段由不同的開發人員維護,這種老代碼,呵呵呵,懂得都懂。團隊討論決定就用這個項目來做DDD的落地。
雖然一開始看了很多理論知識文檔,一些技術實現細節文檔。但在編寫初版本的DDD設計文檔時,依舊發現特別的別扭,總感覺很奇怪。本質原因還是缺乏DDD設計經驗,并且對DDD的各個知識點,分層細節理解不夠深入。在這個迷茫階段,作者抱著試一試的心態,嘗試加了殷浩老師的釘釘,所幸他同意了。后續就是請教學習了,請教各種理論細節的實現和注意事項。在這個過程中,有以下幾點感想:
- 深入理解理論知識,需要落地去反復的驗證,總結出來的理論知識一般具有高度的概括性,為什么是這樣,不這樣會如何往往需要自己去驗證;
- 自以為已經明白了理論知識,但在實際項目使用中,卻是錯誤地使用,比如倉庫層,領域層的一些細節問題;
- DDD落地困難的點還在于實現一個功能可以有不同的模式,這些模式不一定都對,但從功能實現層面來說卻是都可以完成功能。比如,你在領域層直接調用倉庫層保存數據,但領域層本身只是做純內存化的業務邏輯處理,領域層是不可直接操作數據的。諸如此類的問題,導致不同的人對DDD理解不同,實現模式也不同。由于每一層的標準,實現方案不完全不同,才導致了DDD落地的復雜性。
- DDD做設計時,不單是對領域層做業務設計,應該是拉通整個流程一起做設計。
- 實體,聚合根,這些概念在實際項目中落地到具體的業務場景時,需要反復的迭代設計。
- 規范無處不在,注重編程細節,小到命名,大到使用設計模式,都需要規范編碼。DDD在不同的層面,需要開發人員更加注重規范,不可張冠李戴,錯誤如:在倉庫層里面寫業務邏輯。
- 特別感謝殷浩老師的耐心指導,技術人傳道授業,簡單而純粹。這份技術人獨有的編碼情懷和工匠精神,很帥。
本文旨在為使用或學習DDD模式的同行者,提供一個快速的入門案例(案例gitHub地址),拋磚引玉,共同學習。目前網上還缺乏完善的DDD設計案例,本著相互探討和學習的思想,現基于實際的案例,在脫敏處理后,詳述DDD從理論到落地的流程。大致分為以下模塊:
- 《DDD領域設計-案例-需求說明文檔》
- 《DDD領域設計-案例-建模設計說明》
- 《DDD領域設計-項目目錄結構說明》
- 《DDD領域設計-案例-源碼使用說明》
- 《DDD領域設計-設計規范》
特別說明DDD落地的方案沒有統一的標準,本系列文章采用的技術方案也不一定能完全實現DDD的思想。由于作者水平有限,在一些理解上面若出現偏差,歡迎指導和批評。