[翻譯]-領域事件-Martin Fowler

劉曉日發表於2011-08-29

作者:MartinFowler 譯者:劉曉日

讓我們回憶一些影響領域的趣事。

enter image description here

場景:星期二去Babur's吃飯,使用信用卡付賬。這就可以定義為一個事件,事件型別可以叫做make purchase,事件源為信用卡,事件發生時間為星期二。如果Babur's飯店使用的是老舊的半自動化系統,並且直到星期五才最終提交該賬單,那麼最後的記錄時間則是星期五。

嗯,事情就這樣發生了。並不是所有的事件都需要去觸發,然而也存在某些有價值的事情發生了,卻並未做出任何響應。畢竟重要的事件才需要為之做出響應。大多數系統需要主動觸發某些事件,然後做出響應。通常,你需要弄清楚觸發什麼樣的事件系統才需要做出反應。

這種通過漏斗狀方式將請求傳送到領域事件流再傳輸到系統中的形式,使你可以在系統中記錄下所有請求資訊。這樣有助於你組織邏輯處理,而且你還可以使用“檢查日誌”記錄系統的所有請求。

How it Works

領域事件的精髓在於,它可以捕獲那些可引發應用程式狀態改變的事件,然後事件物件處理系統變化,並儲存在“檢查日誌”中(日誌的一個簡單變種)。

enter image description here

圖1:多請求與單一事件源

圖1有助於我們理解領域事件的精髓。圖中系統可以接受來自使用者介面、訊息系統和一些可以直接運算元據庫表的不同請求。為每種請求都提供了對應的元件介面,將請求轉換成領域事件流儲存為持久日誌,以供領域事件使用。然後事件處理器(Event Processor)從日誌中讀取事件,觸發應用程式中預先定義好的操作。

在這個過程中,系統中請求的第一階段的職責僅僅是建立並且記錄事件;第二階段則完全可以忽略原始請求的存在,只針對事對其進行處理。

例子中我只提到了使用單一事件日誌的方式。在實際專案中如果事件有多種響應的需求,那麼將日誌進行分離還是很有必要的。使用者介面類請求響應要比遠端訊息系統有更快的響應速度,所以為使用者介面類請求提供單獨的日誌和事件處理器絕對是一個不錯的選擇。

圖中暗含了互動過程以非同步的管道和過濾器方式進行,但這不是唯一的方式。事實上多數的方法,尤其是通過使用者介面方式觸發的,是通過使用者介面(UI handler)以同步的互動方式直接呼叫事件處理器。

每個領域事件都從外部觸發點捕獲資訊,由於這些資訊事先已經被記錄下來,而且被當做檢查追蹤的依據,所以源資料應該是不可改變的。也就是說一旦事件物件被建立,源資料就不能被修改。當然事件中還有一類資料用於記錄系統進行了哪些響應,稱之為處理資料。領域事件中的資料可劃分為不可改變的,用於捕獲事件的源資料和可變的,用於記錄系統對事件作出哪些響應的處理資料。信用卡付費的示例中,源資料應該包括:賬單金額、付費人等不可變資訊。處理資料包含哪桌客人要求結賬的資訊。如果平臺中需要支援不可變資料,或許可以利用這個區別將事件封裝到兩個不同的物件中。

儘管源資料不可改變,但是有時候系統需要處理變化,就比如原始事件不正確的場景。可以將這種變化當做“追溯事件”來處理。然後事件處理器通過處理“追溯事件”糾正剛剛發生的錯誤事件。通常這種處理會放在比較通用的層次上實現。

還有一種很少使用的快取資料,用來快取事件流中源資料或其他資料。在這些場景下,事件處理器在彙總已經發生事件資訊的同時處理當前事件,並且將彙總資訊新增到當前事件,以加速當前事件處理速度。和其他快取技術具備同樣的特性,就是在任何調整發生時,資料都可以被刪除和重新計算。

不同的事件由不同的原因引發,所以使用事件型別標識事件。作為事件處理器排程機制的一部分,事件型別可以代表子型別事件、單獨的事件物件,或兩者混合的方式。

使用不同型別的事件持有不同資料很常見,事件型別的子型別可以很好的處理這種狀況。美中不足的是事件子型別會導致型別擴散,尤其是在事件所持有資料中大部分都相同的情況下。

事件是發生在某個時間點上的事情,所以事件本身就包含時間資訊。事件儲存有兩個重要的時間點:事件發生時間和事件被記錄時間。這兩個時間點對應事件發生和記錄時間的概念。

當然不是任何情況下都需要這兩種時間點,但是需要考慮是否有可能同時需要他們。使用一種時間點的風險在於不清楚使用的是哪種時間點,也許時間剛好也可能稍有延遲。所以建議大家在使用的時候明確指出時間點型別。

有些情況可能需要多個時間點來記錄事件何時被哪個系統所捕獲。

When to use it

使用領域事件捕獲系統觸發,是一項重大的決策。開始可能很難接受它具用侵入性的將自己注入到應用或模型中,然而當習慣使用它的時候,是否能獲得更大的收益還不是確定性的。

儘管領域事件的使用方式不那麼令人滿意,但使用它確實可以帶來眾多好處。

事件的檢查日誌記錄了完整的資訊,使對程式的追蹤和除錯成為可能。當系統出現異常,就可以在這裡找到異常資訊。通過將重要資訊儲存到檢查日誌中,可以大大減少因為疏忽而遺漏掉重要資訊的機率。

清除事件流使將來對應用的部分甚至全部更換變得更容易,增加一個“訊息路由”將事件傳遞到新系統中即可。雖然這不像推倒原有系統,重新設計系統方式那麼主流,但是當系統重出現頻繁替換原有程式的時候不妨考慮下這種方式。(Although it isn't fashionable to design a system in a way that facilitates its eventual demise, the sheer frequency of system replacement projects should mean we ought to pay more attention to it. )

事件源作為領域事件的組成部分發揮著巨大的作用,使系統中的所有改變活動都通過領域事件來實現。

原文地址:http://martinfowler.com/eaaDev/DomainEvent.html

宣告:答應溫謙老師的貧血模型的示例還在進行中。

相關文章