DDD:架構思想的舊瓶新酒

DDD和DSL、DCI的關係是什麼?開發團隊爲何需要DDD?它與微服務與中臺又有着怎樣的聯繫?目前業界實踐DDD最大的問題是什麼?11 月30 日,在由ThoughtWorks 舉辦的領域驅動設計峯會 DDD-China 2019上,InfoQ 記者帶着這些問題對中興通訊資深軟件架構師張曉龍進行了採訪。

DDD、DSL和DCI

DDD概念最早提出於2004年,作爲一種軟件開發的指導思想,DDD對軟件開發帶來了諸多可能與方向,張曉龍認爲DDD爲軟件開發帶來的好處主要有以下幾點:

  • 首先,最大好處就是所有參與者圍繞一個統一一致的領域模型工作,傳統的分析模型和設計模型不再割裂,不管是做設計、做分析還是寫代碼、寫文檔,腦海中所構建的畫面都是一致的。

  • 第二,DDD是一個軟件開發過程,它顯式地把領域和設計放到了軟件開發的核心,軟件人員和業務人員被受到同樣的重視,他們合作來構建領域模型,使得軟件的交付質量更高且維護成本更低;

  • 第三,DDD提出的分層架構,有效分離了業務複雜度和技術複雜度,凸顯了領域模型,使得領域層的代碼和領域模型保持高度一致;

  • 第四,統一語言非常重要,每個概念在各自的上下文中是清晰的無歧義的,同時要控制領域模型的複雜度,於是DDD在戰略上提出了分離子域(問題域空間)和拆分BC(解決方案空間)的模式,BC間通過Context Mapping來集成;

  • 第五,DDD在戰術層面提出了很多模式(聚合,實體,值對象,服務,工廠,倉儲),對領域模型中的元素進行了分類,並給出了每類元素在領域模型中的職責和特徵,降低了領域模型的構建成本。

張曉龍此前曾在DDD-China峯會和ArchSummit全球架構師峯會上分別做過《當DDD遇上DSL(Domain-Specific Language)》、《當DDD遇上DCI(Data,Context, Interactive)》的演講,在他看來,DDD和DSL、DCI之間存在極強的關聯性。

DDD和DSL的融合有三點:

  1. 面向領域;

  2. 模型的組裝方式;

  3. 分層架構演進。

DSL可以看作是在領域模型之上的一層外殼,可以顯著增強領域模型的能力。它的價值主要有兩個,一是提升了開發人員的生產力,二是增進了開發人員與領域專家的溝通。舉個例子:想讓BA負責流程契約的設計,該流程契約是一個活文檔,可以跑測試,而BA不熟悉宿主語言。於是,我們設計了一種外部DSL來專門描述流程契約,對BA非常友好,學習成本也很低(不超過5分鐘就可以學會),最後發現BA很快就廣泛使用了起來。外部DSL並不一定要定義新文法,我們直接複用了plantUML文法,安裝該插件可以自動生成序列圖,非常棒!對於外部DSL,需要自己實現一個解析器將DSL文法解析成語法樹,再根據語法樹生成語義模型。語義模型可以看作領域模型(嚴格的講語義模型是領域模型的子集),外部DSL就是對領域模型的一種組裝方式。

DCI的作用主要體現在兩方面:

首先,DCI助力DDD戰術設計:

  1. 顯式地對ROLE建模,解決了貧血模型與充血模型之爭;

  2. 一個聚合可以支持哪些ROLE,一個ROLE可以由哪些聚合扮演,一個場景下哪些聚合要扮演哪些角色;

  3. 當Aggregate 內部實體行爲比較多時可以嵌套使用 DCI 來拆分和組合;

其次,DCI助力DDD代碼落地:

  1. 對象就是Data,Client爲Context,對象在Client中的行爲就是ROLE。

  2. 根據正交設計原則得到小類(素材庫),根據多重繼承(only C++)或依賴注入來組合素材,不管是行爲類還是數據類,都按Role的方式來組合,對像僅僅組合Role並注入依賴;

  3. 小類大對象:類作爲一種模塊化手段,遵循高內聚,低耦合,讓軟件易於應對變化;對象作爲一種領域對象的的直接映射,解決了過多的類帶來的可理解性問題,讓領域可以指導設計,設計真正反映領域;領域對象需要真正意義上的生命週期管理。

張曉龍認爲,DCI對一些開發人員的影響可能比DDD和DSL還大,因爲開發人員每天都在不斷倒騰代碼,想讓代碼的組合性更強,以便快速應對需求的變化。

開發團隊真的需要DDD

DDD思想貫穿了整個軟件開發的生命週期,包括對需求的分析、建模、架構、設計,和最終的代碼實現,甚至對代碼的測試與重構。代碼是業務的核心資產,不管是否特性團隊,開發團隊肯定是代碼的編寫者和守護者。

對於開發團隊而言,需要關注以下幾點:

  • 首先是統一語言,讓團隊成員可以做到無障礙的溝通,不管是什麼角色都能基於同樣的畫面進行討論;

  • 其次是團隊中各個角色都圍繞領域模型開展工作;

  • 第三是代碼物理設計容易標準化,比如說在分層設計時,基礎設施層怎麼設計,應用層怎麼設計,DTO應該放在哪兒,領域層中各個建模元素如何組織?

更進一步,在分層架構裏,應用層更加關注橫切面的東西,比如說要上報一個告警,要給用戶發送一個Email,這些最好都集中放到應用層裏面。但觸發是在領域層發生的,應用層怎麼知道?通過領域事件來實現依賴反轉,即應用層訂閱領域事件,領域層發佈領域事件。

在中興通訊,核心業務屬於通信行業,DDD的應用場景跟互聯網企業有着很大差別:

  1. 嵌入式軟件;

  2. 兼業務複雜性和技術複雜性;

  3. 軟件規模大,功能複雜,特性交叉;

  4. 高質量,高性能,高可靠等要求。

張曉龍舉例提到,中興通訊在開發團隊中實踐DDD的經驗具體而言有以下幾點:

  1. 領域專家下團隊,和團隊一起交流和協作;

  2. 教練指導,開展戰訓營,定期review;

  3. 架構、設計、編碼和工程實踐:(1)DCI,DSL,正交設計,組合式設計;(2)編碼規範和紀律;(3)嵌入式C/C++最佳實踐;(4)軟件工程能力:開發者測試,小步安全流暢的重構,持續交付流水線,每日Code Review。

DDD 與微服務

DDD概念提出距今已經有15年的歷史,前十年時間都一直處於不溫不火的狀態,而在最近幾年纔開始大行其道。張曉龍表示,中興通訊在2012-2015年期間也有過一些成功的案例,但對於整個業界來說了解的人並不多。他拿DDD-China峯會舉例解釋:這次峯會的參會者有500人的規模,而我們假設峯會在2015年之前舉辦的話,估計參會者不會超過100人。因此,我們可以斷定是微服務的熱風讓人們重新發現了領域驅動設計的價值。

微服務架構從提出以來一直沒有很好的理論支撐如何合理地劃分服務邊界,人們常常爲服務要劃分多大而爭吵不休。而DDD被發現恰好可以彌補微服務的營養不良:(1)服務最大不要大過一個BC,否則服務內可能會存在有歧義的領域概念;(2)服務最小不要小過一個聚合,否則會引入分佈式事務的複雜度;(3)服務間最好通過Domain Event來進行交互,這樣可以讓服務保持鬆耦合。微服務和DDD的結合,讓微服務架構看起來似乎更加穩健了。

“微服務就像是DDD的心上人,使得DDD真正煥發起了青春。”張曉龍這樣解釋。

對於業界目前流行的中臺概念,張曉龍同樣也有自己的看法:

中臺和DDD不是同一個層面的東西,不能爲了把它們聯繫在一起,而強行找相似點。中臺實際上就是多條業務線的共同需求,比如對於滴滴公司來說,快車、專車和出租車等業務都是微服務架構,這些業務的很多服務是相似的,考慮將這些服務從各個前臺下沉到統一的平臺,這個平臺就是中臺。中臺要考慮各個前臺的需求,所以複雜性變高了。

中臺是一種企業級的架構模式,從企業全局整體視角來看架構全貌,而DDD是一種主流的軟件開發方法,用來應對軟件的核心複雜性。中臺架構可以看作是微服務架構的延伸和發展,服務複雜性很高,所以更需要用DDD的方式去設計和建模,但二者之間並不是相同層面的概念。

DDD的困局

最近幾年DDD的火爆也給業界開發團隊帶來了一些迷思,爲什麼我的DDD推行不下去?爲什麼我的DDD做起來總是跟敏捷一樣,最後都變了味?

張曉龍總結了DDD目前面臨的幾大困局:

  • 首先是領域案例面比較窄。目前業界的DDD實踐案例並不多,而且很多案例是偏向互聯網領域的,對於工業領域、嵌入式領域和操作系統領域基本沒有涉及;

  • 第二,DDD書籍非常少,而且大多數書籍是以Java或C#寫的。如果開發團隊用的是C、C++、Python或Go語言,基本沒有可參考的書籍,難度也就更大一些(尤其是C和C++);

  • 第三,各個巨頭公司,比如Google,微軟,BAT等,很少組織、參與或贊助DDD峯會,沒有形成引導作用,業界自然也就少有跟隨效應;

  • 第四,開發團隊要麼找不到領域專家,要麼領域專家無法與開發團隊長時間保持溝通,導致實踐中出現偏差;

  • 第五,DDD落地有一定的門檻,對開發者的技能和素質都有較高的要求。

針對以上幾大困局,張曉龍也給出了自己的解決方案:

  1. 培訓OOA、OOD和OOP的基本知識,並實戰演練,不斷彌補與高手的gap ;

  2. 領域專家和團隊一起工作,確保大家頭腦中的畫面是一致的;

  3. DDD建模要有文檔交付物,並和代碼同步演進,以便對代碼不熟悉的人員也能看到並理解領域驅動設計成果的全貌。

軟件開發沒有銀彈,DDD也不是萬能的。如果開發團隊真的決定用DDD的思想指導軟件開發,就一定要跟隨時代的腳步,吃透DDD這個舊瓶裏裝的新酒。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章