DDD領域驅動設計落地實踐:六步拆解DDD

{"type":"doc","content":[{"type":"heading","attrs":{"align":null,"level":1},"content":[{"type":"text","text":"引言","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"相信通過前面幾篇文章的介紹,大家對於DDD 的相關理論以及實踐的套路有了一定的理解,但是理解DDD理論和實踐手段是一回事,能不能把這些理論知識實際應用到我們實際工作中又是另外一回事,因此本文通過實際的業務分析把之前文章中涉及的理論和手段全部帶着大家走一遍,我想通過這種方式,讓大家實際的感受下DDD落地過程中會遇到哪些問題以及我們應該怎樣去解決這些問題。","attrs":{}}]},{"type":"heading","attrs":{"align":null,"level":1},"content":[{"type":"text","text":"項目需求信息","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"這裏還是大家比較熟悉的電商場景來進行說明,我想這樣大家比較好理解一點。在前段時間雙十一,大家被各種購物優惠券的套路整的眼花繚亂,彷彿數學不好,都不配拿到最優惠的價格了。大家都在吐槽,就不能少點套路,買東西直接給我5折不就天下太平了嗎?我想造成這種現象的原因大概就是中國電商行業的內卷吧,只有通過各種營銷活動的堆積,才能讓大家話更多的時間去瀏覽更過的商品,才能獲得更好的留客以及交易。好了,跑題了,這些我們先不去關心。那我們今天就用這個折磨人的優惠券的流程作爲設計實例來說明整個DDD的落地過程吧。優惠券的關鍵業務流程如下:","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"(1)當需要進行大促活動的時候,運營同學需要選定對應的商品,創建創建優惠券。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"(2)運營同學需要創建營銷活動,制定對應的營銷活動規則,比如什麼滿減啊,跨店減啊類似這種折磨人腦細胞的規則,然後關聯相應的優惠券,最後提交活動審批。審批通過後,進行營銷活動發佈。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"(3)提交活動審批後,審批進行營銷活動審批。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"(4)用戶在營銷頁面領取優惠券之後,下單購買商品之後,在付款的時候根據對應的優惠券進行付費金額計算並完成支付。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/b6/b6afc8351f9643c68eeb24fb19038aed.png","alt":null,"title":"","style":[{"key":"width","value":"100%"},{"key":"bordertype","value":"none"}],"href":"","fromPaste":false,"pastePass":false}},{"type":"heading","attrs":{"align":null,"level":1},"content":[{"type":"text","text":"DDD落地實踐","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"項目背景信息我們大致瞭解之後,那麼我們就要着手開始通過DDD來進行領域驅動設計的過程了。其實我們學習DDD理論以及方法不是最終的目的,而通過它實現實際的業務複雜度治理以及優化微服務設計纔是真正的目的。","attrs":{}}]},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"戰略設計","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"在戰略設計階段,我們最主要的過程大致包括了業務場景分析、領域建模、劃分邊界上下文三個階段。實際上戰略設計師DDD過程中的核心步驟,","attrs":{}}]},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"1、業務分析","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"在這個階段我們所有做的就是進行全面的業務梳理,吧業務中涉及到的所有細節都梳理出來,爲後續進行領域建模分析提供足夠的、全面的業務輸入。經常使用到的業務場景分析方法主要包括用例分析法、事件風暴法以及四色建模法。這裏我們使用事件風暴進行業務場景的分析以及梳理。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"(1)事前準備","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"在進行事件風暴之前我們需要進行一些準備,主要包括貼紙、筆以及討論的會議室,會議室中最好不要有椅子,目的是想讓大家都能夠站立在一起、全神貫注的去進行業務討論。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"(2)邀請參會的人","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"會議的參與方主要包括業務、用戶、PD、研發、測試、架構師等。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"(3)業務討論","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"首先確定我們今天需要討論的業務是什麼,目標是什麼。像前文所說的那樣,本次討論的業務就是營銷活動的優惠券業務,目標就是完成優惠券的業務梳理,確保沒有業務方面的理解gap,在團隊中達成業務理解的的一致性。在這個過程中我們需要通過提問的方式來驅動交流。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"a、分析業務中的事件,搞清楚事件發生的前因後果,什麼意思呢?就是什麼動作會導致當前時間的發生,當前這個事件發生後又會導致怎樣的後果。這些我們都需要梳理清楚。還有一點需要注意, 我不但要關注正常的業務流程還要關注異常的業務流程。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"b、尋找業務邏輯和業務規則,比如我們在提交活動前,需要確定這些優惠券適用哪些人、領取方式是怎樣的以及生效事件是怎樣的等等,這些都是我們在執行操作之前需要確定的業務規則。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"如下圖所示,我們將優惠券的業務流程進行了梳理,分別從操作人、事件、命令的方式來描述整個優惠券業務流轉的過程。","attrs":{}}]},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/7d/7dbf4fafbfbd7f12eb37d931bb71e058.png","alt":null,"title":"","style":[{"key":"width","value":"100%"},{"key":"bordertype","value":"none"}],"href":"","fromPaste":false,"pastePass":false}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"注:在進行事件風暴過程中,所有的參與人都要全身投入整個過程,放下手機以及電腦,一起參與整個業務梳理過程,只有這樣,事件風暴纔可能有比較好的效果。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"2、領域建模","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"在前面的事件風暴業務梳理中,我們已經把優惠券業務涉及到的參與者、動作以及事件等都進行了全面的梳理。那麼接下來我們就要在此基礎之上進行領域建模,這是整個DDD的核心。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"(1)領域對象分析","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"如上面所示的事件風暴小黑板中的內容,我們需要在這些梳理出來的內容中找到對應的實體、值對象以及圍繞這些的領域事件以及命令操作。根據分析,我們總整個業務過程中提取了優惠券、營銷活動、活動審批單、活動規則、審批意見等實體以及值對象以及和這些領域對象相關的命令操作。","attrs":{}}]},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/24/24db2baf4979a36933067b4783414299.png","alt":null,"title":"","style":[{"key":"width","value":"100%"},{"key":"bordertype","value":"none"}],"href":"","fromPaste":false,"pastePass":false}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"(2)構建業務聚合","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"完成領域對象分析之後,我們需要構建業務聚合。想要構建聚合,那麼首先就要在實體中找到聚合根。我們先來回顧下聚合根的特點,聚合根一定是實體,那麼它具有全局唯一的標識,另外它是具備生命週期的同時需要專門的模塊來進行管理。根據這樣的標準,在領域對象中我們發現優惠券、營銷活動以及活動審批單是具備聚合根特徵的,而營銷規則、營銷內容等是和營銷活動緊密相關的,因此他們構成營銷活動聚合關係。優惠券規則、優惠券類型等是和優惠券聚合根緊密相連的,所以他們構成優惠券聚合關係。同理活動審批單也會構成聚合關係。最終我們形成如下的聚合關係。","attrs":{}}]},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/1e/1e9edcec75be03f68f3dcff3f0ac108c.png","alt":null,"title":"","style":[{"key":"width","value":"100%"},{"key":"bordertype","value":"none"}],"href":"","fromPaste":false,"pastePass":false}},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"3、劃分邊界上下文","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"在上述步驟中,我們獲得了整個業務流程中的所有聚合後,我們需要更具業務語義上下文將具體的聚合劃分到對應的上下文中,因此我們可以把優惠券的業務分爲優惠券、營銷活動以及審批三個限界上下文。","attrs":{}}]},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"戰術設計","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"在戰略設計階段,我們通過事件風暴法對整體的業務進行了全部的梳理,同時構建了領域模型以及劃分了邊界下文。那麼接下來我們就要將領域模型映射到工程結構以及代碼中實現最終的實現落地。另外在這個階段實際還有很多細節需要明確,那優惠券來說,它包含哪些屬性,需要哪些領域服務,哪些需要設計爲實體,哪些需要設計爲值對象,這些都是需要在戰術設計階段明確下來。","attrs":{}}]},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"1、微服務拆分","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"我們根據已經劃分的邊界上下文,我們可以拆分爲優惠券服務、營銷活動服務以及審批中心三個微服務,至於用戶支付使用這塊,還是由原先已存在支付服務來完成,只是在付款覈算的時候需要使用到優惠券進行最後的金額計算。","attrs":{}}]},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"2、領域分層","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"在領域分層方面,我們還是按照之前文章中所說的分層結構來進行,即interfaces層、biz層、domain層以及instructure層。每層代表的含義之前的文章中已經進行了詳細的說明,大家可以翻看前面文章中的介紹,這裏不再進行贅述了。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"我們以優惠券爲例,實際聚合中對象還需要進行進一步的細化。對於優惠券來說它實際上還有如下所示的值對象以及實體來組成實際的優惠券。同時在優惠券我們的梳理的領域服務還包括創建優惠券、查詢優惠券以及修改優惠券狀態,這些動作實際都應該在領域層通過領域服務的形式完成落地。而對應的biz層就相當於業務的編排組合,也就是實際的業務流程的串聯。","attrs":{}}]},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/57/57de622503103e991899cbac099aafc3.png","alt":null,"title":"","style":[{"key":"width","value":"100%"},{"key":"bordertype","value":"none"}],"href":"","fromPaste":false,"pastePass":false}},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"3、代碼結構","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"當我們把領域對象進行進一步的細化之後,同時把對應的領域服務敲定之後,我們可以把這些分析後的內容映射成工程分層後的代碼了。如下圖所示,即爲優惠券的domain層的代碼映射。","attrs":{}}]},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/69/6923b709dc574eccd0da65225c7b2dc6.png","alt":null,"title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"當然到這裏並不意味着結束,其實在後續還有很多工作要做,比如詳細設計、編寫代碼以及功能測試,特別實在詳細設計階段,我們還要涉及很多的細節問題的敲定,比如數據庫表的設計、比如使用什麼MQ,用不用緩存,怎麼保證緩存和數據庫的數據一致性問題,分佈式服務有沒有分佈式事務的問題,應該怎麼解決?有沒有服務冪等問題,應該怎麼解決?這些都是需要在詳細設計階段進行確定的。因此DDD就像是框架,通過它把業務映射成爲領域對象以及領域服務和領域事件,再把這些領域相關內容再讀映射爲實際的代碼。使得我們的服務更加的邏輯清晰以及擴展性更強,但是分佈式的技術實現細節,我們還是需要有對應的解決方案來進行解決。","attrs":{}}]},{"type":"heading","attrs":{"align":null,"level":1},"content":[{"type":"text","text":"總結","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"本文以電商行業的營銷活動中的優惠券的發放和使用作爲實際案例來闡述DDD領域驅動設計落地實踐的過程,通過整個過程的梳理,爲大家提煉了整個設計過程的精要,相信大家可以按照這樣的思路在實際的工作中再結合各自的業務特徵應該可以真正完成整個DDD的實踐。萬事開頭難,相信只要大家能夠親自去參與或者主導一個DDD的落地實踐過程,那麼對於理解DDD這套架構設計方法論又會進入一個新的臺階。在後面的文章中再和大家聊聊落地DDD過程中可能會遇到的一些問題以及軟件複雜度治理的問題。","attrs":{}}]}]}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章