2017 年 2 月

第 32 卷,第 2 期

本文章是由機器翻譯。

技術最前線 - 內部商業智慧與事件及 CQRS

Dino Esposito | 2017 年 2 月

Dino Esposito我討論幾個框線與客戶最近來驗證商務程序的效率,並建立 UX 小組的整體品質。在系統提供了幾個共用,使用者無法挑選並開始處理工作項目。客戶整體技術的人,但她無法想像的只是表示人員挑選功能和處理的目前狀態的記錄與關聯式資料庫資料表。

不用說,類似的架構會明確地執行此作業。不過,使用不同和以事件為基礎架構時,您可以抓取很多情形系統中的資訊。核心問題,因此,如下所示︰ 可能需要您的客戶,現在或未來 — 存取和使用額外的資訊可以發揮事件嗎?

在本專欄中,我拿起我先前停止的地方在上個月的專欄中,將商務智慧 (BI) 模組加入預訂會議室範例應用程式處理。BI 近來詞彙是很多載的 buzzword 通常與特定技術和產品相關聯。基本上,不過,BI 是指一組技術,抓取,原始的資料轉換成有用的資訊來改善處理程序,或作為只統計的辨識項的分析師。 

藉由加入至應用程式的事件來源,您可以取得原始資料的保留。事件來源和 CQRS 結合您得到正確正規化,這是因為應用程式的核心功能的命令堆疊中儲存的原始商務事件。不過,在任何時間,您可以新增讀取未經處理資料並,轉換其他有意義的資訊區塊,基於任何商業用途,您可能需要的額外模組。

不會錯過的事

說到反白顯示的事件來源的優點,通常所提到的第一個點如下︰ 「 具事件不會錯過在系統中發生的事 」。 無法將 truer,但是它可能需要更多的實用的說明。看看**[圖 1**。

多種規劃可採用原始事件
[圖 1 多個預測可採用原始事件

在建立、 讀取、 更新、 刪除 (CRUD) 系統,您通常有一個資料表示法 — 大部分是關聯式 — 和一或多個簡易投影,大部分的時間只調整表格式資料展示層的需求。使用事件來源,您更進一步,採取這種模型,並降低儲存資料的抽象層級是重要的因素。網域更精確的資訊您儲存、 更豐富和更多投影,您隨時可以建置。

在軟體系統中,使用者的動作是最小的可觀察的行為,這些動作所造成的商務事件是最基本的資訊可以儲存。在上一篇專欄 (msdn.com/magazine/mt790196),我使用 MementoFX framework 透過 NuGet 來無障礙地處理,並將相關的事件保存在網域彙總物件的存留期。我還使用了特殊的同步處理工具 — 稱為 denormalizers — 若要建立每個相關的商務事件之後可檢視的投影。最後,顯示的所有資料行已重新撰寫 CRUD 系統根據事件的命令-傳奇 (ECS) 模式。讓我們看看現在將另一個投影填寫 manager 的儀表板畫面。

朝您自己的 BI 層

在**[圖 2**,您可以看到範例應用程式的主畫面。如前所述,它是共用的資源,例如會議室一組預約系統。

UI 的範例預約系統
[圖 2 範例預約系統的 UI

如圖中,您可以猜得到,允許進入系統的任何使用者會有機會通訊錄的空間,並再移動或取消預定。在傳統的 CRUD 導向系統沒有預約資料表,其中每一筆記錄識別保留項目。當移動保留項目時,會覆寫開始時間和長度,並取消保留時,只是刪除該記錄。在任何時間,記錄的一般查詢會傳回預約的目前狀態。如果您變成一般的 CRUD 歷史 CRUD (請參閱在本專欄和 2016 年 6 月期msdn.com/magazine/mt703431msdn.com/magazine/mt707524分別),您可以追蹤固定的數目的事件,並將它們儲存在某些其他資料表中的任何相關資訊。中的方式,然後,最好事件來源、 MementoFX 為基礎的解決方案透過純簡單的歷史 CRUD 嗎? 關鍵在於程式碼的彈性和最終軟體成品的恢復功能。

MementoFX,與您專注於網域相關的行為和事件。模型解決這些需求的網域物件,並讓其通過。您必須查詢發生了什麼事,在指定的日期和時間,系統的狀態,以及您是否擁有的所有事件或只是原始資料彙總並轉換某些適合某些偶爾的商業用途的自訂方式來記錄的 API。這是原始資料、 預期的意義與人稱之為 BI 的本質。

建置一般事件記錄檔

參考範例應用程式中,您有 RavenDB 資料庫來存放所有未經處理的事件與 SQL Server 的反正規化的表格,其中包含暫止的預約清單。儲存的事件包含建立預約事件所有移到不同的時間,該預約的後續事件和甚至是取消該預約的事件。已取消的事件不會再顯示在主要 UI 中,因此它中繼預約已移至的位置。所有這些事件不相關的建置主要 UI,但重要的管理員或系統管理員建立儀表板 UI。

做為範例,讓我們看看如何將所有的預約系統 (或建立在指定的時間間隔的預約) 中,並顯示每個,整個歷程記錄中所示**[圖 3**。

完整的系統中的事件記錄檔
[圖 3 完整的系統中的事件記錄檔

系統會計算 16 暫止的預約,但每個登記包含一或多個事件。舉例來講,反白顯示的預約第一次建立,再進入兩次,以不同的位置不同的日期。

若要產生類似的畫面,您必須明確地查詢事件存放區中的所有事件,然後算出的它們連線到符合預定的 UI 的圖形。產生的實際檢視 Razor 程式碼會收到此類資料模型︰

public class BookingWithHistory
{
  public BookingWithHistory()
  {
    History = new List<BookingHistory>();
  }
  public BookingSummary Current { get; set; }
  public IList<BookingHistory> History { get; set; }
}

BookingSummary 類別代表給定預約的目前狀態,而是背後的主要檢視類別**[圖 1**。

public class BookingSummary : Dto
{
  public Guid BookingId { get; set; }
  public string DisplayName { get; set; }
  public DateTime Day { get; set; }
  public int StartHour { get; set; }
  public int StartMins { get; set; }
  public int NumberOfSlots { get; set; }
  public BookingReason Reason { get; set; }}

每個 「 建立 」 或 「 移動 」 動作之後,此類別的執行個體會正規化程序期間建立的。這個類別會保存,而且讀取透過 Entity Framework 與傳統的 SQL Server 資料庫。換句話說,這個類別是系統的形成周圍的目前和最新的快照集狀態的預設檢視的項目。技術上來說,這個類別是屬於讀取模型。

檢視您在取得**[圖 3**改為收集資料,也是來自原始事件記錄在事件儲存,在範例中的 RavenDB 存放區。下列程式碼片段會顯示查詢執行針對事件存放區取得具有指定識別碼預約的存留期間發生感興趣的所有事件︰

var createdEvents = EventStore.Find<NewBookingCreatedEvent>(e =>
  e.BookingId == bookingId).ToList();
var movedEvents = EventStore.Find<BookingMovedEvent>(e =>
  e.BookingId == bookingId).ToList();
var deletedEvents = EventStore.Find<BookingCanceledEvent>(e =>
  e.BookingId == bookingId).ToList();

這些事件的聯集提供指定的彙總的完整記錄。重新執行所有這些事件 — 也就套用循序每個事件的狀態彙總物件的新執行個體,傳回目前的狀態物件的顯示或處理程序的用途。不用說,不過,您可以將某個日期篩選條件加入至事件查詢,並因此重建網域物件的狀態 — 預約 — 到指定的日期為止。 

推斷一些商務資訊

例如,假設您是負責內部程序管理員。在您的角色,您會想共用的資源,例如會議室,有效地使用。您要如何確認並據此更新預約原則? [圖 4提供有用的資訊來回答這個問題。

圓形圖會顯示多少預約所建立的時間間隔和多少人已更新移動,或已取消。橫條圖中,而是會中斷上週的相同資訊。在第一個粗略分析似乎幾乎一半的保留項目會在某個時間點移動,甚至是一種每四個取消。

如果您願意改善 manager 處理,在圖形**[圖 4**聽起來可能出現的警示。無論您仔細看的話之後保留項目所做, 的變更數目非常重要。為此防止其他潛在的使用者輕鬆地書籍及其聊天室? 若要停止從響起警示,您可能要查看每個房間相同的時間間隔的平均的涵蓋範圍。如果這個特定的涵蓋範圍圖表還不在您的儀表板,讓開發人員加入它其實不需要很長的工作時數。最後,它幾乎撰寫 LINQ 樣式查詢的另一個述詞︰

var eventsByWeek = bookingStatuses.GroupBy(b => b.WeekDate).ToList();
foreach (var weekEvents in eventsByWeek)
{
  var wr = new WeekActivityReport
  {
    StartOfWeek = weekEvents.Key,
    TotalBookingCreated = weekEvents.Count(),
    TotalBookingMoved = weekEvents.Count(b => b.Moved),
    TotalBookingDeleted = weekEvents.Count(b => b.Deleted)
  };
  reports.Add(wr);
}

在指定的時間間隔內預約動作圖形報表
圖 4 的指定的時間間隔內預約動作圖形的報表

特別的是,範例應用程式取得所有事件中指定的時間間隔內所有的預約,並將它們以週為單位。接下來,它會建立每週的活動報表物件,輕鬆地傳遞至 ChartJS 建立發揮這些超炫的圖形。

我在本專欄中所強調的意思是最重要的部分的事件來源是,原始儲存以最低的可能層級的抽象概念的資訊之後,您可以使用它在許多不同的方式在許多不同的時間。為了示範聊天室的會議,部署在後續版本中的管理員儀表板,或讓另一個全新的產品。您亦可剖析應用程式的存留期間的所有事件,並建立新資料預測其最上層您想得到的任何業務目標。個以上的所有項目,任何後續的開發工作無關大多數的情況下您所擁有並且建置它,不會影響您已在進行中。這是最終任何您在做應用 CQRS 與事件來源組合的投資報酬率。

總結

處理軟體中的商務事件是什麼新玩意兒。您可能可以達到類似的結果,使用歷程記錄的 CRUD (H CRUD) — 只是美觀名稱任何種類的手動的解決方案,可讓您追蹤的商務物件的不同狀態。事件來源會執行相同的工作,差別,在於它在不同的抽象層級運作,且依賴工具 (例如事件存放區) 和模式 (例如,事件來源) 的特製化的架構 (例如 CQRS) 內容中更強大且量身訂做。

我曾撰寫有關 CQRS 與來源的方法,我會構成多數人共識的 CQRS 相關性的概念和現在好一段時間的 MSDN Magazine 中的事件和事件,但發現很難找到中要開始的位置。這些人建議回到 H-CRUD,我寫入有關後的 5 (msdn.com/magazine/mt703431) 和 6 月 (msdn.com/magazine/mt707524),然後再回到有關 ECS 模式 (也稱為 CQRS/ES) 和 MementoFX 較新的文件。應該可以協助您熟悉的心態從開始,並接著漸進式增強高達到達的點,您在其中執行舊的項目,以新的和更強大的方式。

這稱為軟體不是魔法或宗教相關。軟體是完成工作,最好可為客戶和開發小組的方式。事件存放區匯流排,事件模式和架構,以及 MementoFX 有助於需要快速且有效地完成工作。


Dino Esposito是每個 「 Microsoft.NET:  架構的企業應用程式 」 (Microsoft Press,2014年) 和 [使用 ASP.NET 最新 Web 應用程式] (Microsoft Press,2016年)。.NET 和 Android 平台在 JetBrains,並在世界各地的產業活動的技術推廣人員 Esposito 分享軟體的願景software2cents.wordpress.com和 Twitter: @despos

感謝下列 Microsoft 技術專家來檢閱這份文件︰ Andrea Saltarello