人壽保險銷售平臺的領域驅動設計和事件風暴案例分享 -James Hickey
幾年前,我領導了一個線上銷售人壽保險新平臺的網路開發。我們將介紹以下幾點:
- 事件風暴:這是什麼以及如何開始對業務域進行建模
- 從領域事件的角度思考系統或業務域如何真正幫助澄清問題
- 人壽保險業務可能面臨的一些重要問題
- 如何更好地處理與外部系統/ API的互動
- 某些分散式模式如何改善系統的使用者體驗
什麼是事件風暴?
事件風暴是通常用來發現和了解業務運作方式的研討會。您邀請所有利益相關者,並用便籤紙表明領域事件中了發生什麼,他們可能會導致什麼樣的影響或其他流程。
我還發現事件衝動甚至在較小規模和團隊討論或設計討論中也很有用。
過去的設計概述
該系統旨在讓(a)主要保險提供商和(b)第三方保險提供商允許其客戶線上申請人壽保險。它是可配置的,因為第三方提供商可以選擇將包括通用申請流程的哪些部分,入口點在哪裡以及其他自定義項。
當第三方提供商處理應用程式時,流程如下所示:
- 從第三方提供商的客戶填寫的初始表單中接受一些HTTP POST資料。
- 使用者繼續填寫線上人壽保險應用程式(分多個步驟)。
- 首先,一般聯絡資訊。
- 接下來,有關受益人的資訊等
- 然後,一份醫療問卷。
- 等等。
一切都在一個龐大的程式碼庫中完成。所有的Web UI和業務邏輯都在一起。
這種方法的一些問題是:
- 缺乏程式碼質量
- 可維護性方面的困難
- 缺乏業務流程的程式碼結構記錄
- 長時間執行的同步HTTP POST可能會超時並導致處理錯誤
- 和更多...
探索我們的領域
讓我們開始根據域中發生的事件來檢視業務流,以概述我們正在處理的內容。
請記住,這不是對所有域事件的詳盡瞭解,而是非常簡化的外觀:
ApplicationStarted、PersonalInformationProviede、MedicalQuestionsProvided、ApplicationCompleted
之所以將PersonalInformationProvided視為域事件,是因為發生了其他響應。
例如,保險公司堅持要求系統傳送帶有令牌的電子郵件,以便建議的被保險人(即申請人)可以在以後的日期恢復其申請。
MedicalQuestionsProvided可能會導致申請人喪失資格,所選保險產品失去資格,在整個剩餘表格中啟用完全不同的路徑,等等。
進入下一步:
如您所見,這是使事情變得有趣的地方。
在BankingInfoProvided之後,系統將遠端呼叫保險公司的“特殊” API,該API將檢視過去的申請人歷史記錄,銀行歷史記錄,病歷等,並做出決定。該決定是通過相同的HTTP POST返回。
在某些情況下,申請的被保險人必須在以後的日期進行身體檢查。在此之前,他們的申請一直處於待處理狀態。
如果申請通過(ApplicationAccepted),則將建立保險單(PolicyCreated)。否則失敗,這意味著沒有任何Policy被建立。
首次支付保單(FirstPolicyPaymentRecieved)後,該保單將“啟用”。如果在前30天(或任意持續時間)內未啟用Policy,則該策略將立即被取消。
有界上下文
在現有系統的設計中,沒有邊界上下文的概念。一切都儲存在一個龐大的XML檔案中(是的……我們在過時的行業中必須處理的事情)。我們知道我們需要對此進行拆分。應該怎麼辦?
重要事件
“關鍵事件”是最重要的事件,因為它們是領域內重大變化的驅動力。
在這種情況下,最重要的事件是PolicyCreated。這是申請正式轉變為真實保險單的時候。這就是使用者首先想要的最終目標。
有趣的是,這也是面向使用者的Web應用程式結束之處,並是後端辦公系統的保險Policy開始之處。
子域
另一個有趣的領域(除非您熟悉該行業,否則您可能不會意識到)醫療問卷非常複雜。根據您回答某些問題的方式,可能會發生許多不同的事情。
圍繞此特定領域的程式碼和業務邏輯是一個熱點。
由於該領域包含的複雜性,我有興趣將這個領域作為一個子域進行研究,並將其視為有界的上下文。
子域與有界上下文不同。子域仍然是與業務相關的部分,而有限的上下文是關於我們的軟體所具有的邊界。但是,很多時候它們確實匹配-尤其是在建模開始時,就像我們在做的那樣。但是,如果業務結構發生變化,則子域可能會發生變化(隨業務變化),而繫結的上下文仍會烘焙到軟體中。
從業務的角度來看,這裡MedicalQuestionsProvided絕對是關鍵事件。它是申請被保險人是否有資格獲得保險或有資格獲得其他“額外”保險附加產品的主要驅動力。(在現有系統中,系統的這一部分最難構建和維護!)
這是有限上下文的主要概念的亮點-您可以在特定區域或複雜的問題空間周圍劃分邊界,並使該複雜性保持隔離狀態。沒有人需要知道它是如何工作的。它只需要知道調查表的末尾會發生什麼。
請記住,儘管我們不能隨心所欲地建立有界上下文。在這種情況下,我們確定了(目前看來)一個關鍵事件。
語言
同樣,如果我們與領域專家深入研究,我們會發現在醫學問題中使用的(普遍存在的)語言是非常特定於醫學問卷的。
例如,在這種情況下,當談到申請人時,是指他們的健康狀況,身體健康狀況等。
這是在整個域中唯一使用此語言的有關申請人的地方。
子域之間的過渡
您會注意到,資料流是從一個上下文流到另一個上下文,然後又返回到同一上下文。而通常,在典型的DDD示例中,您會看到資料從一個上下文流到另一個上下文,並且該流再也不會返回原始上下文。
我的直覺是,這些複雜的子域在某些總體業務流程或其他父域中間散佈,在現實世界域中很常見。
樸素API Calls和 Saga比較
現有系統的主要問題之一是,它將直接從Web應用程式釋出HTTP POST到保險提供商的“特殊” API,該API會批准或拒絕該應用程式。
同樣,這很容易導致出現以下問題:
- 由於網路問題導致HTTP超時
- 端點關閉時的錯誤
- 該請求花費的時間太長且超時...
由於這是一個白標產品,我們無法控制該API的效能和可用性。
為了更清晰地概括,這裡是所需的步驟(準系統):
- 提交應用程式(通過HTTP POST)
- 等待...
- 確保重試錯誤...
- 如果外部系統從不響應,則中止
- 如果確實響應,則將結果提供給使用者
這種長時間執行的作業/流程通常最好使用saga模式來完成。
處理這些型別的長時間執行的作業時,其他考慮因素可能是路由單模式或流程管理器模式 -兩者均與saga模式相似。
使用saga模式,我大致會想到以下內容:
這看起來要複雜得多,但是請耐心等待一下。
請注意,BankingInfoProvided事件將不會啟動HTTP POST這種“簡單明瞭”的提交資訊方式,而是將啟動一個長期執行的後臺作業。具體來說,啟動的是ApplicationSubmissionSaga。
這個Saga有兩個處理程式:
[list=1]
為什麼?這給了我們什麼?
彈性系統
在原始設計中(直接HTTP POST)-如果外部API 甚至沒有執行怎麼辦?
哦...
我猜該使用者不走運。他們甚至無法提交他們的申請...
如果使用saga模式會發生這種情況怎麼辦?
Saga流程將失敗,然後進入睡眠狀態並稍後重試(因為它是後臺程式)。如果外部系統第二天恢復正常,那麼Saga將成功提交申請並繼續!
注意:此重試過程在上圖中由上的橙色齒輪指示SubmitApplicationForApprovalStep。
這種處理分散式事務或長時間執行的業務流程的方法(即使您不擁有外部API)也可以幫助您構建可能會失敗並且預期會失敗的系統。
對UX的影響
讓我們根據對UX的影響來比較這兩種設計。是的,建模上的差異極大地影響了使用者體驗。
採用原始的原始設計,如果外部系統出現故障,則使用者將無法完成其應用程式。因此...使用者將不得不稍後返回該網站並“重試!”
使用Saga這種模式的地方就在這裡:使用者將“完成”他/她的應用程式,我們將告訴他們:“一旦我們處理完您的應用程式,您將在接下來的24小時內收到一封電子郵件。”
使用者回家,並最終在不久的將來的某個時間收到一封電子郵件,告訴他們他們需要了解的所有資訊。
但是,如果外部系統現在關閉了怎麼辦?
使用者不知道。他們走了。我們對系統進行了設計,使我們不需要使用者與外部API進行通訊並處理故障。
使用者的體驗是什麼?
太棒了
這意味著巨大的意義。這是易於使用與那些煩人且難以使用的系統之間的差異。
這會影響保險公司的品牌和聲譽。
正確建模域的重要性
這回到了很好地建模域的想法。這都是建模。我們還沒有編寫任何程式碼,但是從概念上講,我們可以知道兩種設計都會發生什麼。
這就是為什麼對於想要成功併為使用者提供最佳體驗的公司聘請擅長對此類業務領域和流程進行建模的開發人員和工程師的原因。
從字面上看,這可能是公司成功與失敗之間的區別!
這是為什麼要學習作為開發人員/工程師使用這些工具建模的重要性的一種觀點。
問題!商業利益相關者不同意
利益相關者希望保持網站能夠將結果立即顯示給客戶,他們不喜歡這一事實:使用者現在網站上無法及時獲得申請狀態的反饋。
我們的新設計意味著應用程式批准/拒絕的結果現在是一個後臺過程-與我們的Web應用程式斷開了連線。以下是你可能已經想到了一個解決方案:在Web應用程式也可以訂閱ApplicationAccepted,ApplicationDenied和ApplicationPending事件,並使用網路套接字(使用SignalR等),以“推”的結果返回給使用者的瀏覽器。
這甚至可能包括顯示瀏覽器通知(即使我們都討厭它們)?
無論哪種方式,這都是滿足我們到目前為止所有要求的一種方式。
結論
在這個領域上,以上看起來有些原始。還有更多的東西。
希望您確實學到了一些有關建模業務流程的知識。有時候,僅通過更改我們在業務流程中處理步驟的方式,我們就能產生巨大的影響!
相關文章
- 領域驅動設計中的聚合是什麼? - James Hickey
- DDD領域驅動設計:領域事件事件
- 領域驅動設計戰術模式--領域事件模式事件
- 戲說領域驅動設計(廿五)——領域事件事件
- 結合領域事件和微服務的實現領域驅動設計 - Alagarsamy事件微服務
- 領域驅動設計:CQRS 和事件源的強大功能事件
- 事件風暴與領域故事的比較事件
- 聊一聊中臺和DDD(領域驅動設計)
- 領域驅動設計(DDD)實踐之路(二):事件驅動與CQRS事件
- 領域驅動設計,中臺與微服務微服務
- 事件風暴 - 分解問題領域的最佳實踐事件
- 領域驅動設計示例
- MasaFramework -- 領域驅動設計Framework
- 理解領域驅動設計
- JavaScript中的領域驅動設計JavaScript
- 實現領域驅動設計
- 領域驅動設計核心概念
- 領域驅動設計簡介
- 再談領域驅動設計
- DDD領域驅動設計pdf
- 整潔的領域驅動設計 - George
- 問題驅動設計與領域驅動設計的區別 - abdullin
- 領域驅動設計戰術模式--領域服務模式
- 戲說領域驅動設計(廿一)——領域服務
- 前端開發-領域驅動設計前端
- DDD-領域驅動設計示例
- 淺談DDD(領域驅動設計)
- 淺談 DDD 領域驅動設計
- 何時使用領域驅動設計
- 微服務領域驅動設計 - semaphoreci微服務
- DDD領域驅動設計:倉儲
- 戲說領域驅動設計(五)——子域
- 《實現領域驅動設計》筆記——領域、子域和限界上下文筆記
- 事件驅動的微服務-事件驅動設計事件微服務
- “親切照料”下的領域驅動設計
- 領域驅動設計的概念解釋 -DEVdev
- 領域驅動設計對依賴的控制
- 領域驅動設計的DDD與ddd - nick