系統整容紀:責任鏈設計模式的應用實戰(爆燈了,研發工期由45天降爲1天)

本文通過介紹使用責任鏈設計模式的背景和經歷,來使得讀者加深對於此設計模式的印象,甚至受到一定的啓發來對自己當下所參與、所負責的項目進行“整容”,從而提升系統的“美感”。分享工作中的點點滴滴。

一、背景

在下所負責的系統中有這麼一個模塊,分區模塊,直接看這個詞的話相信很多人都會疑惑甚至是誤解,其實其真正的含義就是“路由”,接下來我簡單描述一下何謂“路由”。

相信大家都有過網上購物的經驗,每當我們下完訂單後,我們都能隨時隨地的查看訂單的物流跟蹤狀態,而上述的“路由”概念就是指:訂單從A地到B地的運輸路由線路,例如訂單order1要從A運輸到目的地F,其可以從A->B->D->F,也可以從A->D->F,至於具體應該走哪條線路,是靠系統中配置的路由以及對應的匹配規則進行篩選出來的。

很長的一段時間裏,系統裏的路由配置和規則都是靜態的(所謂靜態就是提前配置好並且幾乎是固定不變的),這種做法的弊端很明顯,就是成本無法控制,就如同上述所講的例子,運輸路線明明有機會可以減少甚至是可以直送(A地到F地的貨物明明可以裝滿N車,卻也不得不按照系統中制定的路線進行運輸),但是卻被系統中定死的路由規則所限只能多走一些道路,提高了人力作業和運輸的成本。

基於此有位大牛發現了降本增效的商機:就是讓這塊路由線路和規則動起來,使得系統能夠更靈活的兼容上述情況,達到資源的極限利用,舉個例子:比如有很多訂單都是從A要送達目的地F的,系統中靜態線路配置的只有A->B->D->F,但是經過系統監測計算發現從A到F的貨物量可以裝滿兩車,那此時爲這些訂單臨時生成一條新的線路從A直達F,同時在A場地進行收貨、發貨等凡是涉及到路由線路匹配的實操環節時,均兼容上此臨時路由的場景,這樣就能在不改變用戶習慣的情況下將整體成本給降下來,並且運輸到目的地的效率也得到了大大的提高。

這位大牛提出的方案很好,得到了大家的廣泛認可和好評,於是在立項後進入了轟轟烈烈的開發階段,而在下有幸被委以重任來主導完成此項目的開發交付。

值得一提的是,路由線路這塊的改動貫穿了訂單的整個實操流程以及一些邊邊角角的輔助查詢、統計報表等功能,場景涉及衆多,所以壓力還是蠻大的,雖然期間也確實走了不少彎路,但最終的結果是好的,甚至在之後的又來了幾個類似變動路由線路的需求,但是基於此次改造後,我們這邊都能進行輕鬆應對,這個在文章後續的效果中會體現一下。

說了這麼一大堆,有沒有覺得其實都是廢話的感覺,哈哈,確實有點囉嗦,接下來讓我們來夢迴路由,再現一下整個稀碎而又有成就感的改造過程。

二、思路和方法

後續文章中提到的分區是爲路由匹配規則的含義

首先來看一張簡易的實操流程示意圖



 

 

在每個場地的實際操作的作業流程中都會涉及到分區匹配規則的情況,同時在一些輔助實操作業的查詢功能或報表功能中也會涉及到路由匹配規則,所以一旦分區匹配規則要做變動,那麼就會面臨如下痛點

首先在業務層面上就會幾乎貫穿整個流程,無論是評估、開發、測試等環節都會面臨工作量巨大的問題
再次從系統層面上來看,這部分的代碼現狀也非常不友好,主要體現在:
分區匹配核心業務規則一致,但是代碼寫法不一,並且分佈散亂,讓人難以閱讀與維護,同時伴隨場景遺漏的風險
分區匹配功能目前都是各個實例自行編寫並且耦合在各個使用場景中,不具備擴展性,一旦規則變化,改動成本非常高

基於上述痛點,在下決定下定決心將此模塊進行重構整治一番,一來通過此次挑戰來提高自我、二來也爲以後此塊規則再次變更的可能做好鋪墊,那麼具體應該怎麼做才能解決上述所提到的痛點呢?我是這麼做的

1. 業務層面上做好充分的評估:體現在開發的詳細設計上(這裏由於在下對於業務規則非常熟,所以算是是本人的優勢拉哈哈),像場景梳理啊、修改方案、甚至在設計中下沉到了具體功能(按鈕點擊啊、錄入框輸入後的回車觸發啊等等這些細節)的修改邏輯方案以及代碼位置,以便讓所有參與開發人員以此爲指導手冊進行快速開發,測試人員以此爲指導進行用例編寫、產品人員以此爲字典加深其自身對於此塊業務的理解等等。聽起來是不是很牛X,哇哈哈,這裏有點吹噓拉,本文中不着重介紹這裏,主要介紹設計模式哈,咱們緩緩繼續往下看
2. 這裏是我們的重頭戲哈,系統層面上主要體現在代碼上,畢竟說的再好,落實不到代碼,看不到效果都是白搭嘛,何況咱又是職位,好了,廢話不多說,繼續看我表演哈哈
首先將分區匹配核心模塊進行統一的收口,在系統中只保留一個實例進行服務提供,既能解決代碼分散維護成本高的問題、又能避免場景遺漏的風險

看到這裏或許會有人說,你這個會不會帶來另外一個問題啊:雖然場景不會遺漏了,達到了一處代碼變動,處處場景都會生效,但是會不會改動了某些場景原有的功能特性?能想到這裏的同學,確實很細心哈,如果是硬性收口的話的確是會產生這個新問題,所以統一收口這塊一定要支持擴展,預留好鉤子便於支持各個場景的差異化處理。這麼說比較抽象,舉個例子:比如通用場景規則是所有單子都按照系統既定配置的分區規則進行運輸,但是現在有一些商家開通了一些快速送到目的地的服務,那對於這些商家的單子就不能用現有的通用規則進行分區匹配運輸了,要按照新的規則進行分區匹配從而達到快速運輸的目的。這就是裏邊的差異化。

複用現有的數據結構,增加分區類型,並調整對應的sql和service服務(這裏不是本篇重點就不展開講了),在兼容現有生產邏輯的基礎上支持分區規則的擴展
結合設計模式的思想調整分區匹配規則的代碼結構:採用責任鏈模式(這裏是本篇文章的重點內容)

那麼到底什麼是責任鏈模式呢?

大牛給出的定義:使多個對象都有機會處理請求,從而避免了請求的發送者和接受者之間的耦合關係。將這些對象連成一條鏈,並沿着這條鏈傳遞該請求,直到有對象處理它爲止。

結合着現有系統的實際業務來講講我是如何進行套用的:開篇背景中已經介紹過現有的分區匹配規則爲靜態分區匹配(如某某業務點到點、某某業務點到範圍區域等等,具體業務細則就不展開講了,只要知道這裏邊的匹配規則一大堆即可),現在要新增一種規則支持動態(也是各種匹配,就不展開講了),這裏我把每一種分區規則都定義爲一種分區類型,而每一個分區類型都定義爲一個分區節點,將這些節點穿成一條鏈,讓每個請求都在這條鏈中找到匹配自己的線路進行運輸。

由於業務細則比較敏感,文章中就不具體透露了,不影響重點設計模式的應用理解

結合定義以及上述分析,那麼實際情況到底適不適合使用責任鏈設計模式呢?在下認爲只要能夠解決上述痛點並且總體的利大於弊,那麼就是適用的。首先使用此模式改造後的優點如下:

將請求和處理分開了(從與業務實操的耦合中解脫出來,完全不用關心請求是怎麼來的,只專注於分區規則的匹配)
提高了系統的靈活性和擴展性(再有新的規則,只需要增加節點即可)

當然了,此模式也有一定的缺點:當責任鏈比較長的時候,由於每個請求都會遍歷整個鏈條,可能會有性能的問題,同時對於不理解業務的同學調試起來也會感覺比較複雜。

整體看下來,優點是解決了我們當下的痛點,並且利於後續的擴展,而缺點中的性能部分可通過結合模板模式中預留的鉤子函數(如果當下請求不適合於當下分區節點規則則跳過)拉最大限度的降低性能問題的影響,同時基於開發人員瞭解業務也是應當的。那這樣看來總體還是利大於弊的。

說了這麼多我們先來看看改造前後的分區模塊的簡單對比示意圖吧



 

 

雖然圖非常簡陋,但是其對比含義還是很明顯的,改造前:分區匹配和業務處理是耦合在一塊的;改造後:分區匹配是一條鏈並且裏邊沒有業務邏輯處理,從耦合中解脫了出來,也支持擴展。看到這裏會有人疑惑:上文中不是說只新增了一個動態匹配規則嗎,怎麼鏈中有這麼多節點,而且還是兩條鏈。這裏我稍作解釋下:當下的兩條鏈是經歷過許多需求版本變更的,當下看起來區別已是不大,主要是因爲其提供的來源業務指定場景不同抽象出來的兩條鏈,互不干擾各自運行,而裏邊多處本文介紹的那些節點也是後來新增的,直至當下還在系統中使用的節點規則(這也就是文章開篇我提的:萬一後邊還有規則變更呢。果然還是機智如我,“預言”應驗了,在效果中我會講出這裏支持擴展對於縮短工期的重要性)

三、實踐過程

相信有不少讀者會發現,上面又是說統一收口、又是說結合模板模式最大程度規避性能影響,那你這個責任鏈一種設計模式是支持不了的吧。

沒錯,你說對了,大聰明,確實只是使用單一的責任鏈設計模式遠遠達不到上文中所說的效果,這裏我們也確實將工廠、模板、責任鏈模式進行了結合使用,工廠用來獲取鏈條的bean,模板用來設置通用方法、方法間的調用以及預留給子類實現的開關、前後置處理、差異化等方法,責任鏈用來組合各個節點,這裏簡單抽幾個節點將類圖展示出來如下



 

 

這段就比較簡單了,畢竟就是擼碼,上面的類圖幾乎代碼中的實踐應用了,也是代碼中的核心部分,而在實際調用中均是通過工廠來獲取bean鏈條進行具體分區匹配的。

四、對實踐過程的思考和對效果的評價

改造過後的成果主要體現在後續的擴展和維護,就如文章開篇提到的一旦分區匹配規則要做變動就會面臨兩個痛點,最直接的體現就是在工期上面,第一次接此塊的變動新增路由規則需求時,整體實際用的工期就研發側來說是45天,就更別說一旦遇到BUG,那測試工期也就沒保障了(對應上圖節點中的動態節點)



 

 

但是後來沒多久就又再次增加匹配規則的新需求(對應上圖節點中的到倉拼車節點),同類的需求,工期縮短近半,優45天降低到了27天,這裏還包括此需求中的其他非分區模塊的改造,當然了第一版的改造確實有些完美的地方,經過這次需求由進行了優化



 

 

接下來的這兩個就真正體現到了什麼叫做工期消失術,一個是首板分區規則需求,一個是最近B網融合需求中的直髮分區規則

直髮分區工期2天
首板分區工期就1天

說實話,我在沒回看這些數據的時候也沒想到有這麼大的效果,現在回頭一看我也是驚呆了,誰能想到一個設計模式的應用竟能將工期由45天縮短至了1天,這太不可思議了。

當然了其中也還有一些可以改進升級的地方,目前責任鏈節點的裝配都是手動指定的,可改動爲自動裝配(我在另個業務場景中的改造中已經實現過了,這裏也會進行同步改造),再有一個就是要控制節點的數量,如果數量過大則可能需要考慮兼容方案了。

俗話說滴水穿石非一日之功,冰凍三尺非一日之寒,追求強大的工具、新穎的技術固然可行,但是也不要忘了日常工作中的一點一滴的小改動,短時之間可能看不出什麼,一旦量變引起了質變,我相信那結果將是非常可觀亮眼的。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章