微信架構 & 支付架構(上)
一. 微信和支付寶對比
這兩者現在已經占領了移動支付的90%市場,支付形式也都大抵相同,只是在實現細節上略微不同。這里之所以要專門對比,是因為有些接口的不同在后邊的框架的設計中也會有所影響。主要集中在以下幾個方面:
1. 支付方式上:
a. 支付寶多了一個聲波支付
b. 手機端H5支付方式中, 微信只支持微信內部瀏覽器
c. 微信用戶掃碼方式中除了正常下單返回支付二維碼,還提提供了回調下單模式(即掃描的二維碼並不是支付二維碼,而是商品二維碼,微信會回調商戶指定地址才真實下單)
2. 接口安全
a. 微信不同接口安全等級不一樣,涉及付款等接口加密相對簡單(MD5,SHA1),涉及到退款,發送紅包等接口需要使用雙向證書驗證
b. 支付寶所有接口統一使用RSA加密驗證,需要公私鑰驗證。
3. 接口協議
a. 微信使用的xml協議,所有參數基本都在同一層級。
b. 支付寶使用json協議,核心參數放在biz_content字段中。
二. 微信和支付寶軟件架構
作為一個重要業務,微信支付在客戶端上面臨着各種問題。其中最核心問題就是分平台實現導致的問題:
iOS 和安卓實現不一致
- 容易出 Bug
- 通過溝通保證不了質量
擴展性差,無法快速響應業務需求
- 需求變更迭代周期長
- 數據上報不全面
質量保障體系不完善
- 缺少業務及設計知識沉淀
- 協議管理松散
- 缺少統一的自動化測試
用戶體驗不一致
比如下圖就是之前安卓和 iOS 沒有統一前的收銀台。
為了解決分平台實現這個核心問題,並解決以往的技術債務。我們建立起了一整套基於 C++
的跨平台框架,並對核心支付流程進行了重構。
微信支付跨平台從 iOS 7.0.4 版本起, 安卓從 7.0.7 版本起全面覆蓋。
線上效果指標
以 iOS 上線情況為例:
Crash 率
上線前后 Crash 率保持平穩,沒有影響微信穩定性,跨平台支付無必現 Crash,做到了用戶無感知切換。
舉個例子,大家可以用微信發一筆紅包,拉起的收銀台和支付流程就是由基於C++編寫的跨平台代碼所驅動的。
效能提升
以核心支付流程代碼為例,跨平台需要 3512 行,iOS 原生需要 6328 行。減少了近 45% 的代碼。
以新需求開發為例:
7.0.4 版本需求一:收銀台改版
7.0.4 版本需求二:簡化版本收銀台
- 跨平台實現:iOS + 安卓 共計 3 人日,在封板時間前完成
- 原生實現:iOS, 安卓封板時間后一周才基本完成
- 跨平台實現:iOS + 安卓共計 5 人日,在封板時間前完成
- 原生實現:iOS, 安卓封板時間后一周才基本完成
那么支付跨平台軟件架構怎么樣有效進行質量保障,並且提升生產力呢?這是這篇文章的主要內容。
什么是軟件架構
什么是軟件架構?正如 Ivar Jacobson (UML 之父)說過的一樣,找五個人來回答這個問題,五個人可能都有各自不同的答案。
架構定義可以有很多種說法,從代碼規范到發布流程都可以是架構的一部分。
針對微信支付的業務特點,這里對架構的定義是:架構是系統的組成部件及其之間的相互關系(通訊方式)。這更符合我們程序員日常編寫業務代碼時對架構的理解。也就是通俗意義上講的 MVC
,MVVM
等。
為什么需要軟件架構
早在 1986 年的時候,人月神話的作者在討論軟件的復雜性時,談到:軟件的本質復雜性存在於復雜的業務需求中。
而管理復雜性,最根本的手段就是職責分離。為了實現職責分離,代碼重用,架構慢慢地復現出來。架構的本質是管理復雜性。關注微信公眾號:Java技術棧,在后台回復:架構,可以獲取我整理的 N 篇架構干貨。
沒有架構,我們所有的代碼都耦合在一起,人類的心智模型不擅長處理這種復雜性,架構的設立,和圖書館的圖書分類,公司的組織划分等,本質都是一樣的。是為了管理復雜性,以取得更高的生產力。
從零到一構建支付跨平台軟件架構
在移動客戶端領域,業界基於 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% 的代碼。更重要的是,這里的特殊流程,是在路由機制里面統一處理的,沒有耦合到業務代碼中,並且是可復用的。