Bounded Context和域邊界
Bounded Context(BC)是單個Ubiquitous語言,一致模型和不變量在其中運行的清晰邊界。在邊界內,術語是明確的(「Stake」,「Customer」,「Limit」),向外上下文通過合同(事件/命令)進行交流,並且不會向內拉其他語義「尾巴」。精心選擇的邊界減少了連通性,簡化了縮放並加快了產品的進化。
1)為什麼需要邊界
認知負荷降低。該團隊使用一種模型和一種語言,而不是「同時進行整個業務」。
不變量隔離。關鍵規則(平衡≥ 0,登錄的唯一性)生活在同一位置,並受到集合的保護。
變更管理。卑詩省內部計劃/規則的演變不會打破鄰居-有明確的合同。
性能和可靠性。在BC內部,可以選擇合適的一致性模型和存儲。外部-異步投影。
2)如何識別Bounded Context
快速方法(workshop 2-4小時):1.事件風暴:將域事件「發生了什麼」加起來,然後命令「要求做什麼」,然後加上「誰保證規則」。
2.語言集群:單詞和規則始終重合的地方-潛在的BC。其中「客戶」一詞表示不同(付款人vs玩家)-存在明顯不同的上下文。
3.不變量和ownership:什麼不能被破壞,誰來回答?不變性→可以保證它的BC內部。
4.價值流:將經常改變在一起的步驟分組,這些步驟是一個卑詩省候選人。
5.組織結構:如果一個部分由具有單個KPI的單獨命令完成,則可能是單獨的BC(但反之亦然:組織結構不應盲目地決定模型)。
邊界信號:- 術語爭議(「出價」,「票證」,「回合」-不同的含義)。
- 最熱的不變量「流過」服務。
- 不同的SLO和變化速度。
- 為了原子性,模塊之間的「雙寫」。
3)典型上下文(主題領域的示例)
Identity/KYC-註冊、驗證級別、約束狀態。
Wallet/Ledger-資產負債表,電匯,儲備,貨幣。
Betting/Orders-接收,報價,結算。
遊戲/回合是回合的生命周期,結果。
Bonus/Promo-權責發生制,vager,轉換。
Payments-存款/收款,支付網關狀態。
Compliance/Reporting-報告、審計、監管展示。
Catalog/Provider Integration-遊戲,版本,提供商狀態。
Analytics/Read Models-投影和實例化視圖。
4) Context Map: BC如何交互
上下文映射捕獲關系類型:- Customer–Supplier.一個BC(Supplier)提供事件/數據,另一個(Customer)調整其模型。
- Conformist.客戶采用Supplier語言和模型(例如,監管註冊表)。
- Partnership.兩個BC同步演變語言和合同(通常是一個團隊/路線圖)。
- Shared Kernel.一般最低升降機/圖書館,共同考試;謹慎使用。
- Anti-Corruption Layer (ACL).保護層,將別人的模型翻譯成自己的語言。
- Open Host Service / Published Language.公共協議/計劃,經過審查和記錄。
實踐:默認情況下,使用ACL和異步事件;Conformist-僅當提供商規定標準時,Shared Kernel才是最低限度的和有意識的。
5)邊界=語言+模型+不變量+存儲
在BC內定義:- Ubiquitous Language.帶有示例的術語詞典。
- 聚合和不變量。誰「持有」規則,允許哪些操作。
- 一致性模型。Strong/CP用於金錢,EC/causal用於店面。
- 存儲和索引。選擇不變量和SLO。
- 退出合同。事件/命令,方案版本,交付的SLO。
外部:沒有直接SQL/表約束。溝通-通過合同。
6)邊界與一致性(PACELC)
在BC內部:選擇不變量的模型(接收處的Wallet-Strong,Betting-Strong)。
在BC之間:最常見的是事件和投影。如果需要同步檢查-帶有截止日期和不可用故障的顯式命令(不是「隱藏」REST電話)。
7)反腐敗層(ACL)
ACL任務:不要讓別人的語言和「臟」數據進入卑詩省。
圖解映射:外部「PaymentStatus=SETTLED」 →內部「LedgerEntry(類型=信用,reason=PsPSettle)」。
驗證和豐富:不變性驗證,時區規範化,貨幣。
轉化:支持「schema_version」外部合同,向後兼容性。
相同性:通過「external_id」/「operation_id」。
可觀察性:「有毒」消息的「源」,「schema_version」,「mapping_id」,DLQ。
8)邊界和數據: 所有權,投影,API
Ownership:誰擁有「真相」?只有所有者更改記錄。BC的其余部分是read模型和參考。
投影:讀取下的非標準化表;從事件中更新。
API:命令(與所有者發生變異)和查詢(閱讀投影)。沒有其他數據的「端到端」更新。
9)演變和版本
事件和API-具有「schema_version」和兼容性策略(additive+fallback)。
Blue/Green by BC:新合同「v2」平行於「v1」發布,流量逐漸轉移。
遷移:對於重大變化-新的投影/服務,閱讀的「兩階段卷軸」。
10)邊界測試
合同測試:檢查BC是否遵守已發布的合同(產品測試),並正確理解別人(消費者測試)。
基於屬性的:BC內部的聚合不變性(平衡,限制,唯一性)。
集成上的混亂:延遲,訂單外部,復制,計劃進化;具有DLQ和安全的redrive。
NFR測試:p95/邊界峰值負載 (事件服務器/ACL)。
11)可觀察性和SLO邊界
度量標準:通過事件/命令、'projection_lag_ms'、'dlq_rate'、mapping錯誤、p95 API。
Tracing:強制性標簽'bc'、'tenant_id'、'event_id'、'operation_id'、'schema_version'。
Alerts:投影滯後,命令故障增加,方案「flap」(許多「schema_mismatch」)。
12) multi-tenant和地區
「tenant_id」-在邊界上所有事件和投影的鍵中。
Fairness: 發布限制/redrive per tenant以使「嘈雜」不會破壞鄰居的SLO。
居住地:卑詩省的數據生活在「家庭」地區;跨區域匯總/報告。
13)反模式(由模糊的邊界引起)
巨型「核心服務」。每個地方都→事務鬥爭,長版本,低自主權。
表集成。直接選擇到別人的表→脆弱性,並在模式下進行配對。
Dual-write.同時「方便」地寫成兩個BC,→發散和不變量的破壞。
默認的Conformist。「采用別人的模式」→別人的含義被泄露,進化是不可能的。
隱藏同步呼叫。REST的「內部某個地方」沒有明確的合同和截止日期→出乎意料的可用性依賴性。
14)輪廓示例(語言方案)
[Wallet/Ledger] <--CP, Leader, Transactions-->
publishes: WalletReserved/Committed v
[Betting] <--CP on bid taking-->
events: BetPlaced/Settled v
[Read Models/Analytics] <--EC projection-->
[Payments] --ACL--> [Wallet/Ledger]
[Provider Integration] --ACL--> [Game/Round]
[Compliance] <-events - [KYC/Identity], -> reports [Reporting]
15)邊界選擇迷你海德
1.形成不變量並確定誰可以保證它們。
2.描述字典(10-20個術語),並檢查團隊是否有一種理解。
3.繪制Context Map和關系類型。
4.解決內部和連接上的一致性模型。
5.設計合同(事件/命令)和ACL。
6.規劃可觀察性(度量/tracing/alerta)和DLQ/redrive。
7.進行合同測試和「風暴」(chaos)以進行集成。
8.確定政府:誰會說語言/方案,如何進行更改。
16)售前支票清單
- 每個BC都有字典,匯總和不變量。
- 在Context Map上定義了關系並記錄了合同。
- 通過事件/命令和ACL進行集成,沒有直接SQL依賴關系。
- 指揮/事件的相等性;有outbox/inbox和DLQ。
- 一致性模型(BC內部/之間)已提交並測試。
- 電路轉換和互操作性策略(v1/v2)。
- Laga/Error/Performance和Alerta度量標準已配置。
- 遵循多重性和數據駐留政策。
- 操作花花公子:schema-mismatch, redrive, rebuild投影。
17)快速食譜
金錢和限制:帶有CP和交易的單個BC,僅限命令API,事件作為讀取真理的結果。
Fids/目錄:帶有EC的BC,投影和緩存,顯然是「新鮮」。
與外部提供商的集成:始終通過ACL、事件/命令、模式轉換。
團隊成長:一個BC是一個團隊,團隊具有「語言所有者」和「不變量守護者」。
重構整體:首先是合同和ACL,然後是物理分離。
結論
Bounded Context不僅是圖表,而且是關於語言,規則和演變方法的工作約定。清晰的邊界減少了連通性,加快了變化,並使系統可預測地運行。根據含義和不變性進行劃分,保護ACL邊界和合同,使用所有指標進行測量-即使域和團隊快速增長,您的體系結構仍將保持靈活和可靠。