有幸參與了一些領域驅動的項目,讀了一些文章,也見識了一些不倫不類的架構,感覺對領域驅動有了更進一步的認識。是以今天跟大夥探讨一下領域驅動設計,同時也對一些想要實踐領域驅動設計卻又無處下手,或者一些正在實踐卻又說不上領域驅動設計到底好在哪的朋友一些指引方向。當然對于”領域驅動設計”這個主題而言從來不乏争論,是以大家可以在暢所欲言。
為什麼要使用領域驅動設計?
從Eric Evans的《領域驅動設計:軟體核心複雜性應對之道》一書的書名就可以看出這一方法論是為了解決軟體核心複雜性的。也就是說軟體業務越來越複雜了,領域驅動設計可以讓事情變得簡單。而實際情況是:領域驅動設計的門檻很高,沒有很深厚的面向對象編碼能力幾乎不可能實踐成功。
這一說法是否自相沖突呢?Martin Fowler在PoEAA一書中給了一個有力的解釋:
我們把三層架構等除了領域驅動之外的架構方式都可以歸納為以資料為中心的架構方式,在圖中是黑色的粗實線;
領域驅動設計在圖中是綠色的粗實線。
當軟體在開發初期,以資料驅動的架構方式非常容易上手,但是随着業務的增長和項目的推進,軟體開發和維護難度急劇升高。
領域驅動設計則在項目初期就處在一個比較難以上手的位置,但是随着業務的增長和項目的推進,軟體開發和維護難度平滑上升。
這幅圖形象的解釋了領域驅動設計和傳統的軟體架構模式兩者在軟體開發過程中解決複雜性之間的差異。
領域驅動設計的核心是什麼?
顧名思義,領域驅動設計的核心是領域模型,這一方法論可以通俗的了解為先找到業務中的領域模型,以領域模型為中心驅動項目的開發。而領域模型的設計精髓在于面向對象分析,在于對事物的抽象能力,一個領域驅動架構師必然是一個面向對象分析的大師。
在面向對象程式設計中講究封裝,講究設計低耦合,高内聚的類。而對于一個軟體工程來講,僅僅隻靠類的設計是不夠的,我們需要把緊密聯系在一起的業務設計為一個領域模型,讓領域模型内部隐藏一些細節,這樣一來領域模型和領域模型之間的關系就會變得簡單。這一思想有效的降低了複雜的業務之間千絲萬縷的耦合關系。
下圖為“以資料為中心的架構模式”,表和表之間關系錯綜複雜:
下圖是“領域模型”:領域和領域之間隻存在大粒度的接口和互動:
初期學習DDD的朋友一定不會錯過Eric Evans寫的《領域驅動設計:軟體核心複雜性應對之道》,這本書名氣很大,也是很多人入門領域驅動設計的首選讀物,這本書提到了領域驅動設計中的一些概念:Repository,Domain,ValueObject等。但是初學者有可能得出一個錯誤的結論:有人誤認為項目架構中加入***Repository,***Domain,***ValueObject就變成了DDD架構。如果沒有悟出其精髓就在項目中加入這些概念,那充其量也不過是個三層架構;反之對于一個面向對象分析的高手而言,不使用這些概念也可以實作領域驅動設計。
以IUserRepository這樣一個接口定義為例:
一個IUserRepository是一個Repository,他隻能以User聚合根為機關進行操作。方法List<Rule> GetRules(int id)将此Repository打回了原形,這不再是一個Repository,這是一個DAL。
正确的實作方式:
這段代碼展現了User作為一個領域模型,他擁有自己的職責和能力。
如何開始實踐領域驅動設計?
正如本文通篇所說,領域驅動設計講究的是領域模型的分析和對事物的抽象,從來沒有提起過資料如何存取這個話題,言下之意在領域驅動設計中,我們不關心過資料如何存取,怎麼樣寫linq效率高,使用懶加載還是include,這些實作細節會将你帶入傳統的三層架構模式中。
在領域驅動設計中要先設計領域模型,接着寫Domain邏輯,至于資料庫,僅僅是用來存儲資料的工具。使用database first那不叫領域驅動設計,很明顯你先設計的表結構,是以應該叫資料庫驅動設計更為準确。更不要引入資料庫獨有的技術,例如觸發器,存儲過程等。資料庫除了存儲資料外,其餘一切邏輯都是Domain邏輯。
我們不妨以大家都比較熟悉的醫院門診看病流程舉個例子,看看如何開始實踐領域驅動設計:
我們暫且認為一個門診看病流程就是一個完整的領域模型,此時你要忘掉資料庫,不要再想表結構如何設計,而是就這一領域模型進行抽象:
我們暫且不讨論這一模型是否符合真實場景,但是這個例子帶你邁入了領域驅動設計的第一步,同時這個例子也向你展示了軟體開發可以不用先設計資料庫。當你寫好所有的Domain邏輯後再考慮把這個類持久化在資料庫中就好了。在我眼中,資料庫僅僅是一個儲存資料的東西,不要把他過早的耦合在代碼中。這一強調了很多遍的觀點影響着你能否成功實踐DDD。
CQRS架構展望
話雖這樣說,但是既然你在使用關系資料庫,有人就會免不了跟你提起性能怎麼優化這樣的話題。這也是傳統ORM+關系資料庫實作領域驅動設計的硬傷,特别是當你的領域模型Scope設計過大,意味着Repository中的操作每次都要關聯一堆表出來,特别是有人設計資料喜歡遵守第N範式這種基本就沒轍了(沒有貶低遵守這些範式的意思,隻是這樣設計的資料庫+ORM會産生較多關聯,相對應的設計為表結構備援設計,有利于ORM提升性能),不得不說到了最後由于資料庫的存儲性能問題,我們又一次将資料庫納入到了考慮範圍。
解決這一問題的方案是CQRS架構, Query端各種緩存和Nosql,順便把搜尋引擎也用上,讓你的軟體飛奔起來。這一架構解耦了資料庫操作,你基本沒有機會跟資料庫打交道并且還解決了資料存儲的性能問題。
這一進化過程也解開了一些人的疑慮,為什麼從剛開始寫代碼就開始學習各種設計模式,但是從來沒有機會使用過?因為你所寫的代碼無時無刻不耦合着資料庫這一“毒瘤”,而資料庫操作作為一種實作細節摻雜在你的代碼中,是以領域驅動設計為此而生,你準備好了嗎?
作者:Richie Zhang
來源:http://www.cnblogs.com/richieyang/
聲明:本文版權歸作者和部落格園共有,歡迎轉載,但未經作者同意必須保留此段聲明,且在文章頁面明顯位置給出原文連接配接,否則保留追究法律責任的權利。