本文書接上回《為了落地DDD,我是這樣“PUA”大家的》 ,歡迎關注我的同名公眾號。
https://mp.weixin.qq.com/s/DjC0FSWY1bgJyLPIND5evA
什麼是最重要的事
如果你認真讀過前面的文章,那麼一定知道我們的核心邏輯:領域驅動是一種價值觀,這個價值觀是:“領域(邊界)”的明確是軟體設計掌控複雜度最重要的事。
那麼整個軟體交付過程中,架構師的職責就是持續保持“需求”、“模型”、“程式碼”三者的邊界範圍明確且一致。再回過頭看整個軟體交付存在的意義,就是為了滿足需求,因此本質上來說,“需求”的邊界就決定了一切,那麼結論就不言而喻了:
最重要的事,就是需求的邊界(範圍)。
什麼叫邊界明確
假如說我有兩個需求A和B,那麼我們建模的時候就有如下幾種結果,大家感受一下,通常情況下,自己給出的結果是哪個選項?哪個選項又是最理想的?
我相信大部分人都會認同,其中B和D是符合邊界明確、需求與模型邊界一致的原則的,而現實的情況大部分結果是A和C,各種各樣的“join”充斥著系統的各個角落,一個典型的例子,就是使用者-角色系統的設計。
使用者-角色系統,通常會有這樣幾個關鍵需求:
- 建立使用者
- 建立角色
- 為使用者設定角色
- 檢視使用者有哪些角色
- 檢視一個角色包含多少個使用者
我們用最傳統的設計方法來做,模型大體是這樣的:
這樣的結果是不是對應到了前面選項A和C比較類似?因為“使用者聚合”與“角色聚合”連線的存在,導致需求與模型的邊界不一致。
而我們要做的,就是在滿足所有需求的同時,消除打破邊界的連線。
如何操作
首先我們分析上圖,假如我們把下面幾個需求先去掉:
- 為使用者設定角色
- 檢視使用者有哪些角色
- 檢視一個角色包含多少個使用者
那麼我們會得到一個符合邊界明確原則的設計:
然後我們再思考,下面兩個需求,應該哪個聚合負責:
- 為使用者設定角色
- 檢視使用者有哪些角色
答案很顯然是“使用者聚合”,那麼我們可以得到下面的設計:
這時你會疑問,如果沒有“使用者聚合”和“角色聚合”的連線,怎麼設定使用者有哪些角色呢?
問題的關鍵,就在這裡,通常我們總是會把“關係表”在圖中用一條線來表示,那如果我說,“使用者聚合”有一個集合屬性,叫做“使用者角色”,你會認同嗎?如果我們知道使用者物件有一個集合屬性叫“使用者角色”,那麼是不是上圖就很合理?
如果順著這個思路,我們再來看需求“檢視一個角色包含多少個使用者”,它應該由哪個模型來解決?我想你已經知道答案了,就是“使用者聚合”,最終我們得到如下設計:
到此,所有的需求可以滿足,需求被劃分為兩個範圍,分別對應兩個模型。
為什麼說它很難
如果你一直跟著我的思路,完成了上面的過程,那麼你會發現,需求的邊界不是客觀存在的,而是我們主觀的劃分,這個劃分的目的是為了在一個確定的範圍內,能夠解決這個問題。因為它是主觀的,就不可衡量和判斷,每個人都可以有自己的劃分思路。另外它又是簡單的,因為你可以像上圖一樣,這樣劃分邊界,給出對應的模型解決它,就像在給自己家的襪子分配收納盒一樣簡單。
所以,我常常嘆息,關於領域驅動設計:
說它難,難的是做出取捨。
說它簡單,是因為能明確知道取什麼舍什麼。