
最近我在幾個技術群和博客評論區(qū)里看到了一波很有意思的“回頭翻案”式言論。有人翻出十二年前的帖子說“DDD本來就是給遺留系統(tǒng)改造用的你們拿來設計新系統(tǒng)是誤用”有人說“DDD根本不是什么建模方法它只是分層架構(gòu)的別名”還有人信誓旦旦地講“真正的DDD必須用六邊形架構(gòu)不然就是假DDD”。這種敘述方式放在別的圈子里叫“歲月史書”放在技術圈子里就是有人開始按自己的需要重新編排領域驅(qū)動設計DDD的“正史”了。作為一個從敏捷開發(fā)火熱年代就開始接觸DDD、也親手在幾個中大型項目里落地過領域模型的從業(yè)者我想認真聊聊這件事。不是說不能批評DDD恰恰相反DDD身上有很多值得反思的問題概念門檻高、落地成本大、團隊認知參差、被工程化包裝后面目全非……這些都該罵。但“該罵”和“捏造歷史”是兩回事。當討論變成羅生門新手很容易被帶偏甚至帶著錯誤的認知去設計系統(tǒng)最后把失敗歸結(jié)為“DDD不行”。這篇文章我不打算站隊只想把幾件我自己踩過坑、查過資料、見過真實案例的事情攤開講清楚幫大家在這波“歲月史書”的聲浪里找到一條能落地的判斷路徑。1. 先盤點一下這波“翻案”里都有哪些典型言論1.1 “DDD已死”和“DDD從未活過”每隔幾年技術社區(qū)就會周期性出現(xiàn)“DDD已死”的論調(diào)。這個調(diào)調(diào)我見得很多了從2015年左右微服務剛火起來時被拿出來說一次到這幾年的“云原生時代DDD過時了”套路幾乎一模一樣先找一個失敗的團隊案例再引用幾段被截斷的原書內(nèi)容最后得出“DDD只能活在PPT里”的結(jié)論。最近的新玩法更進了一步直接“釜底抽薪”“DDD其實從來就不是一個具體的方法論它只是一堆概念的拼湊”。這種說法最難反駁因為它聽起來很有“獨立思考”的氣質(zhì)符合人們對“祛魅”的喜好??蓡栴}是如果《領域驅(qū)動設計》那本書里那套關于模型、通用語言、限界上下文、聚合的理論不是方法論那什么才算方法論難道方法論必須要到“代碼生成器”那個粒度才配叫方法論我倒不反對對DDD做“降格”處理——把它看作一套思維工具而不是銀彈這恰恰是健康的。但“DISS不是問題否定其歷史是另一個問題”。當一個人說“DDD從未活過”時他不是在參與技術討論而是在做話語權(quán)的重置——因為他無法說服你DDD不好那就干脆讓“DDD曾經(jīng)被誤解為很好”這件事本身變成笑話。1.2 “DDD本來就應該xxx”的重新發(fā)明比“已死論”更普遍的是各種“本來論”。典型句式是“DDD本來就應該配合事件溯源使用”“DDD本來就應該用六邊形架構(gòu)落地”“DDD本來就是要做CQRS的”……這種話術的高明之處在于它不否定DDD而是把你的實踐經(jīng)驗全部判為“不入流”。比如你做了幾年DDD用的還是經(jīng)典的四層架構(gòu)共享內(nèi)核突然有人告訴你“沒有用六邊形架構(gòu)的DDD不是真正的DDD”你心里是什么感覺你會先懷疑自己然后懷疑自己的項目最后懷疑那本書。但“本來論”最大的問題是缺乏文本依據(jù)。Eric Evans在《領域驅(qū)動設計》里通篇沒有把DDD和任何一種具體架構(gòu)風格綁定。他講的架構(gòu)是“模型驅(qū)動設計”下各層如何協(xié)作、如何保護領域?qū)硬槐患夹g細節(jié)污染而不是“必須用端口適配器”這種具體處方。后者是后來無數(shù)實踐者從工程教訓中總結(jié)出的偏好把它們說成“DDD的定義”就是把實踐經(jīng)驗偷偷升級成了教義。這種重新發(fā)明還有個副產(chǎn)品術語通脹。什么都可以叫DDD什么都可以說成“DDD的應有之義”。當所有人的DDD都不是同一個東西時圈子里的討論就失去了公共基礎。于是真正想學習DDD的人比算法工程師學新框架還累——因為框架文檔是明確的DDD卻沒有“官方文檔”只有一堆互相打架的二手解讀。1.3 “用DDD失敗的人都是沒用對”還有一類言論我覺得要單獨拎出來說。它誕生于“翻案”的反面走的是“原教旨主義”路線只要有人公開說DDD項目失敗了評論區(qū)必然會出現(xiàn)“你們根本不懂DDD偽DDD當然會失敗”。這套邏輯幾乎是不可證偽的。它把所有失敗都歸咎于“沒有用正宗DDD”但“正宗”的定義永遠掌握在評論者手里。你說你做了事件風暴他說你沒做領域分析你說你做了領域分析他說你的聚合設計是錯的你問哪里錯了他開始講“這個需要長期咨詢陪跑”。這種邏輯本質(zhì)上和“歲月史書”是一枚硬幣的兩面都在用敘事替代事實用定義權(quán)替代證據(jù)。我見過真實的DDD失敗案例也做過復盤失敗的原因通常非常復雜組織架構(gòu)與限界上下文沖突、領域?qū)<胰毕F隊代碼能力不足、業(yè)務本身就在劇烈變化……把這些統(tǒng)統(tǒng)推導到“因為沒學正宗DDD”上既不符合事實也不負責任。2. 六邊形架構(gòu)是怎么被“焊死”在DDD戰(zhàn)車上的2.1 六邊形架構(gòu)的真正生日既然熱詞里帶著六邊形架構(gòu)那這大概就是最近“歲月史書”事件的重點戰(zhàn)場了。先把歷史事實擺出來六邊形架構(gòu)Hexagonal Architecture也叫端口與適配器架構(gòu)是Alistair Cockburn在2005年前后提出的起因是他在實踐中發(fā)現(xiàn)業(yè)務邏輯不該被數(shù)據(jù)庫、UI、消息隊列這些外圍技術綁架。那個年代還沒有“微服務”這個詞DDD藍皮書剛剛出版兩年兩者是完全獨立的思想脈絡。六邊形架構(gòu)早期最知名的實踐者是寫《企業(yè)應用架構(gòu)模式》的Martin Fowler那一派他們當時在討論“業(yè)務邏輯與技術細節(jié)分離”時引用的是《企業(yè)架構(gòu)模式》中的“Application Facade”和“Domain Model”和Evans的DDD并沒有強綁定關系。那問題來了為什么現(xiàn)在一說DDD默認配圖就是那個經(jīng)典的“六邊形內(nèi)部領域模型外部端口”的圖這就要說到DDD落地史上的一個尷尬事實Evans在書里提出的經(jīng)典四層架構(gòu)用戶界面層、應用層、領域?qū)印⒒A設施層在實際工程中非常難拿捏。尤其是“基礎設施層依賴方向倒置”這個點大多數(shù)人做不到一做就做成“Controller調(diào)Service調(diào)Repository”領域?qū)幼兂梢欢沿氀獙ο蟮奈募A。2.2 當“分層”撐不住時六邊形被當成了救生圈我在第一個真正規(guī)模比較大的DDD項目里就踩過四層架構(gòu)的坑。當時我們嚴格按照書里的分層做了包結(jié)構(gòu)controller、service、domain、infrastructure分得清清楚楚代碼評審時大家都很滿意。但等業(yè)務復雜起來問題立刻浮現(xiàn)一個應用服務經(jīng)常需要編排多個倉儲事務邊界落在哪一層消息發(fā)不出去要不要回滾外部API調(diào)用超時領域事件到底算不算已發(fā)布這些問題四層架構(gòu)沒有明確答案團隊開始各自為政。后來我們引入了六邊形架構(gòu)的思路——把入口和出口都抽象成端口把數(shù)據(jù)庫、消息隊列、HTTP客戶端都當作適配器替換。這么一改領域?qū)痈蓛袅瞬簧贉y試也變得好寫了。那段時間我們確實在內(nèi)部達成了共識“DDD項目就該這么搭”。但這里有個重要的認知陷阱我們是“因為DDD遇到了工程問題所以選擇了六邊形架構(gòu)來輔助”而不是“六邊形架構(gòu)是DDD的前提”。可多數(shù)博客在傳播時把第二個表述當成了事實。于是“DDD六邊形”從“經(jīng)驗組合”變成了“標準范式”最后升級為“不用六邊形就不算DDD”。這本質(zhì)上就是一次典型的術語漂移事件。2.3 捆綁敘事為什么這么有市場我后來想明白了這種捆綁敘事有它不可抵擋的傳播優(yōu)勢它給了學習者一個“標準答案”。DDD最讓人痛苦的地方就是“答案全靠自己悟”。限界上下文怎么劃聚合怎么做大做小這些沒有唯一正確的解讓習慣了框架文檔的工程師非常沒有安全感。六邊形架構(gòu)恰好提供了一種“看起來有標準”的結(jié)構(gòu)端口、適配器、內(nèi)部六邊形邊界清晰目錄結(jié)構(gòu)一目了然。當有人說“這就是DDD的標準落地方式”時很多人會本能地選擇相信——因為相信讓自己舒服。然而標準答案的代價是犧牲靈活性。六邊形架構(gòu)本質(zhì)上解決的是“技術細節(jié)與業(yè)務核心的隔離問題”它根本不關心你的領域模型質(zhì)量。一個完全沒有領域模型的CRUD項目照樣可以用六邊形架構(gòu)套得嚴絲合縫。反過來一個領域模型極其精妙、但采用傳統(tǒng)三層架構(gòu)的項目也不會因為沒用六邊形就失去“DDD資格”。把兩者焊死對雙方都是傷害。我個人的結(jié)論是你可以把六邊形架構(gòu)和DDD配合使用這沒有錯現(xiàn)實中也確實很好用但你應該清楚你是在“用DDD建模再用六邊形架構(gòu)做代碼組織”不是在做“標準DDD”。放棄“標準答案”的執(zhí)念反而更容易用好這兩樣東西。3. 翻開藍皮書那些正在被悄悄掉包的“原廠定義”3.1 “通用語言”不是詞匯表是協(xié)作協(xié)議“歲月史書”最精細的操作就是把原書概念掉包成另一個看似相似、實際完全不同的東西?!巴ㄓ谜Z言Ubiquitous Language”就是重災區(qū)。流行解讀里通用語言被簡化成了一張“團隊術語表”業(yè)務管訂單叫“工單”技術管它叫“Order”大家統(tǒng)一一下就叫“Order”吧。表面看這就是通用語言的全部。但Evans寫這個概念的時候強調(diào)的是在一個限界上下文內(nèi)業(yè)務專家與開發(fā)人員使用同一套語言進行討論、建模、設計而且這套語言必須體現(xiàn)在代碼、測試、文檔、日常對話中。被簡化成詞匯表之后通用語言的核心動作——深入的、能暴露模型分歧的對話——被完全丟掉了。團隊可能擁有一份術語表但做需求分析時依舊各說各話建出來的模型跟業(yè)務真實心智模型嚴重背離。這是一種特別隱蔽的“歲月史書”它沒有篡改文字卻篡改了概念的生命力。3.2 “模型”不是只畫UML是要進入代碼的第二個被掉包的概念是“模型”。好多翻案文章喜歡嘲諷DDD——“畫一堆UML圖就能解決復雜業(yè)務嗎”這個靶子很好打因為確實有很多偽DDD項目熱衷于畫圖。但原書的立場恰恰相反。Evans反復強調(diào)模型必須“和實現(xiàn)綁定”要讓它成為“軟件的脊柱”。一個只存在于PPT里的抽象模型在他看來不是DDD的成果而是失敗。他在前言里就寫得很明白這本書講的是“如何在軟件中建立模型”而不是“如何畫好一張模型圖”??上У氖翘鄬嵺`者以及批評者把“建立模型”理解成了“繪制模型”。這也解釋了為什么有些“翻案”看起來很犀利——他們批判的對象本身就不是DDD而是偽DDD。但他們偏要沿著“偽DDD就是DDD”這條線去完成對DDD的宣判這就把批判做成了新的歷史敘事。3.3 貧血模型與充血模型被夸大的對立討論DDD永遠繞不開“貧血模型vs充血模型”而這場討論里也充斥著我見過最多的掉包。流行觀點是DDD推崇充血模型使用貧血模型就是沒有領會DDD精神甚至“貧血模型是一種反模式”。這個觀點源自有據(jù)。Martin Fowler寫過一篇著名的《AnemicDomainModel》批評了那種“對象只有getter/setter業(yè)務邏輯全散落在Service里”的貧血模型。這篇博客對DDD圈影響極大。但這里有個細節(jié)被歲月史書淹沒了Evans在他的書里并沒有明確批判貧血模型他講的是“模型承載業(yè)務規(guī)則”這個原則。如果一個貧血模型配合服務層仍然能讓業(yè)務規(guī)則的語義清晰可見、由領域?qū)咏y(tǒng)一表達那它并不必然違背DDD。現(xiàn)實情況是很多項目因為團隊的代碼能力、業(yè)務規(guī)模、歷史包袱用“貧血對象事務腳本”的方式反而更清晰。你可以說這不是DDD的最理想形態(tài)但把它直接打成“異端”等于把原書沒有的教義塞進了歷史。3.4 戰(zhàn)略設計為何總是缺席最后想認真提一句所有翻案聲音里很少聽到有人認真討論戰(zhàn)略設計?!跋藿缟舷挛摹薄吧舷挛挠成洹薄胺栏瘜印薄肮蚕韮?nèi)核”“開放主機服務”這些屬于Evans原書后半部分的內(nèi)容才是DDD相對其他建模方法最有價值的部分——它試圖解決“多模型共存”“系統(tǒng)邊界”的問題。但戰(zhàn)術設計聚合、值對象、領域事件、倉儲因為更貼近編碼成了培訓機構(gòu)的賣點、博客的流量入口。狼來了喊多了“DDD建聚合畫領域事件圖”的矮化版本反而成了主流。這變成了一種雙重的歲月史書一邊是戰(zhàn)術設計被拔高成全部一邊是戰(zhàn)略設計的缺席被默認為正常。等到有人說“DDD解決不了系統(tǒng)邊界問題”時你甚至不知道他說的“DDD”到底是指原書里的DDD還是那個被矮化過的DDD。4. 假DDD泛濫才是歲月史書真正的土壤4.1 “建文件夾”式DDD最流行的實踐幻覺這幾年的項目里我見過特別多的“DDD項目”說它們是“建文件夾”式DDD一點都不冤枉。它們的特征是包結(jié)構(gòu)嚴謹?shù)匕凑誥pplication/domain/infrastructure三層劃分領域?qū)永锾芍欢褜嶓w和一些表面上的值對象然后就沒有然后了。聚合內(nèi)沒有業(yè)務不變量領域事件量是零規(guī)則散落在應用服務里所謂“領域服務”只是替Controller分擔了十行代碼。遇到這種項目團隊復盤時會覺得驚訝“我們嚴格按照DDD做的為什么代碼還是爛”項目最終失敗團隊把責任推給DDD。但這里面有個特別反直覺的真相DDD的許多概念確實是“聽著簡單、做著極難”的。我自己的團隊第一次做聚合劃分時信心滿滿地劃分了十幾個聚合結(jié)果兩個月后就發(fā)現(xiàn)了模型漂移——同一個業(yè)務規(guī)則在兩個聚合中各實現(xiàn)了一版。如果你沒有經(jīng)歷這種“被模型教訓”的過程你很難說自己在實踐DDD。4.2 失敗復盤里的歸因錯誤當大量“建文件夾式DDD項目”失敗后翻案文章就有了現(xiàn)成的素材。它們會把這些失敗的復盤當作“DDD項目的失敗”進而推導“DDD不適用于xxx場景”。但稍微仔細看一眼就能發(fā)現(xiàn)那些項目里根本沒有像樣的領域建模過程——沒有事件風暴級別的業(yè)務探索沒有核心域和支撐域的區(qū)分沒有限界上下文的獨立演進。這種歸因錯位很有意思一個人開車路線圖拿反了車子半路拋錨他不怪自己沒檢查油量、不怪自己看錯地圖而是得出結(jié)論“這條路根本不通網(wǎng)上那些說這條路能到的人都是在騙人”。然后他開始寫帖子把這條路的真實地理坐標全部“修正”一遍。這就是歲月史書的生成機制不是歷史本身被歪曲而是提取歷史樣本的過程充滿了偏差。4.3 偽DDD為什么會成為主流敘事我不愿意把所有鍋都扣在培訓機構(gòu)和自媒體頭上因為需求是雙向的。學習者在面對復雜業(yè)務時確實需要一套能快速上手的“骨架”而“DDD就是用六邊形架構(gòu)建四個文件夾”這個骨架是市面上最容易理解的簡化版。它犧牲了DDD最有價值的“模型驅(qū)動”內(nèi)核保留了最容易展示的外殼。但這種簡化一旦形成生態(tài)就會被大家默認為“DDD的事實標準”。等有一天原教旨主義者站出來說“你們這些根本不是DDD”雙方就會開始互拋歷史。一邊說“DDD本來就是這樣教的”一邊說“DDD從來不是這樣定義的”。吵到最后沒有人去翻開那本書沒有人去看真實項目的演進只?!罢l的話術更像權(quán)威”。這也是為什么我覺得“歲月史書”這個現(xiàn)象本質(zhì)上并不是惡意造謠而是技術傳播中“簡化-固化-神圣化”的必經(jīng)之路。警惕它是因為它會污染你獨立判斷的參照系。5. 面對歲月史書一個實踐者的自處方式5.1 觀點是廉價的文本是硬錨點碰到任何關于“DDD本來應該怎樣”的說法我的第一反應就是你說的“本來”出處在哪Eric Evans的《領域設計》是第一手文本Vaughn Vernon的《實現(xiàn)領域驅(qū)動設計》是優(yōu)質(zhì)的擴展讀物Alberto Brandolini的事件風暴方法論和Greg Young的CQRS/ES都是后來被實踐證明有效的補充但它們有各自的文獻出處和語境。當你發(fā)現(xiàn)一個人把上述所有來源都混在一起說成“DDD本來如此”時你就該知道這是一鍋被人為攪勻的史書而不是一本有章節(jié)頁碼的科學著作。這里分享一個特別實用的技巧給自己建一張“概念出處表”。同樣是“聚合”Evans怎么說、Vernon怎么擴展、你在項目中怎么落地各占一列。當你讀到一篇新博客時把它的觀點放到表格里對照很快就能看出作者是在轉(zhuǎn)述原書、還是在補充個人經(jīng)驗、還是在創(chuàng)造“傳統(tǒng)”。這個方法不復雜但能過濾掉絕大多數(shù)只有情緒沒有依據(jù)的翻案文。5.2 識別“歲月史書”話術的三個紅旗紅旗一絕對化定義。只要出現(xiàn)“真正的DDD必須……”“DDD本質(zhì)上就是……”這類句式先警惕。定義權(quán)是歷史敘事權(quán)的濃縮一個健康的術語討論應該是“在xxx語境下我認為比較好的一種落地方式是……”。紅旗二動機可疑的歸因?!爸灰昧薉DD就是失敗”“只有用了DDD才配叫復雜業(yè)務架構(gòu)”兩種極端都值得懷疑。技術決策是多因素博弈的結(jié)果任何單一歸因都可能是為了敘事服務的。紅旗三憑空消失的失敗細節(jié)。翻案文章往往把失敗項目的關鍵細節(jié)處理得很模糊團隊規(guī)模、領域復雜度、業(yè)務語言統(tǒng)一程度、技術團隊能力基線這些信息要么缺失要么被嚴重簡化。這些細節(jié)才是復盤的靈魂刪掉它們故事就開始變成史書。5.3 把DDD和它的合作伙伴解耦反而更好用我想把“DDD、六邊形架構(gòu)、CQRS/ES、微服務”這幾個常常被焊死的概念拆開來它們之間是“可以協(xié)作”的關系不是“必須配套”的關系概念解決的問題與DDD的關系DDD業(yè)務復雜性建模與模型落地核心方法論六邊形架構(gòu)技術邊界隔離與技術細節(jié)解耦可選實現(xiàn)風格CQRS/ES高并發(fā)讀寫分離與溯源審計可選的讀寫模型策略微服務部署獨立性與組織自治戰(zhàn)略設計的一種落地載體我自己在項目中就做過非六邊形的DDD落地方案也見過CQRS跟DDD毫無關系的純數(shù)據(jù)平臺項目。解耦后每個概念各自承擔職責反而更容易判斷業(yè)務建模累了問題出在DDD的戰(zhàn)術設計邊界層依賴混亂了去調(diào)整六邊形架構(gòu)的端口性能扛不住了再考慮CQRS。如果所有問題都記在“DDD”帳上你既解決不了問題也對不起DDD。5.4 我的建議去寫自己的“戰(zhàn)場記錄”而不是參與“歷史定稿”防“歲月史書”最好的方式不是你成為一個更會吵架的評論者而是成為一個勇于公開細節(jié)的實踐者。我在團隊內(nèi)部推行過一個很小的做法每個迭代結(jié)束時在技術周報里花兩三百字記錄“模型在這個迭代發(fā)生了什么變化”——聚合是否拆分、限界上下文之間是否新增了合作方式、哪些通用語言的詞匯在實踐中被替換了。這些記錄彌足珍貴因為它們記載的是“模型與真實業(yè)務的反復對沖”而不是某篇文章里那個光滑圓潤的“最佳實踐”。當團隊后來面臨架構(gòu)質(zhì)疑時我們不需要引用任何權(quán)威文章只需要把這些記錄攤開就能說清楚“這個設計決定是怎么來的當時面對什么約束后來效果如何”。這就是你自己的“正史”。說到底DDD最大的敵人從來不是所謂的“新范式”而是那些為了獲得確定性而強行收編歷史的聲音。一個領域、一種方法論只有允許不同經(jīng)驗共存、允許失敗細節(jié)被討論、允許文本解釋被挑戰(zhàn)它才可能真正活下來。我不指望能幫誰畫出一條絕對正確的DDD路線但如果這篇東西能讓你在下一次聽到“DDD本來應該……”的時候多問一句“這句話的出處在哪里、這位作者的上下文是什么”那它就沒白寫。方法論一旦被神圣化就會開始腐朽。保持一點考古學家的懷疑精神對DDD、對六邊形架構(gòu)、對所有被包裝成“正統(tǒng)”的東西都保持一點距離反而能走得更遠。