多維擴展點的思考與設計——解決渠道、產品增長引起的腐化問題

隨着業務渠道及產品的增長,你的代碼是否開始陷入IF-ELSE組成的泥潭,難以脫身?git

持續增長的渠道特性

小碼同窗一來到新公司,就負責起了一個新開始,但具備無限想象空間的後臺開發項目。就像全部的互聯網項目同樣,業務變化極其迅速,爲了減小初期試錯成本,小碼同窗選用了流行、便捷的貧血模型,也就是Service+DAO/RPC結構,作了簡單的關注點分離——業務以及基礎設施(存儲/遠程服務)的分離。github

業務很給力,主要流程模式已逐漸成型,同時也增長了不少的營銷渠道,有公司內部的 App、有公衆號、小程序、H5,也有各種外部的合做夥伴的渠道,小碼同窗一直都在高負荷地工做着,徹底來不及思考要怎麼優雅地解決這些渠道增長帶來的問題。然而,每一個渠道會有一個渠道相關的小特性,這意味着在 登陸、註冊、作業務等等各個Service裏,每增長一個渠道時,都要增長一段關於渠道判斷的IF-ELSE判斷語句。量變引發質變,當渠道加到近十個時,小碼懵逼了,理清代碼邏輯脈絡變得極爲困難,由於看一遍代碼,須要將要受到近十個不一樣渠道分支代碼的干擾。同時代碼也變得難以並行開發,多個渠道的拓展會由於同一個Service的修改而更容易發生衝突。
小程序

其實這裏小碼可能會採起另一種作法,陷入另一種困境,小碼同窗每增長一個渠道就將原來的代碼複製一份,而後針對渠道進行簡單的修改,而後就能夠安全高效地完成業務需求了。然而複製代碼一時爽,一直複製一直爽,當咱們須要修改一些渠道公共實現,理清不一樣渠道實現的區別並修改時,近十個渠道就會讓咱們就變得痛不欲生了。
segmentfault

公用邏輯下沉解決方案

小碼同窗想了下,不管多忙都要從這個困境中破局,因而他想出瞭如下方案:
安全

將公共的邏輯下沉,將各個渠道特有的判斷及邏輯都上提。如此一來咱們能夠從代碼中分離渠道和公用業務邏輯——要理解渠道特性,咱們能夠從渠道所在模塊(微服務/package/service)的代碼得知,若是要理解通用的信息,則到公共
業務邏輯層查看對應的實現。架構

但若要使用本解決方案解決目前系統的問題,則須要引入大量的重構,由於該實現須要將大量已有存在的渠道邏輯變動其發生的邏輯時間點,這須要大量的開發及測試人力支持。框架

擴展點解決方案

因而小碼同窗開始在網上搜索相關的解決方案,瞭解到阿里有個能夠解決相似問題的框架實現COLA,並以此爲參考開展了本身的擴展點設計微服務

https://github.com/alibaba/COLA

其引入了一種名爲 擴展點/插件 的機制(擴展點是一個Interface,擴展點實現爲interface的一個特定實現),讓咱們能夠達到如下效果:測試

要實現這個效果,強制咱們把相關業務語義顯式化,例如 通用業務邏輯Service在沒有引入擴展點前,寫的校驗身份的代碼爲編碼

if(is渠道B) {
    渠道B的一大堆代碼進行身份校驗
} else {
    默認實現的一大堆代碼進行身份校驗
}

而引入擴展點後,在通用業務邏輯Service寫的則是

校驗身份擴展點.執行校驗();

其顯式化了業務語義,並像 公用邏輯下沉 的解決方案同樣 分離了主幹的代碼邏輯和特定實現的代碼邏輯,還能保證原有特定渠道邏輯執行的相對位置不變。

在擴展點機制的支持下咱們只須要定下規範——在通用業務邏輯層不能出現任何關於Channel渠道的IF-ELSE判斷,這樣就可收穫大量有基礎抽象的通用業務邏輯代碼,提升識別基礎抽象的能力。

擴展點解決方案的本質

擴展點本質上就是個帶有自動路由功能的策略模式,其根據業務上下文信息,自動推斷出應該選用哪一個具體的擴展點實現。

擴展點的機制和原理簡單,使用也很簡單,但其給業務系統代碼帶來倒是變革性的。

多維擴展問題的出現

小碼同窗利用擴展點已經阻止了渠道增長帶來的代碼腐化加重問題,小碼以保守起見:

  • 對於沒有任何業務變化的代碼保持不變
  • 對於新增的渠道使用擴展點來防止代碼進一步腐化
  • 對於存在業務變更的代碼,在測試資源的支持下,利用擴展點重構原有代碼,令代碼變得新鮮

但新的問題出現了,項目中也有一個與渠道相似的,會不斷擴展實現的概念——產品。

在小碼的系統中,每增長一個產品也是按照相似先前增長渠道的形式,以IF-ELSE完成擴展。因而,小碼但願直接套用以前的擴展點機制,然而事情並無這麼順利。

在上一幅圖中,contextCode爲

companyY.channelB

其表徵的是渠道維度的身份信息,咱們以該信息爲依據,來匹配最適合的渠道相關的實現。與此相似,咱們須要引入產品維度的身份信息,同時也要將不一樣維度的contextCode加以區分,然而COLA的實現中並不支持此類多維擴展實現,因而小碼開始設計了本身的ConextCode及ImplementCode規範,增長了維度標識符:

channel:companyY.channelB
product:companyY.ProductO.subProductE

經過維度標誌,小碼分開了不一樣維度的擴展點以及其對應的實現,解決了大部分的問題。

多維擴展點衝突問題

引入多維擴展點後,大多數擴展實現都在各自的維度良好運行,井水不犯河水。然而,有少數擴展點卻出現了須要多維同時決定實現的場景,如:

當前如果渠道A且是產品X的狀況下須要使用特定的擴展實現。

目前基於維度隔離的擴展點感受沒法支持此類需求,因而,小碼繼續查找相關資料,瞭解到了阿里TMF2.0框架的實現:

https://segmentfault.com/a/1190000012541958

TMF2.0按文中介紹,其爲一個二維的擴展點實現,這兩維分別是:

  • 行業維度
    • 一個行業維度的代碼即爲TMF2.0的業務身份
    • 其等價於小碼以前設計的沒帶維度標誌的contextCode
  • 產品維度
    • 與本文中的產品設定徹底不一樣,請勿套入理解

與小碼以前設計的維度隔離擴展點不一樣,TMF2.0中行業維度與產品維度會共享擴展點,然而當出現擴展點衝突時,TMF2.0會以業務身份爲線索,經過可視化界面配置特定業務身份在遇到擴展實現衝突時應該選擇哪個擴展實現,並將其固化成配置,運行時依據配置選擇最終擴展實現。

然而該設定並不符合項目的現狀,相關UI的開發設計也是一個巨大的工程,所以小碼設計了另一種折中的設定:

  • 擴展點依然按維度隔離
  • 當出現擴展點路由須要多維信息決策時,採用嵌套形式
  • 不一樣擴展點不一樣維度的嵌套的次序,都按照固定的次序進行

以下圖所示

這個設定的實現雖然繁瑣,可是實際狀況下,出現多維共同干預擴展實現選擇的狀況應該相對少,相對於擴展點維度隔離獲得的好處,其應該能夠接受。

舒心的小碼

擴展點的理論簡單易用,其使得

  • 業務主流程代碼擁有基礎抽象,使得脈絡清晰明瞭
  • 各個渠道、產品的特性高度內聚於各自的package中
  • 業務主流程成熟後,新增的產品、渠道不再須要動業務主流程代碼,只需增長新的渠道包及產品包
    • 業務主流程代碼沒變更,減小了全局風險,減小了測試量
    • 擴展只涉及對應的渠道、產品的增長,這自然隔離了不一樣開發組的工做,提升了並行度

今後小碼和他的小夥伴們今後擺脫了996,與基友們過上了幸福快樂的生活。

做者簡介

多年金融行業經驗,現爲某Top2互聯網銀行高級搬磚工,曾在兩家TOP3股份制商業銀行及一家互金創業公司工做(架構、核心業務主程),EasyTransaction做者,歡迎關注我的公衆號,在這裏我會分享平常工做、生活中對於架構、編碼和業務的思考

相關文章
相關標籤/搜索