1. 程式人生 > >多維擴充套件點的思考與設計——解決渠道、產品增加引發的腐化問題

多維擴充套件點的思考與設計——解決渠道、產品增加引發的腐化問題

隨著業務渠道及產品的增加,你的程式碼是否開始陷入IF-ELSE組成的泥潭,難以脫身?

持續增加的渠道特性

小碼同學一來到新公司,就負責起了一個新開始,但具有無限想象空間的後臺開發專案。就像所有的網際網路專案一樣,業務變化極其迅速,為了減少初期試錯成本,小碼同學選用了流行、便捷的貧血模型,也就是Service+DAO/RPC結構,做了簡單的關注點分離——業務以及基礎設施(儲存/遠端服務)的分離。

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

其實這裡小碼可能會採取另外一種做法,陷入另外一種困境,小碼同學每增加一個渠道就將原來的程式碼複製一份,然後針對渠道進行簡單的修改,然後就可以安全高效地完成業務需求了。然而複製程式碼一時爽,一直複製一直爽,當我們需要修改一些渠道公共實現,理清不同渠道實現的區別並修改時,近十個渠道就會讓我們就變得痛不欲生了。

公用邏輯下沉解決方案

小碼同學想了下,無論多忙都要從這個困境中破局,於是他想出了以下方案:

將公共的邏輯下沉,將各個渠道特有的判斷及邏輯都上提。如此一來我們可以從程式碼中分離渠道和公用業務邏輯——要理解渠道特性,我們可以從渠道所在模組(微服務/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作者,歡迎關注個人公眾號,在這裡我會分享日常工作、生活中對於架構、編碼和業務的思考

相關推薦

擴充套件思考設計——解決渠道產品增加引發腐化問題

隨著業務渠道及產品的增加,你的程式碼是否開始陷入IF-ELSE組成的泥潭,難以脫身? 持續增加的渠道特性 小碼同學一來到新公司,就負責起了一個新開始,但具有無限想象空間的後臺開發專案。就像所有的網際網路專案一樣,業務變化極其迅速,為了減少初期試錯成本,小碼同學選用了流行、便捷的貧血模型,也就是Servic

陣列的定義使用

1、多維陣列 多維陣列可以看成陣列中的陣列,即陣列中儲存的型別為陣列即是多維陣列; 2、多維陣列的定義(以二維陣列為例); 第一種:動態初始化 int[][] arr = new int[3][4];   第二種:靜態建立;不能給定長度 int[][] arr

Tensorflow(1)進行矩陣的拆分拼接

最近在使用tensorflow進行網路訓練的時候,需要提取出別人訓練好的卷積核的部分層的資料。由於tensorflow中的tensor和python中的list不同,無法直接使用加法進行拼接,後來發現一個函式可以完成tensor的拼接。 函式形式如下: tf.concat(concat

通用資料許可權的思考設計

1 資料許可權概述 1.1 什麼是資料許可權? 資料許可權是指對系統使用者進行資料資源可見性的控制,通俗的解釋就是:`符合某條件的使用者只能看到該條件下對應的資料資源`。那麼最簡單的資料許可權大概就是:使用者只能看到自己的資料。而在正式的系統環境中,會有很多更為複雜的資料許可權需求場景,如: 領導需要看到所

MATLAB三圖的繪製(scatter3plot3),同時標明序號

(1)函式scatter3   用法:scatter3(x,y,z,'.',c) % c 為顏色,需和x,y,z長度相同   例子: x=[4229042.63      4230585.02&nbs

資料庫系統原理設計——投影運算選擇運算

書籍:資料庫系統原理與設計(第3版)——萬常選 廖國瓊等編著 資料庫版本:SQL Server 2005 /* select courseNO as 課程號,lower(coursename) 課程名,courseHour/16 as 周課時 from course */ /*  -

MATLAB三圖的繪製(scatter3plot3)

(1)函式scatter3 用法:scatter3(x,y,z,'.',c) % c 為顏色,需和x,y,z長度相同 例子: x=[4229042.63      4230585.02    4231384.96    4231773.63    4233028

opencv3.1.0 特徵檢測影象匹配(features2dxfeatures2d)

特徵檢測與匹配,在物體檢測,視覺跟蹤,三維重建等領域都有廣泛的應用。所以學習features2d、xfeatures2d中函式的使用,很有必要。 1、得到特徵點與特徵點描述(SIFT SURF ORB  AKAZE) (1)SIFT #include <opencv

” 優化——前端高並發策略的更深層思考

經歷 耗時 保護 這樣的 大致 str 頁面請求 本質 target 作者:徐嘉偉,騰訊web前端開發 高級工程師 商業轉載請聯系騰訊WeTest獲得授權,非商業轉載請註明出處。 WeTest 導讀 一項指標的變好,總少不了相應優化策略的實施。優化並不是簡單的一蹴而就

關於數據庫‘狀態’字段設計思考實踐

意義 數量 這樣的 裏的 業務流程 會有 有一個 標準 sql 最近在做訂單及支付相關的系統,在訂單表的設計階段,團隊成員就‘訂單狀態’數據庫字段設計有了一些分歧,網上也有不少關於這方面的思考和探討,結合這些資料和項目的實際情況,擬對一些共性問題進行

Java數組(1):數組數組

soft arr ring 基本 int div 標識 apple 矩陣 我們對數組的基本看法是,你可以創建它們,通過使用整型索引值訪問它們的元素,並且他們的尺寸不能改變。 但是有時候我們需要評估,到底是使用數組還是更加靈活的工具。數組是一個簡單的線性序列,這使得元素訪問非

我的線程—線程設計模式閱讀筆記

圖解java多線程與設計模式 多線程 設計模式 java多線程與設計模式1.Producer-Consumer模式 我來做,你來用 命名生產消費者模式. 生產者和消費者只有一個成為Pipe模式如何解決兩者之間處理速度差異的問題? data

C++ 動態數組的申請釋放

一段 內容 row 像素 這樣的 delet count ros body 今天在實驗室的項目中遇到了一個問題,直接上代碼:    void ViBe::init(Mat img) { imgcol = img.cols; imgr

WPF ViewModel個View綁定後如何解決的問題

如果 dict depend tor 重復 for hashtable hash class 原文:WPF ViewModel與多個View綁定後如何解決的問題當重復創建View並綁定同一個ViewModel後,ViewModel中的字段更新,在新的View中的沒有反應或者

PHP面試(二):程序設計框架基礎知識算法數據結構高並發解決方案類

表設計 工作原理 結構 單一入口 php 能力 高並發解決方案 數據表 缺點 一、程序設計 1、設計功能系統——數據表設計、數據表創建語句、連接數據庫的方式、編碼能力 二、框架基礎知識 1、MVC框架基本原理——原理、常見框架、單一入口的工作原理、模板引擎的理解 2、常見框

【C語言】學習筆記7——指針數組

一個 聲明 %d mage 分享圖片 技術分享 pan 最好 include 1. 聲明一個指向多維數組的指針 int (* pz) [2]; //pz指向一個內涵兩個int類型元素的數組 int * pax[2]; //pax 是一個內含兩個指針元素的

Multi-Model模數據庫引擎設計實現

瓶頸 分享 上傳 實體 單個 協議 schema 選擇 規模 如今,隨著業務“互聯網化”和“智能化”的發展以及架構 “微服務”和“雲化”的發展,應用系統對數據的存儲管理提出了新的標準和要求,數據的多樣性成為了數據庫平臺面臨的一大挑戰,數據庫領域也催生了一種新的主流方向。

apache實現一個域名訪問個服務器問題解決

csdn 文件中 2.4 apache2.2 kill 如果 進行 域名 命令行啟動 1. apache安裝後no service install解決辦法 在在運行中鍵入:cmd ,出來DOS窗口 切換到apache所在目錄的bin文件夾, cd\apache\bin 運

Linux 執行行命令的方法區別(解決supervisor啟動使用GPU的python服務)

在很多情況下,我們需要一次性執行多條命令。比如我在用supervisor啟動python服務的時候就有類似的需求。 對於我的例子背景是通過supervisor監控python在python 35環境下的GPU使用的服務,其中分三個塊:python35環境的需求、GPU服務的使用、服務自動重啟。當

微服務設計的幾思考

接觸微服務也有幾個月時間了,平時斷斷續續的會有一些關於微服務設計的思考,現在做個小結,與大家分享。 先上一張簡單的示意圖 底部是用到的資料儲存設施,中間部分是今天的主角,微服務群,最上面是一個統一入口,閘道器。 微服務應該分為核心微服務和業務微服務 理想的系統應該是小