事件溯源中的時間和時間建模 - Tomasz Jaskula

banq發表於2021-12-01

Tomasz Jaskuła 是巴黎軟體諮詢公司 Luteceo 的技術長和聯合創始人。Tomasz 擁有 20 多年作為開發人員和軟體架構師的專業經驗,曾就職於電子商務、工業、保險和金融領域的多家公司。他主要專注於建立能夠提供真正業務價值、與戰略業務計劃保持一致並提供具有明顯競爭優勢的解決方案的軟體。Tomasz 還是 .NET 平臺的 OSS 專案 XOOM 的主要貢獻者。
 
DDD 和有界上下文
  • DDD 中最重要的是戰略部分。一開始,大約在 2007-2010 年,人們更多地關注 DDD 的戰術方面,比如儲存庫、實體、值物件等模式。我並不是說它們不重要。當然,當涉及到 DDD 實施時,它們是重要的工件,但是當您與業務人員和團隊中的其他成員構建無處不在的語言,並且從戰略的角度發現業務問題時,它們是整個戰略部分。所以這就是讓 DDD 有價值的原因。
  • 識別模型的不同上下文是 DDD 的一部分,稱為有界上下文。有界上下文表示這個概念的這個術語在這個特定的上下文中確實具有特定的含義,並且在不同的上下文中可能具有另一種含義。
  • 一旦確定了這些上下文,您就必須找到一種溝通和整合的方式。所以這也是戰略領域驅動設計的另一個非常重要的部分。
  • 您可以使用領域驅動設計中的實現和戰術工具,但您不能只選擇其中一個。您必須同時使用戰略和戰術部分。

DDD 和函數語言程式設計
  • 在函數語言程式設計中,您有這些不變性的概念。在 DDD 中,您有領域事件的概念。領域事件是已經發生的事實,您無法更改它們。你可以承認發生了一些事情。
  • 您擁有這個單元是域建模的重要組成部分,這一事實與函數語言程式設計非常匹配。當您使用諸如事件溯源CQRS 架構風格之類的東西時,當您擁有這個意圖的命令並且您擁有將命令輸入、應用狀態和生成新狀態的功能時,它可能更明顯。

 
時間建模:
  • 所有重要的業務和業務問題都與時間相關。
  • 回到業務上來,大部分時間我都看到我們正在開發的模型並沒有將時間作為第一要素,而且時間總是隱含的,就像一切都會立即發生一樣。
  • 有一些工件,如工作流、基於時間的業務流程。這些暗示我們時間會流逝,時間對業務很重要。那麼時間建模的意思是我們使用基於時間的工件作為第一建模公民。
  • 同樣,領域事件,它們與時間和時間流逝有關。需要注意的重要一點是,業務總是考慮包括時間,因此我們必須對其進行明確建模。如果我們不將時間建模為一個明確的東西,這就是許多問題潛入的地方。我們試圖解決問題,帶來意外的複雜性,從長遠來看,這會導致無法維護的軟體和大泥球。
  • 有不同型別的時間建模。可以有透過時間產生的觸發器。
  • 我提到的另一個工件是我們的領域事件。領域事件是不可改變的事實。商界人士關心的事情。它以過去時的動詞形式出現。因為這是事實,我們無法改變它。這是已經發生的事情,我們只能承認。但我們無法改變它。它是不可變的。
  • 在建模和建立域模型時在模型中使用領域事件也是一種時間指示。因為透過釋出事件,您對其他對此類領域事件感興趣的人說,發生了一些事情,由不同的利益相關方聽聽這些領域事件來對它們採取行動。但與此同時,它並沒有說它必須在之後發生。它引入了某種非同步關係,你真的不知道是否有人會在一毫秒、一秒或三天內採取行動。
  • 這就像時間的指示,它是由業務人員定義的。大多數情況下,當您不考慮時間時,開發人員或實現域模型的人員都試圖在同一時間立即發生所有事情。它會產生問題,因為我們必須建立不同型別的事務模型,所以一切都是以原子方式發生的。但在時間建模方面,情況並非如此。

三種不同型別的時間:
  • 有不同型別的時間建模,並且都在域建模中明確了時間。那些不同的型別是雙時態的,三時態的,我知道我們是否可以更進一步,它們都是為了回答不同的問題。
  • 雙時態建模基於兩個時間軸。
    • 正如你所說,有一個交易時間,有效的時間軸。因此,我們可以回答特定的問題,例如我的系統在某個時間點的狀態,或者我的系統在某個時間點的狀態應該是什麼,並瞭解發生了什麼。
    • 它背後的想法是使用交易時間作為交易發生的時間。例如,如果我們在系統中記錄了一些東西,我們會取當前日期,並將其放在交易時間上。但有效時間是自由定義的。
  • 三時態建模案例更進一步,因為您有第三個時間軸,即決策軸。它使查詢變得更加複雜,但它也為您提供了更多探索事實的方式。

 
事件溯源
  • 保持狀態的傳統方式是儲存當前狀態。事件溯源使用完全不同的以事件為中心的永續性方法。業務物件透過儲存一系列狀態更改事件來持久化。
  • 因此,每當物件狀態發生變化時,都會將一個新事件附加到已生成事件的序列中,並在僅附加儲存中。這就是透過重放在物件生命週期生命週期中發生的所有事件來重建業務物件當前狀態的方式。
  • 事件溯源是不同的,因為在您確定最重要的事實,即對業務和模型很重要的事件之前,每次發生變化時,您都會生成一部分狀態。因此,一個事件將被附加到日誌中,新增到事件源日誌中,即僅附加日誌。
  • 這樣,當您檢視新增到事件日誌中的事件型別時,您就會了解發生了什麼。我們究竟如何到達,我們如何到達當前狀態。因為所有事件都可以告訴您發生了什麼以達到當前狀態。
  • 當您只是丟棄以前的狀態並用狀態的新快照覆蓋它時,您無法在傳統方法中做到這一點。

 
何時使用事件溯源
  • 事件溯源允許您從不同的角度看待您的領域。因為不僅您知道您是如何獲得當前狀態的,因此這可以讓您瞭解您的系統或您的域中正在發生的事情。您永遠不知道將來如何使用這些事件。因此,它為您提供了更多關於您的域的資料,您可以在未來以不同的方式使用這些資料。因此,這是您在使用事件溯源時免費獲得的重要資訊,而在使用傳統方法時則無法獲得。
  • 狀態轉換是問題空間的一個非常重要的部分,它應該按原樣建模,而事件溯源對此有所幫助。所以我們可以看透已經發生的不同事件。不同的狀態發生了變化,要真正知道發生了什麼。所以這是非常重要的資訊。我會說,如果您有一個複雜的業務領域,並且您正在處理領域事件,那麼使用事件溯源比傳統方法更容易。
  • 我幾乎每次都在使用事件溯源來重構舊的遺留專案。所以我們所做的是透過事件將遺留系統與新的事件源上下文同步。即使您的舊系統不是事件源,您也只有當前狀態的快照。您可以使用多種技術將遺留系統與新事件源同步,比如微服務
  • 最簡單的方法是在遺留端生成事件。它可以透過使用 Change Data Capture 變更資料捕獲 之類的工具來掃描所有發生的事務,遺留系統中的資料來源。它們可以產生有意義的事件,您可以在新上下文中收聽這些事件,並將舊狀態從遺留狀態遷移到新上下文。
  • 或者,您可以自己與業務人員一起製作這些活動。您可以確定什麼是重要的。如果在遺留方面發生了變化,您可以生成對新上下文有意義的事件,並且您可以以這種方式同步,並以這種方式使用事件源上下文和新上下文或微服務。
  • 或者它發生在我正在從事的一些專案中,遺留系統有一些歷史資料,這些資料儲存在歷史表中。我們可以從歷史表中推匯出事件和發生的事情。您可以毫無問題地在x綠地(新專案)和棕地(舊專案)中使用它。
  • 這是不容易的。有時您無法訪問參與狀態更改的所有遺留部分。因此,會丟失一些資訊,因為它並不總是一對一的。
  • 但大多數問題,如果你能在遺留端產生一些有意義的事件,然後將它們同步到新的上下文,你將能夠連結這兩個不同的系統,遺留和新上下文。

事件溯源工具
  • 有事件源資料庫。但是您也可以使用具有這種能力的 SQL 資料庫。或者您甚至可以使用一些可以幫助您解決問題的庫將事件儲存在 SQL 關聯式資料庫的表中。所以儲存事件沒有問題。
  • 在您選擇什麼之後,這取決於您的限制。因為您可能會遇到效能問題。您有一分鐘內發生了數百萬個事件,因此您需要一些可靠的東西,有時將其儲存在 SQL 資料庫中並不能解決問題。
  • 說到雙時態,這就是事情變得更加複雜的地方,因為最好的方法是擁有一個雙時態相容的儲存。最重要的是您可以在不同的時間軸上執行不同的查詢。所以肯定的是,我們使用的資料庫或儲存必須符合時態資料庫相關的標準,否則很難做到。
  • 事實上,雙時態資料庫有一個標準,稱為 SQL 2011。

相關文章