重讀領域驅動設計——如何說好一門通用語言
結論先行:
在 DDD 中,通用語言是以限界上下文為邊界的。如果一個產品或者項目有多個限界上下文,我們就需要為每個限界上下文定義通用語言。
限界上下文提供了一個語義邊界,來保持通用語言和領域概念的一一對應關係。這個約束解決了現實世界中同樣的名詞在不同場景、時機下對應不同的業務概念所帶來的歧義問題,幫助團隊在使用通用語言交流的時候可以無歧義溝通。
初嘗「通用語言」
最初我對於如何構建通用語言的認識,來自於《領域驅動設計》第一章中的案例。這個案例生動的展示了開發人員如何在和領域專家的溝通過程中,建立了雙方理解一致的通用語言,並且使用這個語言來進行雙方的溝通。基於那個案例,我當時對構建通用語言的理解就是要:
- 技術人員使用業務人員的用語作為開發辭彙;
- 劃分好聚合,將這些辭彙關聯到聚合上;
- 技術人員要將這些辭彙映射到代碼實現中;
- 這些辭彙會隨著項目的發展一點點擴展;
帶著這份理解,我在曾經負責過的小型項目上做了一些實踐,效果都很不錯。在很長一段時間,團隊的開發人員體會到了在和業務人員交流時候心有靈犀、會心一笑的快感;也很少聽到「這個東西不是我要的」這類批評了。
「通用語言」遇到同名辭彙時就變得不清不楚了
然而,當我來到ThoughtWorks參與到一些幾十號人的項目時,我發現根據這個原則構建起來的通用語言,在遇到同名多義的辭彙時,就無法保證團隊內部的溝通是無歧義的。而這種歧義又會導致團隊成員說著同樣的話想著不同的事情的情況出現,例如:
- 同名的業務辭彙與實際業務關係不清:「為什麼不能給銷售訂單增加一個是否投訴的欄位,界面上都是顯示在銷售訂單上的」——銷售訂單到底是個什麼東西,能幹什麼不能幹什麼是怎麼確定的?
- 同名的業務辭彙與不同的業務辭彙關聯:「我在銷售訂單付款後改變了買家信息,為什麼我看銷售訂單的預定里的買家也發生了改變」——這裡說的買家信息有幾個?
- 同名的業務辭彙之間的關係不清楚:「為什麼我變更了profile 上的買家地址,銷售訂單上的買家地址就跟著改變了」 ——這裡說訂單上的買家地址和profile 上的買家地址是一個什麼關係?
通過添加約束消除歧義
下圖是 DDD 概念的一個元模型圖。從圖的左下角,我們可以看到在構建通用語言時,還有兩個額外的約束條件:子域和限界上下文。