DDD實(shí)戰(zhàn)心法全公開(kāi) —— 用「事件風(fēng)暴」炸開(kāi)業(yè)務(wù)復(fù)雜度
一、前言
“我們開(kāi)了3天需求會(huì),還是說(shuō)不清訂單履約流程?!?/p>
“需求連續(xù)評(píng)了兩三周,一周就要搞定技術(shù)設(shè)計(jì)”
“我這剛設(shè)計(jì)好,需求內(nèi)容就有變更,流程圖改起來(lái)太費(fèi)事了”
如果你經(jīng)歷過(guò)“業(yè)務(wù)方和技術(shù)團(tuán)隊(duì)互相覺(jué)得對(duì)方是外星人”的溝通困境,如果你厭倦了“先設(shè)計(jì)再開(kāi)發(fā)最后發(fā)現(xiàn)全錯(cuò)了”的循環(huán),那么事件風(fēng)暴(Event Storming)可能是你需要的解藥。
為什么DDD火了20年,卻依然“知易行難”?
2003年,Eric Evans 提出領(lǐng)域驅(qū)動(dòng)設(shè)計(jì)(DDD) 時(shí),稱(chēng)它為 “面向?qū)ο箝_(kāi)發(fā)的正確打開(kāi)方式”。但直到今天,許多團(tuán)隊(duì)依然覺(jué)得DDD “聽(tīng)起來(lái)很美,用起來(lái)很虛”。歸根結(jié)底,還是因?yàn)閳F(tuán)隊(duì)對(duì)DDD的理解不足——不是DDD沒(méi)用,而是傳統(tǒng)的建模方式太難落地DDD這么龐大的體系。
- 文檔黑洞:需求文檔→技術(shù)設(shè)計(jì)→代碼實(shí)現(xiàn),信息層層失真。
- 術(shù)語(yǔ)戰(zhàn)爭(zhēng):業(yè)務(wù)說(shuō)“用戶”,開(kāi)發(fā)說(shuō)“User”,DBA說(shuō)“usr_tbl”——同一個(gè)東西,三種語(yǔ)言。
- 架構(gòu)斷層:畫(huà)了一堆UML圖,最后代碼還是“面條式”Service層。
事件風(fēng)暴:DDD的“暴力破解”法
事件風(fēng)暴不是另一個(gè)理論課,而是一種“用便利貼和咆哮體”快速對(duì)齊業(yè)務(wù)與技術(shù)的實(shí)戰(zhàn)工作坊。它的核心只有兩步:
- 把業(yè)務(wù)邏輯拆解成“事件”(比如“訂單已支付”“庫(kù)存已扣減”)。
- 用彩色貼紙和白板,讓業(yè)務(wù)方和技術(shù)一起“打架”,直到所有人點(diǎn)頭:“對(duì),系統(tǒng)就該這么干!”
為什么它現(xiàn)在才火?
以前不需要:10年前的系統(tǒng)復(fù)雜度,用CRUD就能應(yīng)付。 現(xiàn)在離不開(kāi):微服務(wù)、中臺(tái)化之后,業(yè)務(wù)邏輯散落在幾十個(gè)服務(wù)里,沒(méi)有清晰的領(lǐng)域模型?等著天天救火吧。
本文能帶給你什么?
我們將用一個(gè)從0到1的社交平臺(tái)項(xiàng)目為例,展示:
- 如何用3天事件風(fēng)暴,理清10W字+的復(fù)雜邏輯需求(比如:雙向關(guān)注、多權(quán)限身份限制)。
- 代碼如何直接反映業(yè)務(wù)模型——不再有“設(shè)計(jì)是設(shè)計(jì),代碼是代碼”的分裂感。
二、什么是事件風(fēng)暴?——用“便利貼工作坊”暴力破解業(yè)務(wù)復(fù)雜性
如果你曾經(jīng)經(jīng)歷過(guò)以下場(chǎng)景:
- 業(yè)務(wù)方說(shuō):“用戶觸發(fā)關(guān)注操作后,系統(tǒng)要檢查被關(guān)注用戶是否存在以及是否關(guān)注過(guò)?!?/li>
- 開(kāi)發(fā)理解成:“在AttentionService里加個(gè)check()?!?/li>
- 上線后才發(fā)現(xiàn):業(yè)務(wù)實(shí)際想要的是“取消關(guān)注后再關(guān)注,需要有特殊數(shù)據(jù)處理”——但代碼里根本沒(méi)這邏輯。
事件風(fēng)暴(Event Storming) 就是為了終結(jié)這種“跨服聊天”而生的高強(qiáng)度協(xié)作建模工作坊。它用最原始的工具(便利貼、白板、馬克筆)和最直白的規(guī)則,讓業(yè)務(wù)專(zhuān)家、開(kāi)發(fā)、測(cè)試、架構(gòu)師在同一個(gè)物理(或虛擬)空間里,用同一種語(yǔ)言對(duì)話。
1.事件風(fēng)暴的核心:用“事件”驅(qū)動(dòng)建模
(1)什么是“事件”?
在DDD中,事件(Event)是“業(yè)務(wù)過(guò)程中已發(fā)生的事實(shí)”,通常用過(guò)去時(shí)態(tài)描述:
- ? 訂單已創(chuàng)建(OrderCreated)
- ? 支付已超時(shí)(PaymentTimeout)
- ? 創(chuàng)建訂單(這是“命令”,不是事件)
為什么從事件開(kāi)始?
- 業(yè)務(wù)方天然理解:他們每天都在說(shuō)“用戶付了錢(qián)”“客服處理了投訴”——這些都是事件。
- 技術(shù)方無(wú)法曲解:事件是事實(shí),不像“需求文檔”可能被二次加工。
(2)事件的分類(lèi)與顏色編碼
事件風(fēng)暴用不同顏色的便利貼區(qū)分建模元素(線下常用,線上工具如Miro、知行蜂、語(yǔ)雀、甚至process On也支持):
元素 | 顏色 | 示例 | 作用 |
領(lǐng)域事件 | 橙色 | 用戶已關(guān)注 | 業(yè)務(wù)過(guò)程的核心事實(shí) |
命令 | 藍(lán)色 | 用戶關(guān)注 | 觸發(fā)事件的動(dòng)作(誰(shuí)/什么導(dǎo)致事件發(fā)生) |
聚合 | 黃色 | 關(guān)注 | 一致性邊界(修改數(shù)據(jù)的入口) |
角色 | 粉色 | 會(huì)員、黃金會(huì)員 | 誰(shuí)發(fā)起了命令? |
策略 | 紫色 | 關(guān)注后計(jì)算關(guān)系 | 業(yè)務(wù)規(guī)則(if-else邏輯) |
注:顏色心理學(xué):暖色(橙/黃)代表“已發(fā)生”,冷色(藍(lán)/紫)代表“待決策”——視覺(jué)上就能區(qū)分“事實(shí)”和“動(dòng)作”。
2. 事件風(fēng)暴的流程:從混亂到清晰的三步走
階段1:自由風(fēng)暴——把所有人的腦子倒出來(lái)
規(guī)則:
- 業(yè)務(wù)方大喊:“用戶點(diǎn)了退款按鈕后支付被撤銷(xiāo)了!” → 立刻貼橙色事件支付已撤銷(xiāo)。
- 開(kāi)發(fā)追問(wèn):“誰(shuí)撤銷(xiāo)的?怎么撤銷(xiāo)的?” → 補(bǔ)藍(lán)色命令提交退款申請(qǐng)和粉色角色客戶。
關(guān)鍵技巧:
- 不批評(píng)、不爭(zhēng)論:先貼滿墻再說(shuō),后期再整理。
- 用時(shí)間線排序:把事件按發(fā)生順序從左到右排列,避免“雞生蛋還是蛋生雞”的爭(zhēng)論。
階段2:爭(zhēng)奪聚合——?jiǎng)澏ùa的勢(shì)力范圍
爭(zhēng)議焦點(diǎn): “庫(kù)存扣減應(yīng)該屬于訂單聚合還是庫(kù)存聚合?” “支付失敗通知是支付聚合的責(zé)任,還是獨(dú)立的通知服務(wù)?” 解決方案:
- 用黃色聚合貼紙圈出邊界,比如:
[訂單聚合]
- 事件:`訂單已創(chuàng)建`
- 命令:`取消訂單`
- 策略:`超時(shí)自動(dòng)取消`- 驗(yàn)證一致性:確保一個(gè)聚合內(nèi)的所有修改通過(guò)單一入口(如Order.cancel())。
階段3:代碼映射——從貼紙到類(lèi)名
直接生成代碼骨架:
// 橙色事件 → 類(lèi)
public class OrderCancelled implements DomainEvent {
private OrderId orderId;
private CancelReason reason;
}
// 藍(lán)色命令 → 方法
public class Order {
public void cancel(CancelReason reason) {
// 校驗(yàn)邏輯...
apply(new OrderCancelled(orderId, reason));
}
}避免“文檔斷層”:代碼中的類(lèi)名和方法名必須和貼紙上的術(shù)語(yǔ)完全一致。
3. 為什么事件風(fēng)暴比傳統(tǒng)方法更有效?——從“文檔網(wǎng)球”到“協(xié)作核爆”
“傳統(tǒng)需求分析像打網(wǎng)球——業(yè)務(wù)方發(fā)球,BA截?fù)?,開(kāi)發(fā)扣殺,最后誰(shuí)也沒(méi)接到?!?/p>
事件風(fēng)暴則像核聚變——所有角色在高壓環(huán)境下碰撞,直接釋放出業(yè)務(wù)本質(zhì)的能量。
以下從 效率、質(zhì)量、協(xié)作 三個(gè)維度,對(duì)比事件風(fēng)暴與傳統(tǒng)方法(如用例分析、用戶故事地圖)的本質(zhì)差異:
維度1:效率——從“月級(jí)循環(huán)”到“小時(shí)級(jí)產(chǎn)出”
對(duì)比項(xiàng) | 傳統(tǒng)需求分析 | 事件風(fēng)暴 |
耗時(shí) | 2周文檔評(píng)審 + 1周UML畫(huà)圖 | 3小時(shí)工作坊(含核心模型產(chǎn)出) |
反饋周期 | 需重新召集會(huì)議修正 | 現(xiàn)場(chǎng)移動(dòng)貼紙即時(shí)調(diào)整 |
工具成本 | 專(zhuān)業(yè)工具(Visio/Enterprise Arch) | 便利貼+白板(或Miro) |
關(guān)鍵差異:
- 傳統(tǒng)方法依賴(lài)“文檔轉(zhuǎn)譯”(業(yè)務(wù)→BA→開(kāi)發(fā)),信息衰減嚴(yán)重。
- 事件風(fēng)暴是“同聲傳譯”(所有人用同一套貼紙語(yǔ)言)。
維度2:質(zhì)量——從“表面功能”到“深度規(guī)則”
對(duì)比項(xiàng) | 傳統(tǒng)方法痛點(diǎn) | 事件風(fēng)暴優(yōu)勢(shì) |
業(yè)務(wù)規(guī)則挖掘 | 止步于功能列表(CRUD) | 強(qiáng)制暴露“如果...怎么辦”場(chǎng)景 |
技術(shù)風(fēng)險(xiǎn) | 設(shè)計(jì)文檔不體現(xiàn)并發(fā) | 通過(guò)“時(shí)間線”自然暴露競(jìng)態(tài)條件 |
一致性 | 文檔與代碼逐漸偏離 | 貼紙術(shù)語(yǔ)直接成為類(lèi)名/方法名 |
- 傳統(tǒng)方法是“樹(shù)狀展開(kāi)”(從主干到枝葉,容易遺漏旁支)。
- 事件風(fēng)暴是“網(wǎng)狀探索”(事件之間強(qiáng)制關(guān)聯(lián),暴露隱藏鏈路)。
維度3:協(xié)作——從“甩鍋大會(huì)”到“共同創(chuàng)作”
對(duì)比項(xiàng) | 傳統(tǒng)會(huì)議現(xiàn)象 | 事件風(fēng)暴破局點(diǎn) |
參與度 | 業(yè)務(wù)方玩手機(jī),開(kāi)發(fā)沉默 | 所有人必須動(dòng)手貼紙/反駁 |
責(zé)任歸屬 | “這是BA寫(xiě)的,我不知道” | 每張貼紙需全員認(rèn)可 |
知識(shí)傳遞 | 文檔歸檔后無(wú)人閱讀 | 模型直接映射代碼,持續(xù)可追溯 |
- 具身認(rèn)知效應(yīng):當(dāng)人物理移動(dòng)貼紙時(shí),大腦參與度比被動(dòng)聽(tīng)講高300%(哈佛實(shí)驗(yàn)數(shù)據(jù))。
- 沉默成本:貼滿墻的成果會(huì)讓團(tuán)隊(duì)本能抗拒推翻(相比隨時(shí)可刪的電子文檔)。
4.為什么傳統(tǒng)方法難以替代事件風(fēng)暴?
1)用戶故事地圖的局限
- 關(guān)注“用戶做什么”(功能導(dǎo)向),但忽略“業(yè)務(wù)發(fā)生了什么”(事件導(dǎo)向)。
- 例如:用戶故事會(huì)寫(xiě)“作為用戶,我要取消訂單”,但不會(huì)揭示“取消后需觸發(fā)支付退款+庫(kù)存釋放”的領(lǐng)域事件鏈。
2)用例分析的缺陷
- 過(guò)度設(shè)計(jì):花費(fèi)80%時(shí)間畫(huà)“擴(kuò)展流程”,但核心問(wèn)題可能在基礎(chǔ)場(chǎng)景。
- 靜態(tài)視圖:難以表達(dá)“事件的時(shí)間序依賴(lài)”(如“支付完成”必須晚于“訂單創(chuàng)建”)。
3)架構(gòu)決策記錄的滯后性
- ADR(架構(gòu)決策記錄)通常在技術(shù)方案定型后編寫(xiě),而事件風(fēng)暴在需求階段就通過(guò)“策略貼紙”捕獲業(yè)務(wù)規(guī)則。
5.終極優(yōu)勢(shì):事件風(fēng)暴是“活文檔”
傳統(tǒng)方法的產(chǎn)出物(PRD、原型圖)隨著項(xiàng)目推進(jìn)逐漸失效,而事件風(fēng)暴的模型:
- 直接生成代碼(如OrderCancelled事件類(lèi))。
- 驅(qū)動(dòng)測(cè)試用例(每個(gè)事件對(duì)應(yīng)一個(gè)測(cè)試場(chǎng)景)。
- 成為運(yùn)維手冊(cè)(排查生產(chǎn)問(wèn)題時(shí),對(duì)照事件流定位故障點(diǎn))。
“需求會(huì)結(jié)束那一刻,就是文檔過(guò)期的開(kāi)始——而事件風(fēng)暴的墻,會(huì)一直活在代碼里?!?/p>
三、高級(jí)技巧:如何讓事件風(fēng)暴更高效?——從“有序混亂”到“精準(zhǔn)爆破”
“事件風(fēng)暴不是貼貼紙的藝術(shù),而是用結(jié)構(gòu)化方法制造‘可控沖突’?!?/p>
許多團(tuán)隊(duì)嘗試事件風(fēng)暴后,常遇到這些問(wèn)題:
- “貼了一墻便利貼,但最后模型還是錯(cuò)的”
- “業(yè)務(wù)方和開(kāi)發(fā)又吵起來(lái)了,沒(méi)達(dá)成共識(shí)”
- “工作坊很嗨,但代碼還是老樣子” 以下是經(jīng)過(guò) 50+場(chǎng)事件風(fēng)暴實(shí)戰(zhàn) 提煉的 高階技巧,幫你把工作坊效率提升300%:
技巧1:用“時(shí)間旅行”強(qiáng)制暴露邊界條件
問(wèn)題:團(tuán)隊(duì)容易聚焦“ happy path”,忽略異常流。
回到過(guò)去:
- 問(wèn):“如果訂單已發(fā)貨事件發(fā)生在支付失敗之前,系統(tǒng)會(huì)怎么處理?” → 暴露狀態(tài)機(jī)漏洞。
- 結(jié)果:團(tuán)隊(duì)發(fā)現(xiàn)需增加Payment.cancel()補(bǔ)償事務(wù)。
跳到未來(lái):
- 問(wèn):“如果3個(gè)月后我們要支持‘部分退款’,當(dāng)前模型需要改嗎?” → 提前預(yù)留擴(kuò)展點(diǎn)。
案例:某電商團(tuán)隊(duì)設(shè)計(jì)退貨流程時(shí),通過(guò)“時(shí)間旅行”發(fā)現(xiàn):
- 原模型:退貨申請(qǐng) → 退款完成
- 漏洞:未考慮“退貨物流途中包裹丟失”場(chǎng)景 → 補(bǔ)充退貨超時(shí)自動(dòng)關(guān)閉策略。
技巧2:引入“反派角色”進(jìn)行壓力測(cè)試
問(wèn)題:業(yè)務(wù)方常假設(shè)“用戶會(huì)按規(guī)矩操作”。
解法:指定1人扮演黑客/杠精/惡意用戶,挑戰(zhàn)模型:
攻擊點(diǎn)1:并發(fā)漏洞
- “如果用戶在支付完成前瘋狂點(diǎn)擊‘取消訂單’,會(huì)怎樣?” → 暴露無(wú)鎖設(shè)計(jì)風(fēng)險(xiǎn)。
攻擊點(diǎn)2:規(guī)則繞過(guò)
- “我能不能通過(guò)直接調(diào)用Inventory.release()接口,不付款就釋放庫(kù)存?” → 識(shí)別聚合封裝不嚴(yán)問(wèn)題。
技巧3:用“事件溯源”思維倒推模型
問(wèn)題:團(tuán)隊(duì)容易陷入“如何實(shí)現(xiàn)”的技術(shù)細(xì)節(jié),偏離業(yè)務(wù)本質(zhì)。
從事件反推命令:
- 事件:賬戶已凍結(jié) → 追問(wèn):“誰(shuí)凍結(jié)的?為什么凍結(jié)?” → 找到命令風(fēng)控系統(tǒng)觸發(fā)凍結(jié)。
從命令反推聚合:
- 命令:凍結(jié)賬戶 → 追問(wèn):“哪個(gè)對(duì)象有權(quán)限執(zhí)行?” → 鎖定聚合RiskControlAggregate。

優(yōu)勢(shì):避免設(shè)計(jì)出“貧血模型”(如把freezeAccount()放在UserService里)。
技巧4:強(qiáng)制“聚合隔離”——用白板膠帶劃清界限
問(wèn)題:微服務(wù)設(shè)計(jì)中,團(tuán)隊(duì)常模糊限界上下文邊界。
物理隔離:用不同顏色白板/膠帶劃分區(qū)域,例如:
- 綠色區(qū):訂單上下文(含Order、Payment聚合)
- 黃色區(qū):庫(kù)存上下文(含Inventory、Warehouse聚合)
連接線規(guī)則:
- 跨上下文的交互只能用事件(如OrderPlaced事件觸發(fā)庫(kù)存扣減)。
- 禁止直接寫(xiě)“Order調(diào)用InventoryService”這類(lèi)耦合設(shè)計(jì)。
四、為什么你應(yīng)該嘗試事件風(fēng)暴?——從“混沌”到“清晰”的暴力破解
1. 它解決的是“人”的問(wèn)題,而不僅是“技術(shù)”問(wèn)題
- 業(yè)務(wù)方不再抱怨:“你們根本不懂我的需求!”
- 開(kāi)發(fā)不再怒吼:“文檔里根本沒(méi)寫(xiě)這個(gè)邏輯!”
- 測(cè)試不再崩潰:“為什么這個(gè)場(chǎng)景沒(méi)人提過(guò)?!”
因?yàn)椋?/p>
- ? 所有人用同一套語(yǔ)言(貼紙上的術(shù)語(yǔ)=代碼里的類(lèi)名)
- ? 所有決策當(dāng)場(chǎng)確認(rèn)(業(yè)務(wù)方簽字認(rèn)可的模型,就是代碼的藍(lán)圖)
- ? 所有隱藏規(guī)則暴露(通過(guò)“時(shí)間旅行”和“反派測(cè)試”逼出盲點(diǎn))
2. 它讓“領(lǐng)域模型”從理論落地為代碼
傳統(tǒng)DDD的困境:
- 學(xué)了“聚合根”“限界上下文”,但代碼還是UserService.save()
- 設(shè)計(jì)時(shí)畫(huà)了一堆UML,開(kāi)發(fā)時(shí)全忘了
事件風(fēng)暴的破局:
- 模型即代碼:橙色事件OrderCancelled → 直接生成OrderCancelled類(lèi)
- 邊界即微服務(wù):黃色聚合Order → 對(duì)應(yīng)order-service的領(lǐng)域?qū)?/li>
- 規(guī)則即測(cè)試:紫色策略“超時(shí)自動(dòng)取消” → 轉(zhuǎn)化為OrderShouldAutoCancelWhenTimeout測(cè)試用例
3. 它適用于“從0到1”和“舊城改造”
場(chǎng)景 | 傳統(tǒng)方法痛點(diǎn) | 事件風(fēng)暴解法 |
新項(xiàng)目 | 需求模糊導(dǎo)致反復(fù)重構(gòu) | 3小時(shí)鎖定核心模型,減少50%返工 |
老系統(tǒng) | 不敢改,代碼像“屎山” | 從日志/DB反推事件,逐步抽離聚合 |
4. 它的成本低到離譜,但回報(bào)極高
成本:一包便利貼(¥10)+ 半天時(shí)間
回報(bào):
- 節(jié)省30%需求評(píng)審時(shí)間(不用再開(kāi)5輪會(huì)議)
- 減少50%生產(chǎn)事故(提前暴露并發(fā)/狀態(tài)漏洞)
- 提升團(tuán)隊(duì)幸福感(再也不用玩“需求傳話游戲”)
“與其花2周寫(xiě)沒(méi)人看的文檔,不如用3小時(shí)貼一墻能變成代碼的便利貼?!?/p>
5.立即行動(dòng)的建議
從小處開(kāi)始:
- 下次需求評(píng)審會(huì),改用事件風(fēng)暴梳理最復(fù)雜的1個(gè)流程(如“退款審核”)。
工具準(zhǔn)備:
- 線下:買(mǎi)橙色/藍(lán)色/黃色便利貼(必須顏色區(qū)分!)
- 線上:用Miro/Excalidraw(模板可私信獲?。?/li>
度量效果:
對(duì)比事件風(fēng)暴前后:
- 需求變更率下降多少?
- 領(lǐng)域代碼占比提升多少?
記住:第一次可能混亂,但第三次就會(huì)上癮——因?yàn)槟銜?huì)發(fā)現(xiàn),終于有一種方法能讓業(yè)務(wù)和開(kāi)發(fā)真正對(duì)齊。





























