一家大型企業(yè)的關鍵業(yè)務代碼已經年久失修成為了難以維護的遺留代碼伐庭,有著硅谷高科技企業(yè)軟件開發(fā)管理經驗的高管決定在企業(yè)內部搞編寫單元測試和重構的極限編程實踐。這需要為企業(yè)遺留系統(tǒng)的代碼編寫自動化單元測試鳞仙。那么編寫自動化單元測試該從哪里入手呢请唱?
上文所提到的“領域驅動設計中國峰會2017”大會Event Storming 之父 Alberto Brandolini授課一天的“事件風暴工作坊”下午的“軟件開發(fā)設計”(Software Design)環(huán)節(jié)费就,可以讓開發(fā)團隊了解系統(tǒng)應該具備的領域模型及其交互關系润文,為編寫單元測試進而驅動重構提供指導。
以下是實施步驟:
完成了“探索業(yè)務全景”環(huán)節(jié)豁跑。
確定要建模的需求
在上午探索培訓機構的業(yè)務的基礎上廉涕,下午的任務是要為“替換Eventbrite在線應用“這個需求進行領域建模。假設你是Eventbrite的開發(fā)團隊且想了解如果入手編寫單元測試艇拍,那么可以把Eventbrite視作遺留系統(tǒng)狐蜕,用以下步驟來為其建模。-
了解領域模型之間的業(yè)務邏輯鏈
從需求的起源來看卸夕,用戶的需求來自于真實世界和 Read Model层释,并根據它們來進行 Decision Command(決策命令)。比如培訓課程的聽眾根據“課程快集、價格贡羔、日期廉白、講師、城市乖寒、是否有空”這些 Read Model 來決定是否去報名參加培訓蒙秒。
用戶做了 Decision Command后,就會通過 Aggregate (像個狀態(tài)機)或 External System (外部系統(tǒng))來產生一個 Event(領域事件)宵统。
這些事件又可能會通過一個 Policy (業(yè)務規(guī)則)來觸發(fā)下一個 Decision Command晕讲。
- 用7種報事貼來貼領域模型并梳理業(yè)務邏輯鏈
- Read model: 淺綠
- User: 黃色小報事貼
- Decision Command: 淺藍
- Aggregate: 黃色大報事貼
- Event: 橙色
- External System: 淺粉大報事貼
-
Policy: 紫色大報事貼
按照從左到右的時間順序來貼:
下面其中一組同學貼出的培訓課程報名訂票的業(yè)務邏輯鏈(報名者根據培訓日期訂票瓢省,通過一個未起名的 Aggregate 生成了 Ticket Booked 事件痊班,這個事件又經由 Purchase Policy 觸發(fā)了 Reserve Payment 的命令):
事件風暴之父的忠告
領域建模達成一致是很困難的,要有充分的心理準備馒胆。
-
要邀請領域專家和團隊所有成員,貼報事貼的空間要足夠大凝果。
-
在團隊貼報事貼時,要觀察不同業(yè)務部門的人的活動范圍(比如財務人員不會跑到左邊“培訓課程準備子域”來貼報事貼型雳,這很正常),這能啟發(fā)你識別核心業(yè)務子域纠俭。有些核心業(yè)務子域是長長的一條,像泳道浪慌。有些則集中在一處冤荆,有些則會出現在一頭一尾,這也很正常权纤。
-
事件風暴領域模型聚集的方式有點像樓房——一片一片地出現。
-
開發(fā)團隊不要盲目相信業(yè)務人員編寫的用戶故事欧宜,要合理地向業(yè)務人員 challenge 這些用戶故事后面發(fā)生的事情坐榆。
-
業(yè)務中的分支和開關會讓你備受折磨,你需要衡量它們的全局價值成效來做取舍冗茸。
Aggregate 和 Policy 的名字很難起席镀,可以以后再起名匹中。
Policy 是一種響應式的業(yè)務邏輯,它一旦接收到 Event豪诲,就會觸發(fā)一個 Decision Command顶捷。
-
有時候 Event 會通過"人工"的 Policy 來觸發(fā)一個 Decision Command,但有時事實并不是這樣的……
-
要識別那些“千夫所指”的業(yè)務瓶頸屎篱,首先消除這些最大的障礙服赎,才能有效提升全局優(yōu)化的成效。
我的一些理解及 Brandolini 的回復
- Aggregate 可以理解為“數據完整性的維護者”重虑。
- “千夫所指”的業(yè)務瓶頸可以作為編寫自動化測試的第一個測試用例。
- 我試圖把 Brandolini 的上述7種事件風暴領域模型與 Evans 的 Model-driven design 中談到的7種領域模型按下面的方式對應起來秦士,但Brandolini給了令我驚嘆的回復:
- 我試圖兩者對應起來:
- Read model(淺綠)可以對應 Entities 和 Value Objects缺厉,而后兩者可以用 Factory 來創(chuàng)建,其中 Entities 可以保存在 Repositories 里面隧土。
- User(黃色小報事貼)沒有對應提针。
- Decision Command(淺藍,可以對其編寫自動化測試)可以對應 Aggregates曹傀、Entities 或 Value Objects 里面的行為辐脖。
- Aggregate(黃色大報事貼,可以對其編寫自動化測試)可以對應 Aggregates 卖毁,而 Aggregates 可以由 Factory 來創(chuàng)建揖曾,之后可以保存在 Repositories 里面落萎。
- Event(橙色)可以對應 Domain Events。
- External System(淺粉练链,可以對其編寫自動化契約測試)可以對應 Services。
- Policy(紫色媒鼓,可以對其編寫自動化測試)可以對應 Aggregates绿鸣、Entities 或 Value Objects 里面的行為。
- Brandolini 的回復:
- Eric Evans的領域模型出現在CQRS之前亮蛔。雖然這些模型目前仍然有效究流,但是CQRS的影響力更大。
- Read Model 如今是(DDD領域中的)一等公民芬探。而將其對應到 Entities 和 Repositories 曾經是以前那些做法的薄弱環(huán)節(jié)。
- Policies 其實是被漏掉了哩簿。Eric 從來沒有說過領域模型的搜集工作已經完成了卡骂。所以對于這一點沒有所謂的官方建議形入。一些人創(chuàng)建了代表進程的聚合,另外一些人則將大量的邏輯推向了 Application Services(這通常讓領域模型變得貧血)浓若。 Greg Young 曾指出在這些方面應該有所變化蛇数。
- 我偏好于“對稱性”的領域建模,即將 Aggregates 將 Commands 轉化為 Events碌上,而 Policies 對 Events 作出響應并調度 Commands 來進行工作浦徊。
- 我試圖兩者對應起來:
總結
對于要為企業(yè)遺留系統(tǒng)的代碼編寫自動化單元測試的開發(fā)團隊,可以在進行了“探索業(yè)務全景”環(huán)節(jié)之后霞丧,使用“軟件開發(fā)技術”環(huán)節(jié)中的識別7種事件風暴領域模型的技術蛹尝,來優(yōu)先梳理那些“千夫所指”的有業(yè)務瓶頸的業(yè)務的邏輯鏈悉尾,然后可以開始對其中的 Decision Command、Aggregate 和 Policy 編寫自動化單元測試愕难。用這些單元測試來驅動遺留系統(tǒng)代碼的重構,讓遺留系統(tǒng)的代碼變得易于維護拄衰。