微信支付的跨平臺架構到底有多牛?

程式設計師的成長之路發表於2020-03-25

程式設計師的成長之路
網際網路/程式設計師/成長/職場 


閱讀本文大概需要 10 分鐘。

來自:方秋

背景

作為一個重要業務,微信支付在客戶端上面臨著各種問題。其中最核心問題就是分平臺實現導致的問題:
  1. iOS 和安卓實現不一致

  • 容易出 Bug

  • 透過溝通保證不了質量

  • 擴充套件性差,無法快速響應業務需求

    • 需求變更迭代週期長

    • 資料上報不全面

  • 質量保障體系不完善

    • 缺少業務及設計知識沉澱

    • 協議管理鬆散

    • 缺少統一的自動化測試

  • 使用者體驗不一致

    比如下圖就是之前安卓和 iOS 沒有統一前的收銀臺。


    微信支付的跨平臺架構到底有多牛?

  • 為了解決分平臺實現這個核心問題,並解決以往的技術債務。我們建立起了一整套基於 C++ 的跨平臺框架,並對核心支付流程進行了重構。
    微信支付跨平臺從 iOS 7.0.4 版本起, 安卓從 7.0.7 版本起全面覆蓋。


    線上效果指標

    以 iOS 上線情況為例:
    1. Crash 率

      上線前後 Crash 率保持平穩,沒有影響微信穩定性,跨平臺支付無必現 Crash,做到了使用者無感知切換。

      舉個例子,大家可以用微信發一筆紅包,拉起的收銀臺和支付流程就是由基於C++編寫的跨平臺程式碼所驅動的。

    2. 效能提升

      微信支付的跨平臺架構到底有多牛?

      以核心支付流程程式碼為例,跨平臺需要 3512 行,iOS 原生需要 6328 行。減少了近 45% 的程式碼。

      以新需求開發為例:

      7.0.4 版本需求一:收銀臺改版

      7.0.4 版本需求二:簡化版本收銀臺

    • 跨平臺實現:iOS + 安卓 共計 3 人日,在封板時間前完成

    • 原生實現:iOS, 安卓封板時間後一週才基本完成

    • 跨平臺實現:iOS + 安卓共計 5 人日,在封板時間前完成

    • 原生實現:iOS, 安卓封板時間後一週才基本完成


    那麼支付跨平臺軟體架構怎麼樣有效進行質量保障,並且提升生產力呢?這是這篇文章的主要內容。
    微信支付的跨平臺架構到底有多牛?
    對基於 C++ 如何從零到一構建跨平臺框架感興趣的同學,可以在 %E5%9F%BA%E4%BA%8E%20C%2B%2B%20%E6%9E%84%E5%BB%BA%E5%BE%AE%E4%BF%A1%E5%AE%A2%E6%88%B7%E7%AB%AF%E8%B7%A8%E5%B9%B3%E5%8F%B0%E5%BC%80%E5%8F%91%E6%A1%86%E6%9E%B6.key 下載我在 2019 QCon 廣州站的演講 《基於 C++ 構建微信客戶端跨平臺開發框架》的 Keynote.

    什麼是軟體架構

    什麼是軟體架構?正如 Ivar Jacobson (UML 之父)說過的一樣,找五個人來回答這個問題,五個人可能都有各自不同的答案。
    架構定義可以有很多種說法,從程式碼規範到釋出流程都可以是架構的一部分。
    針對微信支付的業務特點,這裡對架構的定義是:架構是系統的組成部件及其之間的相互關係(通訊方式)。這更符合我們程式設計師日常編寫業務程式碼時對架構的理解。也就是通俗意義上講的 MVCMVVM 等。

    為什麼需要軟體架構

    早在 1986 年的時候,人月神話的作者在討論軟體的複雜性時,談到:軟體的本質複雜性存在於複雜的業務需求中。
    而管理複雜性,最根本的手段就是職責分離。為了實現職責分離,程式碼重用,架構慢慢地復現出來。架構的本質是管理複雜性。
    沒有架構,我們所有的程式碼都耦合在一起,人類的心智模型不擅長處理這種複雜性,架構的設立,和圖書館的圖書分類,公司的組織劃分等,本質都是一樣的。是為了管理複雜性,以取得更高的生產力。


    從零到一構建支付跨平臺軟體架構

    在移動客戶端領域,業界基於 C++ 來編寫業務程式碼,並沒有成熟的架構。即使使用 C++ 編寫業務邏輯,但都不涉及 UI,不涉及介面的跳轉流程。
    既然業界沒有一個成熟的架構可借鑑,那麼是不是直接把業界通用的架構簡單套用一下就好?

    1. 抽象業務流程

    現在業界通用的有 MVC , MVP, MVVM 。這些大家都熟悉的軟體架構。但是這些軟體架構都存在一個問題: 那就是沒有處理好業務流程, 介面轉場。
    微信支付的流程多。而流程就是由一個個的介面(ViewController,Activity)和相關的業務邏輯組合而成。
    上面的 MV(X) 模式忽略了一個非常重要的一點,那就是業務流程,介面的轉場究竟由誰負責。也即 ViewController 與 ViewController 之間的關係由誰維護,業務流程的邏輯寫在哪裡。如果還按照傳統的 MVC 模式,那麼 ViewController 自己負責和不同的 ViewController 通訊。那麼 ViewController 得不到複用,更致命的是業務流程的程式碼非常不清晰,業務流程的程式碼都被分散到各個 Controller 中, 而一個 Controller 又可能耦合了多個業務的程式碼。
    舉個例子:一個普通的轉賬流程,可能會涉及風控攔截,實名驗證, 收銀臺, 綁卡,支付成功頁等等。如果是基於 MVC 這種架構的話,很快程式碼會變得難以維護。
    微信支付的跨平臺架構到底有多牛?
    因此,為了適應微信支付流程多,介面跳轉複雜的特點。架構抽象的第一步就是將業務流程抽象為一個獨立的角色 UseCase。同時, 把介面抽象為 UIPage。 一個大的業務流程可以分解為一個個小的業務流程。
    微信支付的跨平臺架構到底有多牛?
    和剛才基於 MVC 混亂的架構相比:
    1. 業務流程的程式碼能夠聚合到 UseCase 中,而不是分散到原來 iOS, 安卓的各個 ViewController,Activity 中。

    2. 業務流程和介面得到了複用。

    3. 契合微信支付多流程,介面跳轉複雜的業務特點。

    2. 加入路由機制

    既然流程得到了抽象,這個時候需要針對業務流程做更深的思考。在開發支付業務流程時,開發者不可繞過的問題有:
    1. 流程之間,頁面之間的流傳。

      微信支付的跨平臺架構到底有多牛?

      比如我們要給一個朋友轉賬,輸入金額,確認支付,觸發 Cgi 後。下一個流程是多變的。有可能使用者需要去實名,有可能使用者要進入一個安全攔截的 WebView,或者是正常拉起收銀臺。

      本文中的名詞 CGI 可以理解為一個網路請求,類似HTTP請求。

      那麼以往在 iOS, 安卓分開實現時,都沒有一個統一的處理機制。要麼就是透過網路回包的某個欄位來判斷,要麼就是本地維護一些狀態來決定下一步走什麼流程等等。非常繁瑣,易錯。

    2. 特殊流程的處理

      微信支付的跨平臺架構到底有多牛?

      支付業務流程還有個特殊的地方,那就是在正常流程的中間,往往很多時候要需要插入一些特殊流程。比如有些地方要跳轉 Webview, 有些地方要跳轉小程式,有些地方要彈窗告知使用者風險,或者終止當前流程,等等。我們經常需要在業務程式碼裡面不斷重複增加這樣的處理。

    這些問題,引導我想到,微信支付需要一個路由機制。
    首先了解一下路由機制。
    微信支付的跨平臺架構到底有多牛?
    路由機制的核心思想,就是透過向路由傳遞資料,然後路由解析資料,並響應。
    結合微信支付和網路密切相關的特點。創新地將支付領域模型作為傳遞的資料。
    微信支付的跨平臺架構到底有多牛?
    那麼怎麼建立這個支付領域模型的呢?
    建模,就是建立對映。領域知識 + 建模方法 = 領域建模。那麼這裡的領域知識,就是對支付業務流程的理解。建模方法,我採用了 UML 建模。最終會落地為 Proto 協議供客戶端和後臺一起使用。
    微信支付的跨平臺架構到底有多牛?
    首先,微信支付業務特點就是和網路密切相關,流程和頁面往往是由 Cgi 串聯起來。因此建立模型時,最外層便是網路回包。對於路由機制,這裡我們只關心路由資料模型。
    路由資料模型由 路由型別,還有各個路由型別所需要的資訊組合成。
    路由型別清晰的定義了要觸發的行為。究竟是要開啟一個 UseCase,還是要開啟一個介面,或者 網頁,小程式,彈窗等等。
    然後就是這些行為所需要的資料。比如開啟小程式所需要的引數,彈窗所需要的引數等。
    微信支付的跨平臺架構到底有多牛?
    建立支付領域模型後,我們路由的解析就變得非常清晰了。路由解析之後,會根據路由型別,觸發不同的動作。
    比如流程,介面流轉,會交給 UseCase 處理。
    而特殊流程,比如開啟小程式,開啟 webview, 彈窗這些行為會統一進行處理。
    我們在第一步把業務流程抽象為 UseCase。第二步則加入了路由機制。
    加入路由機制後,支付跨平臺的軟體架構演進為這個樣子。
    微信支付的跨平臺架構到底有多牛?
    加入路由機制後,對比 iOS,安卓原來的舊架構:
    1. 統一了流程,頁面的流轉。清晰,易維護。

    2. 統一了特殊流程的處理,減少重複工作。

    3. 在加入路由機制的時候,結合微信支付和網路密切相關的特點進行了支付領域建模。支付後臺協議重構 2.0 的核心思想也是圍繞著這個路由機制展開。

    微信支付的跨平臺架構到底有多牛?
    再來看一下,加入路由機制後,對生產力的提升。以支付流程開啟 WebView, 小程式為例,減少將近 83% 的程式碼。更重要的是,這裡的特殊流程,是在路由機制裡面統一處理的,沒有耦合到業務程式碼中,並且是可複用的。


    3. 管理網路請求

    首先看看原來 iOS 處理支付網路請求的缺陷:
    微信支付的跨平臺架構到底有多牛?
    原來支付的請求,都是透過一個單例網路中心去發起請求,然後收到回包後,透過拋通知,或者呼叫閉包的方式回撥給業務側。
    會存在這樣的問題:
    1. CGI 一對多通訊問題。

      舉個之前遇到的問題。


      微信支付的跨平臺架構到底有多牛?

      那麼錢包發起的 Cgi 的回包就會覆蓋收付款頁面的資料。之前在 iOS 只能透過修修補補,增加場景值,增加些標記位來解決。可能某一天就會又出現新的坑。

      1. 進入錢包頁面後,發起了一個 Cgi

      2. 然後進入收付款頁面也發起同一個 Cgi.

      3. 如果收付款發起的回包先到

      4. 然後錢包首頁的回包再到。

    2. CGI 生命週期問題。

      微信支付的跨平臺架構到底有多牛?

      不時會有使用者反饋一下,怎麼沒有做什麼操作,突然就會彈出網路報錯。

      原因就是 Cgi 的生命週期有問題,在業務結束後,Cgi 的回包仍然得到了處理。

    解決方案:
    1. 將 Cgi 抽象為獨立物件

      在架構設計上來說,舊架構是透過單例模式實現的集約型 API,而我們新的架構則是透過命令模式實現的離散型 API。

      也就是將 Cgi 封裝為獨立物件。我們把 Cgi 相關屬性和能力內聚起來。開發業務時,只需簡單繼承 BaseCgi,設定一下引數即可。


      微信支付的跨平臺架構到底有多牛?

    2. 劃分職責,明確生命週期

      關於 Cgi 由誰發起,之前安卓和 iOS 都沒有一個統一的做法。有些人會放到 Activity,ViewController,和 UI 程式碼耦合起來。

      因此,在跨平臺軟體架構中,我們統一由業務流程 UseCase 進行發起。並且生命週期是一對一的,一個 Cgi 只會有一個 UseCase 處理, UseCase 銷燬後,Cgi 也隨之銷燬。

    微信支付的跨平臺架構到底有多牛?
    對比舊架構:
    1. 杜絕了一對多通訊造成的 Bug

    2. 生命週期和業務邏輯繫結,不會出現業務結束,Cgi 回來後再觸發動作。

    3. 高內聚,低耦合。將 Cgi 相關的資料,能力集中處理,業務側無需感知。

    4. 提供統一的快取,加密能力。

    微信支付的跨平臺架構到底有多牛?
    第一步和第二步,我們抽象了業務流程,加入了路由機制。
    微信支付的跨平臺架構到底有多牛?
    在第三步管理網路請求後。我們的軟體架構演進為這樣子。
    微信支付的跨平臺架構到底有多牛?

    4. 規範資料傳遞

    iOS 和安卓的舊架構都存在資訊傳遞不當和資料汙染問題。這個問題最嚴重。iOS 和 安卓都出過不少 bug。
    首先我們來看看最近現網出現過的問題:
    之前 iOS 出現,不少內部同事,外部的使用者都在反饋:進行零錢頁後,會無故彈空白框。而支付又和金錢有關,引起使用者的恐慌。
    微信支付的跨平臺架構到底有多牛?

    具體原因就是:
    1. 進入支付首頁時,後臺返回了資料,然後被寫入到一個公共的 Model.

    2. 然後進入錢包頁,再進入零錢頁。這個公共 model 一路被傳遞過去。

    3. 然後零錢頁讀取了公共 Model 的資料,但是程式碼無法處理,導致出現了這個讓使用者恐慌的問題。

    除此之外,之前還有有很多發生在安卓,iOS ,像錢包頁零錢展示錯誤。付款的時候。銀行卡失效等等問題。
    這些問題五花八門,看起來發生的地方,場景都不一樣。每次遇到這類問題的時候,就只能去修修補補。
    但是深究下去,會發現真正的原因,是軟體架構上存在的問題:
    微信支付的跨平臺架構到底有多牛?
    支付舊的架構採用了黑板模式,雖然方便了資料讀寫。但是帶來的問題和收益完全不成正比:
    1. 存在公共讀寫的資料型別。

      安卓傳遞的資料型別是一個字典,而 iOS 則是一個 Model 物件。所有的介面,業務邏輯都共用一個資料。

    2. 無序的資料流動。

      資料的流動是不可追溯的,資料的修改可以發生在任意使用公共資料的地方。

    那麼支付跨平臺軟體架構,為了杜絕這樣的問題。我是這麼做的:
    微信支付的跨平臺架構到底有多牛?
    1. 去掉公共讀寫的資料型別

    2. 傳遞值型別(Value Type)的資料, 後面流程修改資料時,不影響前面的流程。

    3. 單向傳遞資料,只依賴注入必要資料。

    4. 如果資料修改需要通知前序流程,使用代理模式通訊。

    規範資料傳遞後。對比舊架構:
    1. 從架構上根本解決了困擾微信支付已久的資料汙染的問題。

    2. 資料的流動變為單向,資料流動變得可追溯。

    前面三步,我們抽象了業務流程,加入了路由機制,統一管理網路請求。
    微信支付的跨平臺架構到底有多牛?
    那麼規範資料傳遞後,我們軟體架構就演進為這樣子。
    微信支付的跨平臺架構到底有多牛?

    總結

    軟體的本質複雜性存在於複雜的業務需求中。而軟體架構的本質就是管理複雜性,因此真正的好的架構,正是在複雜的業務需求中反覆提煉和總結歸納而來,解決了真正的業務問題,不是空談。
    軟體架構除了清理歷史舊架構的缺陷,是我們業務開發的基石之外。還能夠賦能業務,為業務帶來價值。在建立軟體架構的基礎上,還圍繞著軟體架構建立起微信支付的跨平臺自動化資料上報機制,防重複支付,安全橫切等帶來巨大業務收益的能力。有機會的話,後面也會進一步編寫相關文章和大家交流探討。
    架構是一個不斷演進的過程,隨著新的支付業務基於跨平臺軟體架構的不斷編寫, 我也會對這個架構進行持續的更新迭代。讓這個軟體架構更貼合微信支付,更加健壯和完整。


    來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/69900357/viewspace-2682410/,如需轉載,請註明出處,否則將追究法律責任。

    相關文章