领域驱动设计(DDD)的精髓
邊界是核心
無論是從宏觀到微觀再到納米層次,還是從戰略設計推進到戰術設計,領域驅動設計一直強調的核心思想,就是對邊界的劃分與控制。
從分析需求一開始,我們就需要通過確定項目的愿景與目標,劃定問題空間,由此確定核心子領域、通用子領域與支撐子領域。這是領域驅動設計的第一重邊界。它幫助團隊看清主次,理清了問題域中領域邏輯的優先級,同時促使團隊在宏觀層次的全局分析階段能夠將設計的注意力放在領域和對領域模型的理解上,滿足領域驅動設計的要求。
進入解決方案空間,戰略設計獲得的限界上下文成為了領域驅動設計的第二重邊界。通過它可以有效地降低系統規模,無論是在業務領域,還是架構設計,或者團隊協作方面,限界上下文建立的邊界都成為了重要的約束力,邊界內外可以形成兩個不同的世界。暴露在限界上下文邊界外部的是遠程服務或應用服務,每個服務都提供了完整的業務價值,并通過相對穩定的契約來展現服務,由此確定限界上下文之間的協作方式。在限界上下文邊界之內,可以根據不同的需求場景,形成自己的一套設計與實現體系。外部世界的規則是契約、通信以及系統級別的架構風格與模式,內部世界的規則是分層、協作以及類級別的設計風格與模式。
在限界上下文內部,基礎設施層、應用層與領域層之間的隔離成為了領域驅動設計的第三重邊界。如果以六邊形架構來觀察這種層與層之間的隔離,體現的仍然是一種內外隔離,應用層形成了一種保護層,有效地隔離了業務復雜度與技術復雜度。將領域層作為整個系統穩定而內聚的核心,是領域驅動設計的關鍵特征。唯有如此,才能逐漸將這個“領域內核”演化為企業的重要資產。這也是軟件設計的核心思想,即分離變與不變。領域內核中的領域模型具有一種本質的不變性,只要我們將領域邏輯剖析清楚,該模型就能保證相對的穩定性;若能再正確地識別可能的擴展與變化,加以抽象與封裝,就能維持領域模型絕對的穩定性。內核之外的外部資源具有一種偶然的不變性,一旦外部形勢發生變化,這種偶然的不變性就可能瞬間崩塌,需要重新建造方能煥然一新。
若要維持領域內核的穩定性,高內聚與低耦合是其根本要則。雖然職責分配的不合理在應用層邊界的隔離下可以將影響降到最低,但總是在調整與修改的領域模型無法維護領域概念的完整性和一致性;為此,領域模型引入了聚合這一最小的設計單元,它從完整性與一致性對領域模型進行了有效的隔離,成為了領域驅動設計的第四重邊界。領域驅動設計為聚合規定了嚴謹的設計約束,使得整個領域模型的對象圖不再變得散漫,彼此之間的協作也有了嚴格的邊界控制。這一約束與控制或許加大了我們設計的難度,但它卻可以挽救因為限界上下文邊界劃分錯誤帶來的不利決策。聚合設計原則要求聚合之間通過ID進行關聯,避免了聚合根實體之間的引用依賴,也不會受到限界上下文邊界變化的影響。
這四重邊界如下圖所示:
領域驅動設計在各個層次提出的核心模式具有不同的粒度和設計關注點,但本質都在于確定邊界。畢竟,隨著規模的擴大,一個沒有邊界的系統終究會變得越來越混亂,架構沒有清晰的層次,職責缺乏合理的分配,代碼變得不可閱讀和維護,最終形成一種無序設計。在 Pete Goodliffe 講述的《兩個系統的故事:現代軟件神話》中詳細地羅列了無序設計系統的幾種警告信號:
- 代碼沒有顯而易見的進入系統中的路徑;
- 不存在一致性、不存在風格、也沒有統一的概念能夠將不同的部分組織在一起
- 系統中的控制流讓人覺得不舒服,無法預測
- 系統中有太多的“壞味道”,整個代碼庫散發著腐爛的氣味,是在大熱天里散發著刺激氣體的一個垃圾堆
- 數據很少放在使用它的地方。經常引入額外的巴羅克式緩存層,目的是試圖讓數據停留在更方便的地方。
我們看一個無序設計的軟件系統,就好像隔著一層半透明的玻璃觀察事物一般,系統中的軟件元素都變得模糊不清,充斥著各種技術債。細節層面,代碼污濁不堪,違背了“高內聚松耦合”的設計原則,導致許多代碼要么放錯了位置,要么出現重復的代碼塊;架構層面,缺乏清晰的邊界,各種通信與調用依賴糾纏在一起,同一問題域的解決方案各式各樣,讓人眼花繚亂,仿佛進入了沒有規則的無序社會。領域驅動設計的這四重邊界可以保證系統的有序性。
紀律是關鍵
一套方法體系不管有多么的完美,如果團隊不能嚴格地執行方法體系規定的紀律,都是空談。ThoughtWorks 的楊云就指出“領域驅動設計是一種紀律”,他進一步解釋道:
領域驅動設計本身沒有多難,知道了方法的話,認真建模一次還是好搞的,但是持續地保持這個領域模型的更新和有效,并且堅持在工作中用統一語言來討論問題是很難的。紀律才是關鍵。領域驅動設計強調對邊界的劃分與控制,團隊在實施領域驅動設計時如果沒有理解邊界控制的意義,也不遵守邊界的約束紀律,邊界的控制力就會被削弱甚至丟失。例如,我們強調通過分層架構來隔離業務復雜度與技術復雜度,而團隊成員在編寫代碼時卻圖一時的便捷,直接將基礎設施層的代碼放到領域模型對象中;又或者為了追趕進度,沒有認真進行領域建模就草率編寫代碼,卻無視聚合對概念完整性、數據一致性的保護,則領域驅動設計強調的四重邊界就形同虛設了。
紀律是關鍵,畢竟影響軟件開發質量的關鍵因素是人,而不是設計方法。對于團隊成員而言,學習領域驅動設計是提高技能,是否遵守領域驅動設計的紀律則是一種態度。倘若二者皆有,就需要向團隊成員明確:領域驅動設計到底有哪些必須遵守的紀律。
結合領域驅動設計的完整體系,我總結了如下的“三大紀律八項注意”,可作為領域驅動設計團隊執行“作戰任務”的紀律規范:
- 三大紀律
- 領域專家與開發團隊工作在一起
- 領域模型必須遵循統一語言
- 時刻堅守四重設計邊界
- 八項注意
- 子領域與限界上下文不要混為一談
- 一個限界上下文不能由多個團隊開發
- 跨進程協作通過遠程服務,進程內協作通過應用服務
- 保證領域分析模型、領域設計模型與領域實現模型的一致
- 不要將領域模型暴露在應用層之外
- 不要讓數據模型干擾領域模型的設計
- 聚合之間只能通過聚合根ID引用
- 聚合不能依賴訪問外部資源的網關
三大紀律是實施領域驅動設計的最高準則,是否遵守這三大紀律,決定了實施領域驅動設計的成敗。八項注意則重申了設計要素與規則,并對一些規范進行了固化,避免因為團隊成員能力水平的參差不齊導致實施過程的偏差。當然,取決于不同的項目、不同的團隊,實施領域驅動設計的方式自然也可以有所不同,在不違背三大紀律的最高準則下,團隊也可以總結屬于自己的八項注意。
領域驅動設計能力評估模型
要實施領域驅動設計,必須提高團隊的整體能力。團隊的能力與遵循的紀律是一脈相承的:能力足但紀律渙散,不足以打勝仗;紀律嚴而能力缺乏,又心有余而力不足。培養團隊成員的能力并非一朝一夕之功,如果能夠有一套能力評估模型對團隊成員的能力進行評估,就能做到針對性的培養。借助領域驅動設計魔方與領域驅動設計參考過程模型引入的各種方法與模式,我建立了一套領域驅動設計能力評估模型。
領域驅動設計能力評估模型(Domain-driven design Capability Assesment Model,DCAM)是我個人對領域驅動設計經驗的一個提煉,可以通過它指導團隊進行能力的培養和提升。DCAM 并非一個標準或一套認證體系,更非事先制定和強制執行的評估框架。建立這套模型的目的僅僅是為了更好地實施領域驅動設計,我不希望它成為一種僵化的評分標準,而應該是一個能夠不斷演化的評估框架。目前,DCAM 僅限于對象范式的領域驅動設計。
該能力評估模型針對的能力維度包括:
- 敏捷迭代能力
- 領域建模能力
- 架構設計能力
- 整潔編碼能力
每個維度又分為了初始級、成長級與成熟級三個層次。各個層次的成熟度是圍繞著領域驅動設計能力開展評估的,層次越高,則團隊的成熟度就越高,推行領域驅動設計成功的可能性就越高。
敏捷迭代能力
我認為,領域驅動設計之所以在近十余年未能取得舉足輕重的成功,其中一個原因就是它沒有與敏捷軟件開發過程結合起來。敏捷開發的諸多實踐,包括精益需求管理、特性團隊、持續集成、用戶故事等都可以為領域驅動設計的實施保駕護航。它的評估模型為:
等級團隊需求過程初始級組件團隊,缺乏定期的交流制度沒有清晰的需求管理體系每個版本的開發周期長,無法快速響應需求的變化成長級全功能的特性團隊,每日站立會議定義了產品待辦項和迭代待辦項采用了迭代開發,定期交付小版本成熟級自組織的特性團隊,團隊成員定期輪換,形成知識共享建立了故事地圖、建立了史詩故事、特性與用戶故事的需求體系建立了可視化的看板,由下游拉動需求的開發,消除浪費
領域建模能力
團隊的領域建模能力是推行領域驅動設計的基礎,也是有別于其他軟件開發方法的根本。它的評估模型為:
等級領域建模初始級采用數據建模,建立以數據表關系為基礎的數據模型成長級采用領域建模,建模工作只限于少數資深技術人員,并憑借經驗完成建模成熟級采用事件風暴、四色建模等建模方法,由領域專家與開發團隊一起圍繞核心子領域開展領域建模
架構設計能力
如果說領域建模完成了對現實世界的抽象與提煉,則架構設計就是在解決方案空間中進一步對領域模型的細化,添加合理的設計元素,從而建立邊界清晰,具有可重用性與可擴展性的設計模型。它的評估模型為:
等級架構設計初始級采用傳統三層架構,未遵循整潔架構,整個系統缺乏清晰的邊界采用貧血領域模型,業務邏輯主要以事務腳本實現成長級領域層作為分層架構的獨立一層,并為領域層劃分了模塊采用了富領域模型,遵循面向對象設計思想,但未明確定義聚合和資源庫成熟級建立了系統層次與限界上下文層次的系統架構,遵循了整潔架構,建立了清晰的限界上下文與領域層邊界建立了以聚合為核心的領域設計模型,職責合理地分配給聚合、資源庫與領域服務
整潔編碼能力
領域實現模型才是最終要交付的工件,它的質量直接影響了軟件的開發成本和運維成本。按照領域驅動設計方法開發出來的代碼,應該具有清晰表達的領域含義,并成為重要的企業資產。衡量領域實現模型質量的標準就是看它是否滿足了整潔代碼的要求。它的評估模型為:
等級編碼自動化測試初始級編碼以實現功能為唯一目的沒有任何自動化測試成長級方法和類的命名都遵循了統一語言,可讀性高為核心的領域產品代碼提供了單元測試成熟級采用測試驅動開發編寫領域代碼,遵循簡單設計原則具有明確的測試戰略,單元測試先行
總結
許多人反應領域驅動設計很難。Eric Evans 創造了許多領域驅動設計的專有術語,這為團隊學習領域驅動設計制造了知識障礙。對象范式的領域驅動設計建立在良好的面向對象設計基礎上,如果開發人員對面向對象設計的本質思想理解不深,就會在運用領域驅動設計的模式時,顯得首鼠兩端,不知道該做出怎樣的設計決策才滿足領域驅動設計的要求。這種執著于書本知識的運用方式過于僵化,一旦面臨設計難題又找不到標準答案時,就不知該如何是好了。任何一本領域驅動設計的書籍都不可能窮盡所有的領域場景,并給出具體的設計指導,這就需要團隊在學習過程中把握領域驅動設計的精髓。
明確領域驅動設計的四重邊界,將面向對象設計思想融入到對邊界的界定與規劃中,并要求團隊遵守領域驅動設計的紀律,就能更好地實施領域驅動設計。當然,這一切的基礎還取決于一個成熟的領域驅動設計團隊。利用 DCAM 對團隊進行評估,在發現團隊成員的能力短板后進行針對性的培訓,一旦提升了整個團隊的成熟度,在領域驅動設計的精髓指導下,距離領域驅動設計的成功就不遠了!
總結
以上是生活随笔為你收集整理的领域驱动设计(DDD)的精髓的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Kudu - 一个融合低延迟写入和高性能
- 下一篇: @Bean 的用法