微信支付被盜刷?微信:咱們全賠!支付寶:咱們秒賠!

關注我們,設爲星標,天天7:30不見不散,架構路上與您共享

回覆"架構師"獲取資源css


本文原文由微信客戶端高級工程師方秋枋原創發表於WeMobileDev公衆號,即時通信網收錄時有修訂和加工,轉載自即時通信,感謝做者的無私分享。java


一、引言


做爲一個重要業務,微信支付在客戶端上面臨着各類問題。

其中最核心問題就是分平臺實現致使的問題:

git

  • 1)iOS 和安卓實現不一致:容易出 Bug、經過溝通保證不了質量;程序員

  • 2)擴展性差且沒法快速響應業務需求:需求變動迭代週期長、數據上報不全面;github

  • 3)質量保障體系不完善:缺乏業務及設計知識沉澱、協議管理鬆散、缺乏統一的自動化測試;web

  • 4)用戶體驗不一致:好比下圖就是以前安卓和 iOS 沒有統一前的收銀臺。
    面試


  ▲ 微信安卓片和iOS版,沒有統一用戶體驗前的收銀臺功能

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

重構後的軟件架構原理以下圖所示:
 
本文分享了微信團隊基於 C++ 的移動端跨平臺技術在重構整個微信支付功能的過程當中,對於移動端軟件架構設計方面的思考和實踐總結。

術語約定:本文中的名詞 CGI 能夠理解爲一個網絡請求,相似HTTP請求。

擴展閱讀:本文引用的全部圖片均來自《基於C++構建微信客戶端跨平臺開發框架(PPT) [附件下載]》,若有須要可前往下載PPT原稿。
小程序


二、關於做者


 
方秋枋:畢業於華中科技大學,現爲微信客戶端高級工程師。目前主要負責微信支付的跨平臺開發框架與相關業務開發。

是開源項目 SwiftNotificationCenter ,SwiftTimer ,SwiftCssParser 的做者。業餘時間也喜歡混跡在 SwiftGG 翻譯組,老司機 iOS 週報給你們翻譯文章,摘錄週報。喜歡 Simple and Stupid 的代碼。熱愛科技、開源。

緩存

  • 方秋枋的Github:https://github.com/100mango安全

  • 方秋枋的微博:https://weibo.com/100mango?is_hot=1

  • 方秋枋的知乎:https://www.zhihu.com/people/fang-qiu-fang


三、先感覺一下本次重構的線上效果指標


以 iOS 上線狀況爲例。

3.1Crash 率


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

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

3.2效能提高


 

以核心支付流程代碼爲例,跨平臺須要 3512 行,iOS 原生須要 6328 行。減小了近 45% 的代碼。

以新需求開發爲例:

  • 1)7.0.4 版本需求一:收銀臺改版;

  • 2)7.0.4 版本需求二:簡化版本收銀臺。


重構後的軟件架構對開發效率的提高對比:

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

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

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

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


那麼支付跨平臺軟件架構怎麼樣有效進行質量保障,而且提高生產力呢?這是這篇文章的主要內容。

對基於 C++ 如何從零到一構建跨平臺框架感興趣的同窗,能夠看看我在2019 QCon 廣州站的演講 《基於 C++ 構建微信客戶端跨平臺開發框架》PPT原稿。


四、什麼是軟件架構


什麼是軟件架構?正如 Ivar Jacobson (UML 之父)說過的同樣,找五我的來回答這個問題,五我的可能都有各自不一樣的答案。

Ivar Jacobson博士:
 

現代軟件開發之父Ivar Jacobson博士被認爲是深入影響或改變了整個軟件工業開發模式的幾位世界級大師之一。他是模塊和模塊架構、用例、現代業務工程、Rational統一過程等業界主流方法、技術的創始人。Ivar Jacobson博士與Grady Booch和James Rumbaugh一道共同建立了UML建模語言,被業界譽爲UML之父。Ivar Jacobson 的用例驅動方法對整個OOAD行業影響深遠,他所以而成爲業界的一面「旗幟」。


架構定義能夠有不少種說法,從代碼規範到發佈流程均可以是架構的一部分。

針對微信支付的業務特色,這裏對架構的定義是:架構是系統的組成部件及其之間的相互關係(通信方式)。這更符合咱們程序員平常編寫業務代碼時對架構的理解。也就是通俗意義上講的 MVC,MVVM 等。


五、爲何須要軟件架構


早在 1986 年的時候,《人月神話》的做者在討論軟件的複雜性時,談到:軟件的本質複雜性存在於複雜的業務需求中

 
▲ 軟件工程不朽的經典《人月神話》書籍(中文版)封面

而管理複雜性,最根本的手段就是職責分離。爲了實現職責分離,代碼重用,架構慢慢地復現出來。架構的本質是管理複雜性。

沒有架構,咱們全部的代碼都耦合在一塊兒,人類的心智模型不擅長處理這種複雜性,架構的設立,和圖書館的圖書分類,公司的組織劃分等,本質都是同樣的。是爲了管理複雜性,以取得更高的生產力


五、從0到1:構建微信支付跨平臺軟件架構


在移動客戶端領域,業界基於 C++ 來編寫業務代碼,並無成熟的架構。即便使用 C++ 編寫業務邏輯,但都不涉及 UI,不涉及界面的跳轉流程。

既然業界沒有一個成熟的架構可借鑑,那麼是否是直接把業界通用的架構簡單套用一下就好?

5.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)契合微信支付多流程,界面跳轉複雜的業務特色。


5.2加入路由機制


既然流程獲得了抽象,這個時候須要針對業務流程作更深的思考。在開發支付業務流程時,開發者不可繞過的問題有下面這些。

流程之間,頁面之間的流傳:


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

注意:本文中的名詞 CGI 能夠理解爲一個網絡請求,相似HTTP請求。

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

特殊流程的處理:


 
支付業務流程還有個特殊的地方,那就是在正常流程的中間,每每不少時候要須要插入一些特殊流程。好比有些地方要跳轉 Webview, 有些地方要跳轉小程序,有些地方要彈窗告知用戶風險,或者終止當前流程,等等。咱們常常須要在業務代碼裏面不斷重複增長這樣的處理。

這些問題,引導我想到,微信支付須要一個路由機制。

首先了解一下路由機制:
 
路由機制的核心思想,就是經過向路由傳遞數據,而後路由解析數據,並響應。

結合微信支付和網絡密切相關的特色。創新地將支付領域模型做爲傳遞的數據。

 

那麼怎麼創建這個支付領域模型的呢?

建模,就是創建映射。領域知識 + 建模方法 = 領域建模。那麼這裏的領域知識,就是對支付業務流程的理解。建模方法,我採用了 UML 建模。最終會落地爲 Proto 協議供客戶端和後臺一塊兒使用。

 
首先:微信支付業務特色就是和網絡密切相關,流程和頁面每每是由 Cgi 串聯起來。所以創建模型時,最外層即是網絡回包。對於路由機制,這裏咱們只關心路由數據模型。

路由數據模型由路由類型,還有各個路由類型所須要的信息組合成。

路由類型清晰的定義了要觸發的行爲。到底是要開啓一個 UseCase,仍是要打開一個界面,或者 網頁,小程序,彈窗等等。

而後:就是這些行爲所須要的數據。好比打開小程序所須要的參數,彈窗所須要的參數等。

 
創建支付領域模型後,咱們路由的解析就變得很是清晰了。路由解析以後,會根據路由類型,觸發不一樣的動做。

好比流程,界面流轉,會交給 UseCase 處理。

而特殊流程,好比打開小程序,打開 webview, 彈窗這些行爲會統一進行處理。

咱們在第一步把業務流程抽象爲 UseCase。第二步則加入了路由機制。

加入路由機制後,支付跨平臺的軟件架構演進爲這個樣子:
 
加入路由機制後,對比微信的iOS、安卓原來的舊架構:

  • 1)統一了流程,頁面的流轉。清晰,易維護;

  • 2)統一了特殊流程的處理,減小重複工做;

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




再來看一下,加入路由機制後,對生產力的提高。以支付流程打開 WebView,、小程序爲例,減小將近 83% 的代碼。更重要的是,這裏的特殊流程,是在路由機制裏面統一處理的,沒有耦合到業務代碼中,而且是可複用的。

5.3管理網絡請求


首先看看原來 iOS 處理支付網絡請求的缺陷:
 

原來支付的請求,都是經過一個單例網絡中心去發起請求,而後收到回包後,經過拋通知,或者調用閉包的方式回調給業務側。

會存在這樣兩個問題。

1)CGI 一對多通信問題:

舉個以前遇到的問題:
 

如上圖所示,錢包發起的 Cgi 的回包會覆蓋收付款頁面的數據。以前在 iOS 只能經過修修補補,增長場景值,增長些標記位來解決。可能某一天就會又出現新的坑。

具體的問題流程是:

  • a. 進入錢包頁面後,發起了一個 Cgi;

  • b. 而後進入收付款頁面也發起同一個 Cgi;

  • c. 若是收付款發起的回包先到;

  • d. 而後錢包首頁的回包再到。


2)CGI 生命週期問題:

 

如上圖所示,不時會有用戶反饋一下,怎麼沒有作什麼操做,忽然就會彈出網絡報錯。

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

在咱們的解決方案裏,將在構架的以下兩個方面進行優化和處理。

1)將 Cgi 抽象爲獨立對象:

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

也就是將 Cgi 封裝爲獨立對象。咱們把 Cgi 相關屬性和能力內聚起來。開發業務時,只需簡單繼承 BaseCgi,設置一下參數便可。

 

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

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

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

 

對比舊架構:

  • a. 杜絕了一對多通訊形成的 Bug;

  • b. 生命週期和業務邏輯綁定,不會出現業務結束,Cgi 回來後再觸發動做;

  • c. 高內聚,低耦合。將 Cgi 相關的數據,能力集中處理,業務側無需感知;

  • d. 提供統一的緩存,加密能力。


 
在上述第a步和第b步,咱們抽象了業務流程,加入了路由機制:



在上述第c步管理網絡請求後,咱們的軟件架構演進爲這樣子:


5.4規範數據傳遞


iOS 和安卓的舊架構都存在信息傳遞不當和數據污染問題。這個問題最嚴重。iOS 和 安卓都出過很多 bug。

首先咱們來看看最近現網出現過的問題:

以前 iOS 出現,很多內部同事,外部的用戶都在反饋:進行零錢頁後,會無端彈空白框。而支付又和金錢有關,引發用戶的恐慌(見下面的演示視頻所示)。


▲ 視頻原地址:點此進入

大體的緣由,以下圖所示:
 
具體緣由就是:

  • 1)進入支付首頁時,後臺返回了數據,而後被寫入到一個公共的 Model;

  • 2)而後進入錢包頁,再進入零錢頁。這個公共 model 一路被傳遞過去;

  • 3)而後零錢頁讀取了公共 Model 的數據,可是代碼沒法處理,致使出現了這個讓用戶恐慌的問題。


除此以外,以前還有有不少發生在安卓,iOS ,像錢包頁零錢展現錯誤。付款的時候。銀行卡失效等等問題。

這些問題五花八門,看起來發生的地方,場景都不同。每次遇到這類問題的時候,就只能去修修補補。

可是深究下去,會發現真正的緣由,是軟件架構上存在的問題:
 

支付舊的架構採用了黑板模式,雖然方便了數據讀寫,可是帶來的問題和收益徹底不成正比。

具體存在如下問題:

  • 1)存在公共讀寫的數據類型:安卓傳遞的數據類型是一個字典,而 iOS 則是一個 Model 對象。全部的界面,業務邏輯都共用一個數據;

  • 2)無序的數據流動:數據的流動是不可追溯的,數據的修改能夠發生在任意使用公共數據的地方。


那麼支付跨平臺軟件架構,爲了杜絕這樣的問題,我是這麼作的:
 

具體的思路是:

  • 1)去掉公共讀寫的數據類型;

  • 2)傳遞值類型(Value Type)的數據, 後面流程修改數據時,不影響前面的流程;

  • 3)單向傳遞數據,只依賴注入必要數據;

  • 4)若是數據修改須要通知前序流程,使用代理模式通信。


上述的前面三步,咱們抽象了業務流程,加入了路由機制,統一管理網絡請求:


那麼規範數據傳遞後,咱們軟件架構就演進爲這樣子:
 
規範數據傳遞後,對比舊架構:

  • 1)從架構上根本解決了困擾微信支付已久的數據污染的問題;

  • 2)數據的流動變爲單向,數據流動變得可追溯。


六、本文小結


軟件的本質複雜性存在於複雜的業務需求中。而軟件架構的本質就是管理複雜性,所以真正的好的架構,正是在複雜的業務需求中反覆提煉和總結概括而來,解決了真正的業務問題,不是空談。

軟件架構除了清理歷史舊架構的缺陷,是咱們業務開發的基石以外。還可以賦能業務,爲業務帶來價值。在創建軟件架構的基礎上,還圍繞着軟件架構創建起微信支付的跨平臺自動化數據上報機制,防重複支付,安全橫切等帶來巨大業務收益的能力。有機會的話,後面也會進一步編寫相關文章和你們交流探討。

架構是一個不斷演進的過程,隨着新的支付業務基於跨平臺軟件架構的不斷編寫, 我也會對這個架構進行持續的更新迭代。讓這個軟件架構更貼合微信支付,更加健壯和完整。

文章來源 :即時通信網



到此文章就結束了。若是今天的文章對你在進階架構師的路上有新的啓發和進步,歡迎轉發給更多人。歡迎加入架構師社區技術交流羣,衆多大咖帶你進階架構師,在後臺回覆「加羣」便可入羣。














這些年小編給你分享過的乾貨

《IDEA 2020.1 最新破解教程,有效期到2089年

Kubernetes的前世此生

大家公司的架構師是什麼樣的?

《Docker與CI持續集成/CD持續部署》

《還有40天,Java 11就要橫空出世了》

《JDK 10 的 109 項新特性》

《學習微服務的十大理由》

《進大廠必須掌握的50個微服務面試問題》


轉發在看就是最大的支持❤️

本文分享自微信公衆號 - Java架構師社區(mush_java_jg)。
若有侵權,請聯繫 support@oschina.cn 刪除。
本文參與「OSC源創計劃」,歡迎正在閱讀的你也加入,一塊兒分享。

相關文章
相關標籤/搜索