DDD聚合:一致性邊界 -James Hickey

banq發表於2020-05-01

在原始的域驅動設計書中,埃裡克·埃文斯(Eric Evans)對聚合解決了哪些問題進行了評論:

需要保持適用於緊密相關的物件組的不變性,而不僅僅是離散的物件。
什麼是不變式?

不變是業務規則,必須始終保持一致。
換句話說,我們的應用程式中經常會有跨越多個物件的業務規則。我們該如何處理?
聚合嘗試解決兩個主要問題:與業務規則和高爭奪性有關的一致性(即資料庫表中所謂的“鎖”)。

示例:圖書館預訂
如果圖書館有一個可供人們租用的龐大書籍/書卷怎麼辦?某個時刻只能一個讀者租界這本大書,如果將這本書的章節拆分成多本書,減少爭奪,則更多人可以分享這本書的內容。
假設所有這些作為物件存在於您的軟體中,一個龐大的物件模型將是一致的,但是會遇到爭用問題,很多人想租借同一本書籍怎麼辦?小物件將面臨更少的爭用,但是當多個使用者試圖修改這些小物件時,小物件之間將難以保持一致性。

事務一致性
考慮一下資料庫事務。當我們將事務提交到資料庫時,我們之所以這樣做,是因為所有相關資料只是真正地連在一起。

DDD聚合:一致性邊界 -James Hickey

不變性內的一致性
讓我們採用一致性和不變性這兩個概念,並將它們融合在一起。
假設您正在使用時間跟蹤軟體。
兩位不同的經理正在增加為員工工作的時間。

DDD聚合:一致性邊界 -James Hickey

這會很好,因為一位經理修改的日期與另一位經理修改的日期不同。實施的程式碼將每天分別獲取,並且它們也儲存為不同的資料庫行。因此,這裡沒有爭用問題。
當要求我們限制整個時間表的總工作量時會發生什麼?

DDD聚合:一致性邊界 -James Hickey
在此示例中,當前整個時間表狀態目前是32小時,最大值不應超過40小時(這是我們的新業務規則)。兩個經理各自在兩個不同的日期(一個在週一,另一個在週二)增加了8個小時,兩者都將從資料庫中查詢時間有32小時,這時第一個加入的8小時已經成功完成了,而另一個操作已經獲取了時間狀態還是32個工作小時(banq注:類似資料庫ACID的髒讀),那麼第二個操作也會成功。這樣就有了48小時的時間表(但是業務規則是最大值不應超過40小時)。這種情況表明,我們還沒有建立某種一致性邊界。

增加一致性邊界
如果我們在整個時間表和相關物件周圍新增邊界,該怎麼辦?
我們可以將整個時間表視為所有可能發生的操作或其“內部”事物的“門戶”。

DDD聚合:一致性邊界 -James Hickey

現在,整個時間表上的任何操作都必須透過聚合體。這個聚合體好像一個保鏢或代理者。​​​​​​

DDD聚合:一致性邊界 -James Hickey

現在,我們已經在整個時間表上新增了一個一致性邊界,我們可以控制對其執行哪些操作。我們的邏輯並未分散在系統的不同部分。
注意:是的,爭用和鎖定仍然存在問題。我們將在另一篇文章中介紹。

經驗總結
將真實不變式建模為一致性邊界。不變性應驅動我們的總體設計。
不變性根據業務規則,但是,一項業務可能沒有複雜的規則,另一個可能有非常嚴格的規則。這將影響我們設計軟體的方式,從而影響總體邊界。

真正不變性
例如,假設我們正在建立一個影片遊戲,兩個人互相打架。
如果對手的健康點降低到0,會發生什麼。但是,他們沒有死?然而。
也許在幾秒鐘內,系統就會檢查,然後對手就會死去。那有意義嗎?沒有。

DDD聚合:一致性邊界 -James Hickey

真正的不變式是那些需要在與該規則相關的操作相同的交易中保持一致的變數。換句話說,業務規則執行以後沒有必要被再次“檢查”。“檢查”或驗證應該是在某些操作進行時。(banq注:高實時的事務性)
例如,如果線上保險申請中的一項規則是確保申請人的信用評分足夠好以允許他們購買保險,該怎麼辦?
我們是否需要在申請人提交申請的同時進行檢查?不。
我們可以稍後再做,該系統將很有意義。
我們可以說保險申請最終是一致的。在將來的某個時候,當我們“等待”系統執行操作時,我們知道事情最終會解決。
作為業務流程,有意義的是,提交的申請“正在”被批准(或拒絕)。
從事務的意義上講,這些將不被視為真正的不變式。雖然,它們仍然是重要的業務規則。

結論
第一條經驗法則:將真實不變式建模為一致性邊界。花一些時間思考一下您的系統。什麼是真正的不變數的呢?哪一個不是?如果根據相關不變數對物件建模,會發生什麼?

原文點選標題
banq注:需要資料兩個表以上使用外來鍵等約束規則保持書籍一次性一致更改的,都可能需要放入一個聚合;或者,區分業務規則與業務流程,涉及到業務流程的長時間事務不能放入聚合,聚合跨時間邊界太大,但是業務規則與業務流程有時很難區分,業務規則透過業務流程來實現的。參考:https://www.jdon.com/54022

相關文章