剛換了個工作,閑話不說了。前兩天開始一個新項目,大概是一個任務管理系統,由使用者來選取任務,執行任務,反饋完成,我大概做了些設計,本來是打算看能不能在新公司鋪墊一下DDD,不過后來這塊功能沒分到我這,也就沒辦法了。不過如果分到我這,這個設計估計也不能寫博客發了。
具體需求不多說,這個系統很像穿越小說里的佣兵懸賞系統。
發布任務,由被認證為有資格執行的人去搶任務,搶到了任務,去執行任務,完成任務獲得金幣獎勵。
很清晰的幾個階段,狀態遷移,階段之間的交互比較單純,線性的,同時又不需要什么返回值,這幾點上考慮,我首先想到了命令模式。同時沒提到的需求是,任務多是針對一類對象,這類對象在任務執行的流程中經過分析,其狀態與任務狀態雖然不同,但變化幾乎是同步的,有很大一致性,很明顯,非常適合作為一個聚合,任務作為聚合根。確定了命令模式和聚合,作為一個可能會有一定壓力的系統來說,大體上選用CQRS基本上是第一反應了。
首先,用一個序列圖驗證一下思路是否行得通(ExpressParcel指的是任務針對的那類對象):
命令的大致流程都差不多,就不一一貼了,當然不一定是這么多create,大致看上去,是行的通的。
整理下,大概都用哪些對象,哪些命令:
上面是聚合,接收命令的服務和命令的發出角色,下面是命令:
命令的作用其實也很簡單,只是通知狀態變化和積分金幣的變化。另外,還有一塊,只畫了個意思,就不貼了。大概說一下,CQRS的重點是讀寫分離,從這個角度來說,它對性能是比較關注的,命令模式也很適合異步執行,有助於吞吐能力的提升,而為了更進一步的提升,在TaskService接收了命令后,可以不直接執行,而將命令轉為事件消息放入消息隊列,由另外的服務去拉取執行。到這里,非常適合這種架構也是多數這種架構采取的配套方案也就是事件持久化了,補充一句,這里的事件只是一個概念,說明需要發生什么,並不是指.net的event之類的。不過我並沒打算采用事件持久化的方案。
下面說一下我感覺的事件持久化的優缺點,也方便有合適的場景的時候斟酌使用。
優點:可以讓靜態的數據反映出系統曾經發生過的所用動態的變化,彌補了日志的不足,對監控有很大幫助;
使數據庫結構變得簡單,主要部分的基礎結構只有一種,就是事件的結構;
讓程序員可以更專注於邏輯和業務,脫離表驅動造成的數據庫與邏輯的耦合,避免被靜態數據限制動態的業務。
缺點:查詢統計BI等需要另外一套表結構,也就是一份數據需要保存兩種不同的形式;
一旦系統需要重啟,所有事件都需要重演,即使使用快照也不能徹底解決問題,啟動時間長,不利於頻繁的迭代發布;
局部小附加功能的靈活性無法保證,除非系統不使用統一的解決方案。