背景
做爲一個重要業務,微信支付在客戶端上面臨着各類問題。其中最核心問題就是分平臺實現致使的問題,常見的問題有:程序員
iOS 和安卓實現不一致:容易出 Bug和經過溝通保證不了質量;web
擴展性差,沒法快速響應業務需求:需求變動迭代週期長和數據上報不全面;面試
質量保障體系不完善:缺乏業務及設計知識沉澱、協議管理鬆散和缺乏統一的自動化測試;小程序
用戶體驗不一致:好比下圖就是以前安卓和 iOS 沒有統一前的收銀臺。緩存
爲了解決多個平臺實現這個核心問題,並解決以往的技術債務。咱們創建起了一整套基於 C++ 的跨平臺框架,並對核心支付流程進行了重構。微信支付跨平臺從 iOS 7.0.4 版本起, 安卓從 7.0.7 版本起全面覆蓋。安全
目標
以目前線上運行的 iOS 狀況爲例,微信支付跨平臺基本實現了以下指標:微信
Crash
上線先後 Crash 率保持平穩,沒有影響微信穩定性,跨平臺支付無必現 Crash,作到了用戶無感知切換。網絡
舉個例子,你們能夠用微信發一筆紅包,拉起的收銀臺和支付流程就是由基於C++編寫的跨平臺代碼所驅動的。多線程
效能提高
以核心支付流程代碼爲例,跨平臺須要 3512 行,iOS 原生須要 6328 行。減小了近 45% 的代碼。閉包
以新需求開發爲例:
跨平臺實現:iOS + 安卓 共計 3 人日,在封板時間前完成
原生實現:iOS, 安卓封板時間後一週才基本完成
跨平臺實現:iOS + 安卓共計 5 人日,在封板時間前完成
原生實現:iOS, 安卓封板時間後一週才基本完成
那麼支付跨平臺軟件架構怎麼樣有效進行質量保障,而且提高生產力呢?看下面這個架構圖。
對基於 C++ 如何從零到一構建跨平臺框架感興趣的同窗,能夠在查看 《基於 C++ 構建微信客戶端跨平臺開發框架》 。
什麼是軟件架構
什麼是軟件架構?正如 Ivar Jacobson (UML 之父)說過的同樣,找五我的來回答這個問題,五我的可能都有各自不一樣的答案。
架構定義能夠有不少種說法,從代碼規範到發佈流程均可以是架構的一部分。
針對微信支付的業務特色,這裏對架構的定義是:架構是系統的組成部件及其之間的相互關係(通信方式)。這更符合咱們程序員平常編寫業務代碼時對架構的理解,也就是通俗意義上講的 MVC、MVP、MVVM 等。
早在 1986 年的時候,人月神話的做者在討論軟件的複雜性時,談到:軟件的本質複雜性存在於複雜的業務需求中。
而管理複雜性,最根本的手段就是職責分離。爲了實現職責分離,代碼重用,架構慢慢地復現出來。架構的本質是管理複雜性。
沒有架構,咱們全部的代碼都耦合在一塊兒,人類的心智模型不擅長處理這種複雜性,架構的設立,和圖書館的圖書分類,公司的組織劃分等,本質都是同樣的。是爲了管理複雜性,以取得更高的生產力。
從零到一構建支付跨平臺軟件架構
在移動客戶端領域,業界基於 C++ 來編寫業務代碼,並無成熟的架構。即便使用 C++ 編寫業務邏輯,但都不涉及 UI,不涉及界面的跳轉流程。
既然業界沒有一個成熟的架構可借鑑,那麼是否是直接把業界通用的架構簡單套用一下就好?
1,抽象業務流程
如今業界通用的有 MVC , MVP, MVVM 。這些你們都熟悉的軟件架構。可是這些軟件架構都存在一個問題:那就是沒有處理好業務流程以及界面轉場。微信支付的流程多。而流程就是由一個個的界面(ViewController,Activity)和相關的業務邏輯組合而成。
上面的 MV(X) 模式忽略了一個很是重要的一點,那就是業務流程,界面的轉場究竟由誰負責。也即 ViewController 與 ViewController 之間的關係由誰維護,業務流程的邏輯寫在哪裏。若是還按照傳統的 MVC 模式,那麼 ViewController 本身負責和不一樣的 ViewController 通信。那麼 ViewController 得不到複用,更致命的是業務流程的代碼很是不清晰,業務流程的代碼都被分散到各個 Controller 中, 而一個 Controller 又可能耦合了多個業務的代碼。
舉個例子:一個普通的轉帳流程,可能會涉及風控攔截,實名驗證, 收銀臺, 綁卡,支付成功頁等等。若是是基於 MVC 這種架構的話,很快代碼會變得難以維護。
所以,爲了適應微信支付流程多,界面跳轉複雜的特色。架構抽象的第一步就是將業務流程抽象爲一個獨立的角色 UseCase。同時, 把界面抽象爲 UIPage。一個大的業務流程能夠分解爲一個個小的業務流程。
和剛纔基於 MVC 混亂的架構相比,UseCase具備以下優勢:
業務流程的代碼可以聚合到 UseCase 中,而不是分散到原來 iOS, 安卓的各個 ViewController,Activity 中。
業務流程和界面獲得了複用。
契合微信支付多流程,界面跳轉複雜的業務特色。
2. 加入路由
既然流程獲得了抽象,這個時候就須要針對業務流程作更深的思考。在開發支付業務流程時,開發者不可繞過的問題有:
1,流程之間,頁面之間的流傳。
好比咱們要給一個朋友轉帳,輸入金額,確認支付,觸發 Cgi 後。下一個流程是多變的,有可能用戶須要去實名,有可能用戶要進入一個安全攔截的 WebView,或者是正常拉起收銀臺。
那麼以往在 iOS、 安卓分開實現時,都沒有一個統一的處理機制。要麼就是經過網絡回包的某個字段來判斷,要麼就是本地維護一些狀態來決定下一步走什麼流程等等,很是繁瑣且易錯。
2,特殊流程的處理
支付業務流程還有個特殊的地方,那就是在正常流程的中間,每每不少時候要須要插入一些特殊流程。好比有些地方要跳轉 Webview, 有些地方要跳轉小程序,有些地方要彈窗告知用戶風險,或者終止當前流程,等等。咱們常常須要在業務代碼裏面不斷重複增長這樣的處理。
正是由於這些問題引導咱們須要考慮微信支付的路由機制。首先了解一下路由機制。
路由機制的核心思想,就是經過向路由傳遞數據,而後路由解析數據並響應。結合微信支付和網絡密切相關的特色,創新地將支付領域模型做爲傳遞的數據。
那麼怎麼創建這個支付領域模型的呢?
建模,就是創建映射。領域知識 + 建模方法 = 領域建模。那麼這裏的領域知識,就是對支付業務流程的理解。建模方法,我採用了 UML 建模。最終會落地爲 Proto 協議供客戶端和後臺一塊兒使用。
首先,微信支付業務特色就是和網絡密切相關,流程和頁面每每是由 Cgi 串聯起來。所以創建模型時,最外層即是網絡回包。對於路由機制,這裏咱們只關心路由數據模型。
路由數據模型由 路由類型,還有各個路由類型所須要的信息組合成。
路由類型清晰的定義了要觸發的行爲。到底是要開啓一個 UseCase,仍是要打開一個界面,或者 網頁,小程序,彈窗等等。
而後就是這些行爲所須要的數據。好比打開小程序所須要的參數,彈窗所須要的參數等。
創建支付領域模型後,咱們路由的解析就變得很是清晰了。路由解析以後,會根據路由類型,觸發不一樣的動做。好比流程,界面流轉,會交給 UseCase 處理。而特殊流程,好比打開小程序,打開 webview, 彈窗這些行爲會統一進行處理。
咱們在第一步把業務流程抽象爲 UseCase。第二步則加入了路由機制。加入路由機制後,支付跨平臺的軟件架構演進爲這個樣子。
加入路由機制後,對比 iOS、安卓原來的舊架構,新架構具備以下優勢:
統一了流程,頁面的流轉。清晰,易維護。
統一了特殊流程的處理,減小重複工做。
在加入路由機制的時候,結合微信支付和網絡密切相關的特色進行了支付領域建模。支付後臺協議重構 2.0 的核心思想也是圍繞着這個路由機制展開。
再來看一下,加入路由機制後,對生產力的提高。以支付流程打開 WebView, 小程序爲例,減小將近 83% 的代碼。更重要的是,這裏的特殊流程,是在路由機制裏面統一處理的,沒有耦合到業務代碼中,而且是可複用的。
3. 管理網絡請求
首先,看看原來 iOS 處理支付網絡請求的缺陷,下面是示意圖。
原來支付的請求,都是經過一個單例網絡中心去發起請求,而後收到回包後,經過拋通知,或者調用閉包的方式回調給業務方。對於上面這種結構,存在這樣的問題:
1,CGI 一對多通信問題。
舉個以前遇到的問題。
那麼錢包發起的 Cgi 的回包就會覆蓋收付款頁面的數據。以前在 iOS 只能經過修修補補,增長場景值,增長些標記位來解決,可能某一天就會又出現新的坑。
進入錢包頁面後,發起了一個 Cgi
而後進入收付款頁面也發起同一個 Cgi.
若是收付款發起的回包先到
而後錢包首頁的回包再到。
2,CGI 生命週期問題。
不時會有用戶反饋一下,怎麼沒有作什麼操做,忽然就會彈出網絡報錯。緣由就是 Cgi 的生命週期有問題,在業務結束後,Cgi 的回包仍然獲得了處理。
解決方案
1,將 Cgi 抽象爲獨立對象
在架構設計上來講,舊架構是經過單例模式實現的集約型 API,而咱們新的架構則是經過命令模式實現的離散型 API。也就是將 Cgi 封裝爲獨立對象。咱們把 Cgi 相關屬性和能力內聚起來。開發業務時,只需簡單繼承 BaseCgi,設置一下參數便可。
2,劃分職責,明確生命週期
關於 Cgi 由誰發起,以前安卓和 iOS 都沒有一個統一的作法。有些人會放到 Activity,ViewController,和 UI 代碼耦合起來。
所以,在跨平臺軟件架構中,咱們統一由業務流程 UseCase 進行發起。而且生命週期是一對一的,一個 Cgi 只會有一個 UseCase 處理, UseCase 銷燬後,Cgi 也隨之銷燬。
對比舊架構,新的架構具備以下優勢:
杜絕了一對多通訊形成的 Bug。
生命週期和業務邏輯綁定,不會出現業務結束,Cgi 回來後再觸發動做。
高內聚,低耦合。將 Cgi 相關的數據,能力集中處理,業務側無需感知。
提供統一的緩存,加密能力。
第一步和第二步,咱們抽象了業務流程,加入了路由機制。
在第三步管理網絡請求後,咱們的軟件架構演進爲這樣子。
4. 規範數據傳遞
iOS 和安卓的舊架構都存在信息傳遞不當和數據污染問題。這個問題最嚴重。iOS 和 安卓都出過很多 bug。
首先咱們來看看最近現網出現過的問題:以前 iOS 出現,很多內部同事,外部的用戶都在反饋:進行零錢頁後,會無端彈空白框。而支付又和金錢有關,引發用戶的恐慌。
通過排查,具體緣由就是:
進入支付首頁時,後臺返回了數據,而後被寫入到一個公共的 Model.
而後進入錢包頁,再進入零錢頁。這個公共 model 一路被傳遞過去。
而後零錢頁讀取了公共 Model 的數據,可是代碼沒法處理,致使出現了這個讓用戶恐慌的問題。
除此以外,以前還有有不少發生在安卓,iOS ,像錢包頁零錢展現錯誤。付款的時候。銀行卡失效等等問題。這些問題五花八門,看起來發生的地方,場景都不同。每次遇到這類問題的時候,就只能去修修補補。可是深究下去,會發現真正的緣由,是軟件架構上存在的問題:
支付舊的架構採用了黑板模式,雖然方便了數據讀寫。可是帶來的問題和收益徹底不成正比:
存在公共讀寫的數據類型。安卓傳遞的數據類型是一個字典,而 iOS 則是一個 Model 對象。全部的界面,業務邏輯都共用一個數據。
無序的數據流動。數據的流動是不可追溯的,數據的修改能夠發生在任意使用公共數據的地方。
針對上面的問題,支付跨平臺軟件架構,爲了杜絕這樣的問題,作了以下的架構改進。
去掉公共讀寫的數據類型
傳遞值類型(Value Type)的數據, 後面流程修改數據時,不影響前面的流程。
單向傳遞數據,只依賴注入必要數據。
若是數據修改須要通知前序流程,使用代理模式通信。
規範數據傳遞後。對比舊架構:
從架構上根本解決了困擾微信支付已久的數據污染的問題。
數據的流動變爲單向,數據流動變得可追溯。
前面三步,咱們抽象了業務流程,加入了路由機制,統一管理網絡請求,架構以下。
那麼規範數據傳遞後,咱們軟件架構就演進爲這樣子。
總結
軟件的本質複雜性存在於複雜的業務需求中。而軟件架構的本質就是管理複雜性,所以真正的好的架構,正是在複雜的業務需求中反覆提煉和總結概括而來,解決了真正的業務問題,不是空談。
軟件架構除了清理歷史舊架構的缺陷,是咱們業務開發的基石以外。還可以賦能業務,爲業務帶來價值。在創建軟件架構的基礎上,還圍繞着軟件架構創建起微信支付的跨平臺自動化數據上報機制,防重複支付,安全橫切等帶來巨大業務收益的能力。有機會的話,後面也會進一步編寫相關文章和你們交流探討。
架構是一個不斷演進的過程,隨着新的支付業務基於跨平臺軟件架構的不斷編寫, 我也會對這個架構進行持續的更新迭代。讓這個軟件架構更貼合微信支付,更加健壯和完整。
面試專場:
本文分享自微信公衆號 - JAVA高級架構(gaojijiagou)。
若有侵權,請聯繫 support@oschina.cn 刪除。
本文參與「OSC源創計劃」,歡迎正在閱讀的你也加入,一塊兒分享。