M*N個策略造成類爆炸怎樣重構?

語言: CN / TW / HK

背景

收到朋友針對他們遇到的具體問題寫一篇文章的邀請,問題是這樣的

朋友:

我們公司對接了M個三方服務  然後還有N種業務  實現用策略的話感覺有點類爆炸  也想不到什麼好方法了  這也是早上剛接到一個重構支付的需求想到的   根據業務和供應商搞了太多策略實現了[暈]

我:

初步感覺應該用打造接入平臺的方式解決

朋友:

開始的時候沒有考慮到  程式碼一言難盡了 [捂臉]  謝謝謝老師

我從對話中分解出下面幾個問題

1、理解重構、重寫和重新架構

2、怎樣做重構?

3、重構過程與業務支撐之間怎樣平衡?

下面我針對這三個問題展開論述。

理解重構、重寫和重新架構

重構是對程式碼和功能進行 漸進式改進 ;重寫是 要摧毀它,重新構建;重新架構在大框架上做修改和再設計,具體每個實現模組可能是用原來的。

舉個例子,搭積木。重構就是我用積木搭建了一個小馬,發現小馬某些部分不好看,我就把幾塊積木調整調整,讓小馬更好看;重寫就是我用積木搭建了一個小馬,發現自己搭建好了完全不喜歡,把積木推到了重新搭,既然是重新搭,搭好的東西和原來差距有多大就不好說了;重新架構就是我用積木搭建了一個小馬,發現自己其實想要個小橋,沒有必要全部推到重做,而是可以先畫好設計圖,然後直接把小馬的四條腿拆下來做橋墩,脊背部分做一部分橋面,實在不能用的再拆下來重安裝。

重構是小步跑的過程,如果對外提供的功能沒有變化,這是穩妥的方法;重寫往往伴隨著功能上的升級,不然對於“我不知道這段程式碼是幹什麼用的但我不敢刪”這種事情很難保證對外提供的功能沒有變化。

重構和重寫與修改量沒有直接關係。有個哲學問題叫做“特修斯之船”,是說一艘船持續的在海上航行,船不斷有部分老化或者壞掉進行替換,最終整艘船的所有部分都換過一遍,這時候船還是原來那艘船嗎?

所以咱們不再糾結概念,統一用重構這個詞,聚焦於怎麼解決問題。

怎樣做重構

首先需要對系統進行一個生命週期預估,包括:

  • 未來需求預判

  • 模組劃分拆解

  • 總結歷史問題

朋友說:“開始的時候沒有考慮到  程式碼一言難盡了 ,其實大可不必這樣想。架構和程式碼 不是設計出來的,是演進出來的。如果一開始要我做,一段時間之後,也很可能會遇到相同覺得非重構不可的情況。雖然我一定會做未來需求預判,但是現實往往會出現很多例外情況,讓程式充滿了妥協。

那針對朋友遇到的問題,怎麼設計更合理呢?

支付重構

如果只是重構支付部分,我個人覺得相對容易。因為支付需要的要素比較好抽象,主要是下游支付渠道需要什麼。自從有了網聯,現在對接方也比較固定了。直接接網聯或者微信支付、支付寶支付、拉卡拉…… 他們所需要的要素都差不多。因為它們都要接入網聯完成國家監管的需求,所以要素主要看網聯需要哪些要素。

當然,它們的簽名方式可能會不同;呼叫的支付渠道地址不同;給支付渠道傳遞的時候入參組裝方式也不同。甚至有的支付渠道還需要有特殊的步驟。這時候怎麼抽象呢?

推薦“工作流”+策略模式。這是一種實現積木化的方式。定義一個統一介面,比如

class Executor {

void execute(Task task);

}

task裡放置所有的入參,以及每次執行時產生的,下游需要的中間資料。簽名等流程各自實現此介面。這樣就實現了自由組裝的重用。

舉個例子,下面 積木塊”各自實現了自己的execute:

微信支付簽名、微信支付入參組裝、微信支付結果解析、支付寶 支付 名、支付寶 支付 入參組裝 、支付寶 支付結果解析、 支付寶特殊處理、下游http呼叫(這裡假設微信和支付寶都是http的post請求來呼叫的,這樣發起呼叫來說兩者只是請求地址和入參不同)

這時候可以組裝微信支付流程:

List list = new List();

list.put(微信支付簽名);

lis t. put ( 信支付入參組裝 ) ;

lis t. put (下游http呼叫 ) ;

lis t. put ( 信支付結果解析 ) ;

for(Executor e :list) {

e.execute(task);

}

同樣可以組裝支付寶支付流程:

List list = new List();

list.put( 付寶 支付簽名);

lis t. put ( 付寶 支付入參組裝 ) ;

lis t. put (下游http呼叫 ) ;

lis t. put ( 付寶 支付結果解析 ) ;

lis t. put ( 付寶 支付特殊處理 ) ;

for(Executor e :list) {

e.execute(task);

}

不同的流程只是list不同,這個list是可以時間配置化的,可以配置在配置檔案中、甚至可以從資料庫中讀取。微信支付流程和支付寶支付流程是兩種不同的策略,可以使用策略模式。入參選擇哪種策略就用哪種策略執行。這樣,各個流程之間沒有干擾,積木塊變更影響小還可以隨意組合靈活性高。

整體重構

朋友的業務複雜性還不在於支付,而在於收單。解決方法就是文章開頭提到的接入平臺的方式。打造平臺的關鍵不是技術,而是規範。 自己制定規範。 別人接入 都要按照規範來

這裡有前提:公司自身的影響力。平臺是底層自己需要有決策權,比如微信開放平臺,想接入就要理解並使用他們的API。而因為微信基礎在,必須按照人家說的來,這就是平臺影響力。

在實際工作中,一般有兩種情況。接入方自身也沒有什麼規範,本身就要求功能可用,這時候咱們自身有規範,對方比較容易接受。另外一種,對方是實力背景的大公司,也有自己的規範。這時候咱們處於弱勢,要按照別人的規範來,可以使用上面支付重構的積木化方法進行進行組合。

重構過程與業務支撐之間怎樣平衡?

在重構過程中一般會遇到兩頂思考帽問題:一頂是需求的帽子,一頂是重構的帽子。有限的時間怎麼分配呢?建議一開始就定好目標:什麼階段要重構到什麼程度,然後分解工作。最後分攤到每天比如需要2小時時間。那麼在需求開發時間評估的時候就要把這個時間扣掉。

重構做完,老邏輯遷移到新邏輯有風險。這時候我的建議是:

首先,把新功能當成重構結果的驗金石。有新功能,先在新功能上驗證新邏輯的正確性。因為新功能上線到上量有一個過程,初期出了問題影響也不會很大。

然後,老邏輯遷移需要灰度。可以一個業務一個業務的灰度遷移,也可以按照流量百分比進行遷移。

總結

最後總結一下對重構的幾點建議:

1、小步快跑,穩步迭代

2、設計與程式碼的重構結伴而行

3、如果模組或者函式不能想到一個好名字,很可能是設計出了問題

4、每步要保證足夠簡單,想象隨時可能會停止