網域事件
捕捉影響網域的有趣事件記憶

2005 年 12 月 12 日
這是 進階企業應用程式架構開發 的一部分,是我在 2000 年代中期撰寫的。遺憾的是,自那以後,太多其他事情吸引了我的注意力,所以我沒有時間進一步研究它們,我也看不到未來會有太多時間。因此,這些材料很大程度上仍處於草稿階段,在我能夠找到時間再次研究它們之前,我不會進行任何更正或更新。
星期二,我到 Babur's 用餐,並用信用卡付款。這可以建模為一個事件,其事件類型為「進行購買」,其主體是我的信用卡,其發生日期為星期二。如果 Babur's 使用舊的手動系統,並且直到星期五才傳輸交易,則通知日期將為星期五。
事情會發生。並非所有事情都很有趣,有些事情可能值得記錄,但不會引發反應。最有趣的事情會引起反應。許多系統需要對有趣的事件做出反應。通常您需要知道系統為何以它所做的方式做出反應。
透過將輸入引導到 網域事件 串流中,您可以保留系統所有輸入的記錄。這有助於您組織處理邏輯,並允許您保留系統輸入的稽核記錄。
運作方式
網域事件 的精髓在於,您使用它來捕捉可以觸發您正在開發的應用程式狀態變更的事物。然後處理這些事件物件以導致系統變更,並儲存以提供 稽核記錄。

圖 1:事件將漏斗輸入到單一來源。
圖 1 有助於說明此觀點。在這裡,我們有一個系統,其輸入來自使用者介面、訊息系統和資料庫表格的一些直接操作。為了將這些解析為 Domain Event,我們有與這些輸入串流中的每一個互動並將輸入轉換為儲存在持續記錄中的 Domain Event 串流的元件。然後,事件處理器會從記錄中讀取事件並處理它們,觸發我們的應用程式執行它應該執行的任何操作。
在此串流中,系統的第一個輸入層不會對刺激採取任何動作,只會建立並記錄事件。然後,第二個層可以忽略實際的輸入來源,它只會對事件做出反應並處理它。
對於這個範例,我只顯示一個事件記錄。在實務上,如果事件有不同的回應需求,通常有必要將記錄分開。使用者介面通常會想要比許多遠端訊息系統更快的回應時間,因此將使用者介面流量放入不同的記錄並為它們使用不同的處理器是有道理的。
此圖暗示非同步管道和過濾器風格的互動,但這不是此方法的必要部分。事實上,一個常見的方法(特別是對於使用者介面刺激)是讓 UI 處理常式直接在同步互動中呼叫事件處理器。
每個 Domain Event 都會擷取來自外部刺激的資訊。由於這已被記錄,而且我們想要將記錄用作稽核追蹤,因此這個來源資料不變是很重要的。也就是說,一旦您建立事件物件,這個來源資料就不能變更。然而,事件上還有另一種資料,記錄系統如何處理它 - 我稱之為處理資料。我將 Domain Event 上的資料描述為不變的來源資料,它擷取事件的內容,以及可變的處理資料,它記錄系統對事件的回應。信用卡收費的來源資料將包括收費金額、供應商是誰等。處理資料可能包括它出現在哪個報表中。如果您的平台特別支援不變物件,那麼將事件拆分成兩個物件以利用這個功能可能是值得的。
儘管來源資料永遠不會變更,但系統可能需要處理變更,通常是因為原始事件不正確。您可以透過接收此變更為一個獨立的追溯事件來處理此變更。然後,處理器會處理追溯事件以修正較早錯誤事件的後果。通常,此處理可以在非常通用的層級上完成。
第三個,但僅偶爾出現的事件資料類別,是來自事件串流中其他資料的衍生快取資料。在這些情況下,事件處理器會在處理目前事件時,摘要過去事件的資訊,並將該摘要資料新增至目前事件以加速未來的處理。如同任何快取,重要的是發出訊號,表示在發生任何調整時,此資料可以自由移除並重新計算。
不同的事件發生於不同的原因,因此使用不同類型的事件很常見。然後,事件處理器會將事件類型用於其分派機制的一部分。事件類型可以使用事件的子類型、獨立的事件類型物件,或兩者的混合來表示。
不同類型的事件攜帶不同的資料很常見,因此對事件類型使用事件的子類型非常適合。子類型的問題在於這會導致類型激增,如果大部分資料相同,這特別令人沮喪。混合方法使用子類型來處理不同的資料和事件類型物件來發出分派訊號。
事件是關於在時間點上發生的某事,因此事件包含時間資訊是很自然的。執行此操作時,重要的是考量可以與事件一起儲存的兩個時間點:事件在世界上發生的時間和事件被注意到的時間。這些時間點對應於實際時間和記錄時間的概念。
當然,您並不總是需要兩個時間點,但您應該始終考量是否需要兩個。風險在於選擇一個時間點,並且不清楚您選擇哪個時間點,無論是在當時或稍後。因此,我也建議您清楚地命名時間點以指出它是哪一個。
您可能需要多個記錄 時間點 來記錄事件被各種不同系統注意到的時間。
何時使用
透過 網域事件 擷取系統刺激是一項重大決定。它會對應用程式套用一種不同的架構樣式和一種程式設計模型,而這種模型通常會令人感到彆扭,至少在剛開始時會這樣。在這個時間點,還不清楚在您習慣這種方法後,這種方法是否真的需要更多努力。
儘管其不尋常的性質,我認為使用這種方法有一些顯著的好處。
事件的 稽核記錄 提供了一份完整的記錄,這對於稽核和除錯目的都很有價值。如果系統進入一種奇怪的狀態,您會有一份完整的輸入記錄,讓您知道系統是如何進入這種狀態的。透過儲存實際處理的事件,您可以降低忽略將重要資訊寫入 稽核記錄 的機率。
清楚的事件串流讓其他系統更容易在未來替換應用程式的一部分或全部,方法是新增一個 訊息路由器 來將事件轉移到新的系統。雖然以一種促進系統最終消亡的方式來設計系統並不時髦,但系統替換專案的頻繁程度應該表示我們應該更加注意這一點。
網域事件 對於 事件溯源 來說特別重要,事件溯源是一種必要的模式,它組織系統,以便透過 網域事件 進行所有更新。