在探索領域驅動設計主題時,事件和命令之間的差異以及何時應該使用哪些事件和命令?
事件
事件 – 當我們想要傳達某事已發生並且我們並不真正關心誰將收到此通知以及他們將如何處理它時,我們會傳送它。許多訂閱者可以監聽一個事件——一對多的關係。時間是這裡的一個重要方面 - 事件在應用操作後傳送 - 它講述已經發生的事情。
命令
命令 - 這是一個更包裝的請求,我們傳送到特定的(理論上只是技術)服務,以便該服務執行給定的操作 - 一對一的關係。在這種情況下,就時間而言,我們處於執行操作之前。如果傳送命令時出現錯誤 - 尚未發生任何事情,我們可以重複嘗試傳送命令。
看起來很簡單,對吧?
讓我們透過示例來檢查一下
不幸的是,想出 DDD 的例子總是很困難。如果我們從真實系統中獲取這些資料,那麼在不瞭解整個領域的情況下分析它們將會更加困難。因此,這裡仍然使用老掉牙的電子商務或銀行。
使用者操作順序:
- 創造訂單
- 將產品新增到訂單中
- 訂單的稅費計算
- 確認順序
- 訂單支付
在命令的情況下,一切都是同步執行的。使用者建立訂單,將產品新增到訂單中,確認訂單,然後付款。通訊透過佇列進行,給定元件立即收到響應。
對於事件,我們使用具有單獨主題的非同步通訊來進行響應。
在這裡,在輸入通訊 PaymentRequested - Event 和 Tax Calculation Requested - Event 的情況下是否無法用命令替換,我們只會接收事件作為響應。
在這種情況下,我們使用事件還是命令實際上並不重要。直到只有一個元件在監聽!
現實世界的例子
牛仔訂購啤酒,用於比較產品訂購模型中的事件與命令
- [酒吧顧客 -> 女服務員]請來兩杯啤酒[命令]
- [女服務員->調酒師]顧客點了兩瓶啤酒[事件]
- [調酒師 -> 女服務員] 2 瓶啤酒已準備好 [事件]
或者:
- [調酒師 -> 女服務員](透過)給這位先生 2 瓶啤酒 [命令]
- [服務員->顧客] 2瓶啤酒已經準備好了,請拿走[事件]
或者:
- [女服務員 -> 顧客] 這 2 瓶啤酒是給您的,請 [命令]
事件、命令兩者關係是什麼?
- 命令觸發網站上的操作,然後傳送一個事件來傳達操作的應用程式。
- 另一個服務響應此傳送的事件,執行該事件的內部命令以更改服務中的狀態,併為下一個服務生成另一個事件。
傳輸層
我們將研究與事件和命令相關的服務之間的通訊層。對於命令,我們最常使用佇列(Queue),對於事件,我們應該使用釋出/訂閱(Topic)。
當涉及到要使用的特定代理時,大多數都支援佇列和主題這兩種方法:
- IBM MQ
- Apache Kafka
- RabbitMQ
- ActiveMQ
- Amazon SQS (Simple Queue Service)
- Google Cloud Pub/Sub
事件/命令的結構是什麼?
事件和命令之間的另一個重要區別(乍一看並不明顯)是結構的責任。
- 如果是事件,釋出者將決定事件的形式。如果根據定義,他對是否有人會閱讀該事件以及如果是的話,有多少個實體不感興趣,那麼基於同樣的基礎,他是結構的所有者,並決定給定事件應該是什麼樣子。
- 命令的情況並非如此。在這裡,兩個服務之間存在直接通訊,並且由接收者決定他可以接受什麼以及他將處理的命令應該是什麼樣子。
事件與命令相關的非同步/同步
在發現我們在佇列中使用命令和在主題中使用事件之後,我們可以指出另一個區別。
預設情況下,每個命令都是同步的,但每個事件都是非同步的。
儘管實際上沒有什麼可以阻止您透過佇列以非同步方式傳送命令並以非同步方式等待返回佇列上的響應。例如,如果我們預計處理這樣的命令將花費很長時間。