自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

降低復(fù)雜度提升效率,DDD在攜程用車/租車訂單系統(tǒng)重構(gòu)中的實(shí)踐

系統(tǒng) 新聞
本文描述了兩車如何利用DDD(Domain-driven Design,領(lǐng)域驅(qū)動(dòng)設(shè)計(jì))方法論降低系統(tǒng)復(fù)雜度以及在重構(gòu)歷史系統(tǒng)中的取舍和思考。

隨著歷史業(yè)務(wù)不斷迭代和業(yè)務(wù)場(chǎng)景越來越復(fù)雜,攜程用車、租車(簡(jiǎn)稱兩車)面臨歷史技術(shù)債和系統(tǒng)復(fù)雜度越來越高帶來的理解、維護(hù)、迭代困難等問題,我們開始尋求如何更有效的降低復(fù)雜度和提升效率的方法。

本文描述了兩車如何利用DDD(Domain-driven Design,領(lǐng)域驅(qū)動(dòng)設(shè)計(jì))方法論降低系統(tǒng)復(fù)雜度以及在重構(gòu)歷史系統(tǒng)中的取舍和思考。對(duì)于復(fù)雜業(yè)務(wù)場(chǎng)景下的領(lǐng)域驅(qū)動(dòng)設(shè)計(jì)具有借鑒意義。

一、案例介紹

攜程用車訂單相關(guān)業(yè)務(wù)包括接送機(jī)、包車、打車這些產(chǎn)線,訂單相關(guān)的功能包括訂單狀態(tài)管理、支付狀態(tài)管理、供應(yīng)商訂單狀態(tài)管理、履約狀態(tài)管理,其中履約狀態(tài)中包含司機(jī)相關(guān)狀態(tài),完成訂單需要將額外費(fèi)用結(jié)清。

攜程租車訂單相關(guān)功能包括訂單狀態(tài)管理、支付狀態(tài)管理、押金扣款記錄、供應(yīng)商訂單狀態(tài)管理、履約狀態(tài)管理,其中履約狀態(tài)主要是取車和還車相關(guān)狀態(tài)。

訂單和相關(guān)實(shí)體如下圖所示:

圖片

二、問題分析

由于兩車業(yè)務(wù)存在一些差異,為了讀者更容易理解,因此將抽取共性問題來說明。

2.1 溝通困難

關(guān)于溝通困難,我們發(fā)現(xiàn)整個(gè)開發(fā)過程中,溝通實(shí)際上是一個(gè)非常消耗時(shí)間的事情,需求方需要和產(chǎn)品溝通,產(chǎn)品要和研發(fā)人員溝通,研發(fā)開發(fā)過程中發(fā)現(xiàn)一些忽略的細(xì)節(jié)需要產(chǎn)品確認(rèn),來回之間耗費(fèi)了大量時(shí)間。如果是跨團(tuán)隊(duì)溝通,這樣的問題會(huì)更加復(fù)雜,以下總結(jié)了一些常見的場(chǎng)景:

  • 產(chǎn)品不關(guān)心研發(fā)的實(shí)現(xiàn),但是覺得需求很簡(jiǎn)單或者很復(fù)雜。
  • 研發(fā)開發(fā)過程中發(fā)現(xiàn)一些忽略的細(xì)節(jié)需要產(chǎn)品確認(rèn),產(chǎn)品要找需求方確認(rèn)。
  • 歷史邏輯沒人知道,需求評(píng)審的時(shí)候無法發(fā)現(xiàn)問題,做到最后發(fā)現(xiàn)有問題。
  • 跨團(tuán)隊(duì)之間不了解對(duì)方的業(yè)務(wù),需要反復(fù)溝通確認(rèn)。
  • 遇到同一個(gè)名詞不同的理解導(dǎo)致無效溝通。
  • 一個(gè)需求到底該哪個(gè)域來實(shí)現(xiàn)是我們?cè)趯?shí)踐中經(jīng)常反復(fù)探討的問題。
  • ...

例如訂單和供應(yīng)商訂單在不同的團(tuán)隊(duì)內(nèi)都叫訂單,在溝通中針對(duì)“訂單”的討論就會(huì)產(chǎn)生歧義。

2.2 業(yè)務(wù)邊界不清晰

設(shè)計(jì)之初,訂單被各調(diào)用方當(dāng)作了對(duì)外輸出的數(shù)據(jù)源頭,數(shù)據(jù)需求方只要調(diào)訂單詳情即可獲取全量數(shù)據(jù),這為以后訂單的迭代帶來了相當(dāng)大的隱患。訂單在自己的業(yè)務(wù)模型中加入大量不涉及自身業(yè)務(wù)的冗余字段,在系統(tǒng)的演進(jìn)過程中,由于無腦插入他方業(yè)務(wù)字段使得訂單自己也要維護(hù)相關(guān)的邏輯(解釋和修改),導(dǎo)致各方對(duì)訂單的耦合日益加深,導(dǎo)致訂單服務(wù)的發(fā)布變成高風(fēng)險(xiǎn)行為,甚至一個(gè)無關(guān)訂單業(yè)務(wù)的相關(guān)字段修改也可能導(dǎo)致系統(tǒng)故障。

例如訂單上關(guān)于供應(yīng)商的相關(guān)數(shù)據(jù),用戶訂單有一份,采購(gòu)訂單也有一份,當(dāng)采購(gòu)要修改供應(yīng)商的相關(guān)邏輯時(shí)要用戶訂單也一起修改,而用戶訂單必須排查和推動(dòng)相關(guān)使用到這個(gè)字段的業(yè)務(wù)方切換替代方案。

圖片

2.3 面對(duì)業(yè)務(wù)變化修改困難

隨著歷史業(yè)務(wù)迭代,訂單中耦合了許多非訂單關(guān)注的業(yè)務(wù)邏輯。例如歷史上給用戶發(fā)消息通知是根據(jù)用戶訂單狀態(tài)變化觸發(fā)的,由于和通知平臺(tái)交互,因此訂單要提供通知相關(guān)的所有參數(shù),等于訂單依賴通知相關(guān)的模版,明顯存在核心依賴非核心的問題。而此時(shí)如果我們提出需求,要對(duì)于某些通知平臺(tái)發(fā)送失敗的消息進(jìn)行重發(fā),邏輯似乎也只能做到訂單上,不論怎么看都很不優(yōu)雅。

圖片

三、解決方案

3.1 回歸業(yè)務(wù)本質(zhì)——挖掘愿景

為了解決業(yè)務(wù)歸屬問題和明確系統(tǒng)發(fā)展方向,避免將資源投入那些非核心的功能,我們需要明確當(dāng)前項(xiàng)目它是什么,目標(biāo)是什么。因此我們需要為系統(tǒng)準(zhǔn)備一份愿景,它將指導(dǎo)我們?cè)谖磥淼牡胁幻允Х较颉_@個(gè)愿景相當(dāng)于我們的產(chǎn)品定位,是我們的系統(tǒng)和其它系統(tǒng)不同之處,也是當(dāng)前系統(tǒng)的邊界。

圖片

愿景就像手電筒中發(fā)出的光,在光暗之間是我們系統(tǒng)的邊界,系統(tǒng)的未來也在光的方向中。

輸出一個(gè)愿景說明有很多方式,為了簡(jiǎn)化落地的門檻,我們采取麥肯錫“電梯演講”的方式,圍繞機(jī)會(huì)、挑戰(zhàn)、優(yōu)勢(shì)、劣勢(shì)給出一組結(jié)果,由領(lǐng)域?qū)<液烷_發(fā)團(tuán)隊(duì)一起進(jìn)行頭腦風(fēng)暴,實(shí)際上這也是DDD統(tǒng)一語言的開始,我們必須從愿景開始就達(dá)成一致。

圖片

友情提醒

Eric Even在他的書中曾提到過一種模式:領(lǐng)域愿景描述(Domain Vision Statement)

“由于一開始項(xiàng)目的模型通常不存在,但是需求是早已定下的重點(diǎn),為了我們?cè)诤罄m(xù)階段清楚了解系統(tǒng)的價(jià)值,以價(jià)值作為我們的導(dǎo)向?!?/span>

我們?cè)谘芯款I(lǐng)域愿景描述時(shí)發(fā)現(xiàn)要寫出一份合格的文檔并不容易,因?yàn)樗狈γ鞔_的規(guī)范和套路,Eric也只是給了我們幾個(gè)案例體會(huì),不得不說雖然寫出來容易,但是要做到合格還是有門檻的。因此我們退一步,回到Eric說的愿景說明來:“很多項(xiàng)目團(tuán)隊(duì)都會(huì)編寫‘愿景說明’以便管理。最好的愿景說明會(huì)展示出應(yīng)用程序?yàn)榻M織帶來的具體價(jià)值?!?/span>

3.2 高效溝通——利用事件風(fēng)暴統(tǒng)一語言

圖片

說到統(tǒng)一語言,最經(jīng)典的例子應(yīng)該是傳話游戲,一句話從最初的人口中說出,經(jīng)歷中間多人轉(zhuǎn)述,最后可能完全變成另一種意思。

為了快速實(shí)現(xiàn)統(tǒng)一語言,我們?cè)谟唵沃貥?gòu)中花了比較多的時(shí)間進(jìn)行事件風(fēng)暴。事件風(fēng)暴有以下幾點(diǎn)優(yōu)勢(shì):

  • 事件風(fēng)暴圍繞業(yè)務(wù)流程進(jìn)行討論,使在場(chǎng)的每一個(gè)人都通過多條流程深入了解業(yè)務(wù)實(shí)體的變化。
  • 事件風(fēng)暴聚集了“領(lǐng)域?qū)<摇?,產(chǎn)品、開發(fā)、測(cè)試等,本質(zhì)也是一場(chǎng)集合集體智慧的頭腦風(fēng)暴,所有人在事件風(fēng)暴中達(dá)成業(yè)務(wù)共識(shí)。
  • 事件風(fēng)暴集合了所有人的領(lǐng)域知識(shí),同樣是一場(chǎng)領(lǐng)域知識(shí)的分享會(huì)。

圖片

原本事件風(fēng)暴是以工作坊的方式在線下組織,這樣大家的參與感更強(qiáng)烈。但是由于成本和線上辦公的興起,我們?cè)谠诰€工作坊的實(shí)踐會(huì)更多一些。這里推薦兩個(gè)工具,一個(gè)是行知蜂(BeeArt),另一個(gè)是可畫(canva),都支持多人在線協(xié)作。

事件風(fēng)暴其實(shí)非常簡(jiǎn)單,就是業(yè)務(wù)流程+業(yè)務(wù)用例,將業(yè)務(wù)流程橫向展開,通過用例將業(yè)務(wù)中的名詞狀態(tài)變化一一列舉。其中色塊的大小和顏色可以參考www.eventstorming.com,但是我認(rèn)為只要能夠統(tǒng)一大家的認(rèn)知,顏色是次要的。

經(jīng)過我們的嘗試,先列舉業(yè)務(wù)中單據(jù)的狀態(tài)變化,后補(bǔ)全觸發(fā)狀態(tài)變化的動(dòng)作和角色效率會(huì)更高一些。關(guān)鍵是將大家認(rèn)知中的不同事物相同名詞、不同名詞相同事物識(shí)別出來,利于后續(xù)建模。

通過事件風(fēng)暴,我們主要關(guān)注以下幾種情況:

  • 溝通中那些脫離當(dāng)前領(lǐng)域就難以理解的詞匯;
  • 相同名詞,含義不同的;
  • 名詞不同,含義相同的。

將以上三種情況涉及的名詞動(dòng)詞總結(jié)成統(tǒng)一語言表,特別是第三種情況恰恰是我們劃分限界上下文的關(guān)鍵依據(jù)。例如我們?cè)诹闹Ц秵螘r(shí)發(fā)現(xiàn)存在兩種支付單,一個(gè)是包含我們業(yè)務(wù)的支付單,它需要記錄當(dāng)前支付的場(chǎng)景并包含一定的業(yè)務(wù)規(guī)則;另一個(gè)是支付平臺(tái)的支付單,每次支付都會(huì)生成一個(gè)支付單,它可以認(rèn)為是和更抽象的訂單相關(guān)(例如會(huì)員訂單、優(yōu)惠券訂單)。

于是我們提取了費(fèi)項(xiàng)記錄這個(gè)概念,表達(dá)一筆訂單可以有多個(gè)費(fèi)項(xiàng)記錄,用于區(qū)分我們的支付

單和支付中臺(tái)的支付單之間的差別。

3.3 自上而下細(xì)化邊界——子域劃分

傳統(tǒng)面向過程的開發(fā)方法面對(duì)復(fù)雜系統(tǒng)通常會(huì)采用DFD數(shù)據(jù)流圖的方式進(jìn)行拆分,在DDD中則是提出了子域的概念。我們總是會(huì)聽到領(lǐng)域(Domain)和子域(Sub Domain),不論是Eric的DDD還是IDDD中都大量使用這些概念,但是我們會(huì)發(fā)現(xiàn)他們并未向我們解釋清楚子域是如何劃分而來的。

對(duì)于一個(gè)已有的系統(tǒng)而言,我們可以根據(jù)康威定律得出:團(tuán)隊(duì)邊界=系統(tǒng)邊界,因此可以認(rèn)為每個(gè)團(tuán)隊(duì)負(fù)責(zé)的部分就是天然的子域。由于目前訂單團(tuán)隊(duì)本就分為用戶訂單組和采購(gòu)派發(fā)組,因此我們可以初步得出一個(gè)領(lǐng)域劃分:

圖片

此時(shí)我們根據(jù)愿景,可以明確兩個(gè)子域各自的職責(zé):用戶訂單子域負(fù)責(zé)提供用戶訂單流程的查看和管理,并且負(fù)責(zé)在需要的環(huán)節(jié)主動(dòng)通知用戶;采購(gòu)訂單子域則負(fù)責(zé)真正定后履約流程的流轉(zhuǎn),包括供應(yīng)商和行前行中行后的狀態(tài)更新。

最后支付使用的是攜程金融的能力,由于支付平臺(tái)的能力在攜程內(nèi)部是統(tǒng)一的,因此我們認(rèn)為支付平臺(tái)屬于通用域。

3.4 自下而上抽象概念——限界上下文

領(lǐng)域的概念相對(duì)而言還是模糊的,因此Eric提出了DDD中最重要的概念:限界上下文。而限界上下文并非憑空而來,而是需要對(duì)我們?cè)谑录L(fēng)暴中得到的名詞進(jìn)行歸納而來。

圖片

首先我們列舉了用戶訂單域的各種用例,包括下用戶單、支付訂單、修改訂單、取消訂單等。

通過建模法歸納模型,例如在訂單流程中我們存在多場(chǎng)景的支付,同時(shí)又依賴支付平臺(tái)的支付單,因此我們得到了維護(hù)支付單狀態(tài)的支付費(fèi)項(xiàng)記錄,它既維護(hù)了支付單相關(guān)的信息,也維護(hù)了當(dāng)前訂單系統(tǒng)內(nèi)關(guān)于支付的業(yè)務(wù)邏輯。

最后我們根據(jù)業(yè)務(wù)相關(guān)性對(duì)得出的實(shí)體進(jìn)行歸納,結(jié)合我們的愿景得出三個(gè)上下文,分別是:

  • 用戶訂單狀態(tài)上下文:負(fù)責(zé)管理用戶訂單狀態(tài)管理;
  • 支付費(fèi)項(xiàng)上下文:負(fù)責(zé)訂單支付相關(guān)狀態(tài)管理;
  • 用戶通知上下文:負(fù)責(zé)對(duì)用戶進(jìn)行多種方式的通知。

圖片

3.5 挖掘業(yè)務(wù)變化的瓶頸——上下文依賴關(guān)系

實(shí)際上限界上下文可以拆到很細(xì)的粒度,但是我們應(yīng)該遵循“奧康姆剃刀”的規(guī)則,盡量設(shè)置合理的數(shù)量,拆分的要有理有據(jù)。我們可以先看看原來的系統(tǒng)上下文依賴關(guān)系:

圖片

根據(jù)Eric對(duì)上下文關(guān)系的總結(jié),我們可以得出消息中心作為攜程的消息中臺(tái),不會(huì)為了某個(gè)業(yè)務(wù)線做特殊邏輯,因此是很明顯的遵奉者(Conformist)。此時(shí)消息相關(guān)的處理耦合在訂單內(nèi)部,如果發(fā)送消息沒有業(yè)務(wù)邏輯那么采取防腐層(ACL)的方式是比較常見的。

由于我們已經(jīng)識(shí)別到用戶通知存在業(yè)務(wù)邏輯,因此訂單直接和消息中心交互顯得奇怪,而且訂單作為核心域,本來就應(yīng)該盡量不依賴其它域,對(duì)此我們進(jìn)行了如下設(shè)計(jì):

圖片

這樣用戶訂單上下文更加內(nèi)聚,而用戶通知也更加易于迭代。

四、收益總結(jié)

4.1 業(yè)務(wù)邏輯耦合降低

通過上下文拆分和職責(zé)的明確,由各領(lǐng)域維護(hù)自己的數(shù)據(jù)和領(lǐng)域知識(shí),使得訂單不再維護(hù)這些字段,而由數(shù)據(jù)寫入的業(yè)務(wù)方去維護(hù),后續(xù)有和訂單無關(guān)的業(yè)務(wù)邏輯變更時(shí)訂單無需改動(dòng)。

4.2 團(tuán)隊(duì)效率提高

隨著上下文拆分和康威定律的應(yīng)用,各團(tuán)隊(duì)職責(zé)和各自的領(lǐng)域形成映射,過去由于團(tuán)隊(duì)職責(zé)劃分不清,經(jīng)常為某功能誰做來爭(zhēng)論不休的問題也得到了解決。

4.3 性能和穩(wěn)定性提高

通過上下文拆分后,訂單實(shí)體從之前的780多個(gè)字段簡(jiǎn)化到200多個(gè)字段,大大降低了訂單的維護(hù)成本,存儲(chǔ)數(shù)據(jù)量減少,原來的業(yè)務(wù)邏輯也由每個(gè)寫入方自己進(jìn)行維護(hù),接口性能p95 寫由68ms優(yōu)化到12ms ,讀從63ms降低到5ms。

4.4 數(shù)據(jù)一致性

由于過去業(yè)務(wù)方寫入數(shù)據(jù)到訂單可能由于網(wǎng)絡(luò)抖動(dòng)等原因?qū)懭胧』驑I(yè)務(wù)方寫錯(cuò)數(shù)據(jù)導(dǎo)致修復(fù)數(shù)據(jù)需要兩邊一起改,現(xiàn)在業(yè)務(wù)方將數(shù)據(jù)存放在自己的領(lǐng)域內(nèi),不再存入訂單,避免了數(shù)據(jù)不一致和字段寫錯(cuò)等問題的產(chǎn)生。

4.5 人力成本大幅下降

產(chǎn)研溝通涉及的相關(guān)方大量減少,鏈路縮短。刨去原本因?yàn)闃I(yè)務(wù)邏輯耦合導(dǎo)致訂單跟著修改的人力成本,整體人力成本小項(xiàng)目下降70%,大項(xiàng)目更是下降80%。

五、遇到的問題和方案探索

落地DDD實(shí)際上是一個(gè)非常困難的過程,我們必須面對(duì)缺乏領(lǐng)域?qū)<遥瑯I(yè)務(wù)需求多且急,團(tuán)隊(duì)對(duì)DDD理解不深等諸多問題。對(duì)此我們總結(jié)出以下幾點(diǎn)經(jīng)驗(yàn):

5.1 領(lǐng)域?qū)<译y尋

領(lǐng)域?qū)<沂荄DD中最重要的角色之一,沒有領(lǐng)域?qū)<椅覀兙蜔o法獲取知識(shí),就沒有后續(xù)的建模等等。但是實(shí)際工作中要尋找一個(gè)嚴(yán)格意義上的領(lǐng)域?qū)<沂抢щy且成本高昂的,因此我們需要尋求一些其它方式曲線救國(guó),例如該領(lǐng)域的資深研發(fā),資深QA等,同時(shí)我們兩車還采取互相借鑒的方式,雖然業(yè)務(wù)不完全相同,但是領(lǐng)域上也有互通之處。

5.2 業(yè)務(wù)需求多且急

實(shí)際工作中我們經(jīng)常忙于各種業(yè)務(wù)項(xiàng)目,關(guān)鍵是還很急。這就很容易導(dǎo)致我們沒辦法專注于DDD改造,怎么辦呢?我們的方案是在有時(shí)間的時(shí)候把方向定下來,提前進(jìn)行設(shè)計(jì),然后在做業(yè)務(wù)項(xiàng)目時(shí)將這些設(shè)計(jì)逐步進(jìn)行實(shí)現(xiàn)。

5.3 團(tuán)隊(duì)對(duì)DDD理解不深

為了提高團(tuán)隊(duì)對(duì)DDD的理解,我們專門成立了DDD培訓(xùn)小組,將我們的一些落地經(jīng)驗(yàn)整理成規(guī)范和最佳實(shí)踐。同時(shí)在落地時(shí)由培訓(xùn)小組的同學(xué)進(jìn)行把關(guān),避免大家走彎路。

以上就是此次分享的全部?jī)?nèi)容,如果后續(xù)大家有什么疑問可以在下方留言,如果后續(xù)有機(jī)會(huì)我們會(huì)在疑惑較多的點(diǎn)進(jìn)行再次分享。希望大家通過這篇文章得到一些想要的收獲!

責(zé)任編輯:張燕妮 來源: 攜程技術(shù)
相關(guān)推薦

2020-06-01 08:42:11

JavaScript重構(gòu)函數(shù)

2020-12-30 09:20:27

代碼

2024-03-08 14:43:03

攜程技術(shù)系統(tǒng)

2023-10-05 11:08:53

2022-06-03 08:58:24

APP攜程流暢度

2024-06-05 09:35:00

2023-08-25 09:51:21

前端開發(fā)

2022-09-03 21:13:19

攜程供應(yīng)商直連平臺(tái)

2011-06-07 10:30:54

2024-07-30 10:55:25

2014-12-24 10:45:05

攜程

2023-07-07 12:26:39

攜程開發(fā)

2023-03-14 14:01:00

內(nèi)存優(yōu)化

2025-01-26 10:10:30

2022-12-14 10:09:44

研發(fā)效能

2019-11-18 12:41:35

算法Python計(jì)算復(fù)雜性理論

2022-02-23 11:49:25

自動(dòng)化云基礎(chǔ)設(shè)施

2024-04-25 08:33:25

算法時(shí)間復(fù)雜度空間復(fù)雜度

2022-04-07 17:30:31

Flutter攜程火車票渲染

2024-07-05 15:05:00

點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)