移動客戶端架構案例分析與思考

移動客戶端架構案例分析與思考

寫在前面

關於題目

分享以前,想說一下爲何選擇了「架構」這個主題,其實初衷有兩個:html

第一,「架構」對於咱們來講實在是過重要了,我們雖然沒有架構師這個職位,可是在開發的時候,都須要先有個很好的設計,但願咱們的代碼是易維護的,而「設計」每每都會落到「架構」上。因此但願此次分享可以對於你們在架構設計上有一點幫助。react

第二,即使「架構」如此的重要,你們再聊到「架構」這個話題的時候,仍是感受到有點「虛」。想一想緣由,多是由於每一個人對於「架構」的理解可能都不太同樣,一我的在不一樣階段對於「架構」的理解也會不同,架構設計還很依賴於實踐和經驗,不少設計細節(取捨)都是在實踐中不停的迭代、改進,進而反思才能獲得價值觀的升級。因此我藉此次機會,也將我本身以前零散的架構方面的理解,總結一下,爭取能造成一點體系上的認識。但願你們聊起架構時,能稍微不那麼「虛」。ios

分享形式

爲了避免那麼枯燥,今天分享形式,我選了3個架構的案例,來進行分析,來試圖講清楚我對於架構的認識,以及怎麼樣設計出一個好的架構,固然這個話題太大了,我今天先給你們開個頭,但願先能有一點感受就好。面試

最後但願你們帶着批判的精神來聽,歡迎多交流。算法

第一個案例:獵戶語音iOS SDK —— 架構是被業務驅動的

第一個案例,舉一個咱們本身的,放在第一個來說,也是想強調「懂業務」對於設計出好的架構來講,是很是重要的,這也是一些人每每會忽略的點。數據庫

不少同窗確定想,在項目的一開始,就設計一個完美的架構,之後能 hold 住各類變化。其實這是不可能的,架構必定是隨着業務的變化,而不停的演化和進化的,在有的階段還可能對於以前架構作比較大的調整。react-native

背景

你們都知道,咱們同時維護了幾個App,好比小豹、小雅、錘子等,這些上層App,都要依賴於底層的一些framework,好比設計模式

  • 業務中心 OrionServiceSDK.framework (包括不少主要業務)
  • 信息流 OVSChat.framework
  • 技能商店 OVSSkillStore.framework
  • 聲紋 OVSVoicePrint.framework
  • 等等

在早些的時候,咱們對於 SDK 的拆分粒度比較細,好比一個「找手機」技能,都會作成一個 framework。當時的 framework,應該在20個左右,各個 framework(組件) 的依賴關係圖以下:服務器

歷史緣由

咱們這麼作當時的緣由很簡單,但願可以解耦各個組件,將組件儘可能拆細,而後App方想使用什麼功能均可以作到熱插拔,很少也很多,多好~網絡

理想 VS 現實

理想和現實每每會出現矛盾,到實際應用的時候,這樣的設計就給咱們帶來了問題。若是對每一個 framework 進行編號,好比1到20,那麼咱們理想中是這樣的:

可是現實實際上是這樣的:

對比兩張圖的含義就是,實現中咱們各個App,使用的 framework 大致相同,咱們即使把業務拆的很細,若干個被拆分的 framework 其實還老是綁在一塊兒使用。而且,還給咱們維護帶來了巨大的問題,光每次打Git tag,都要折騰一會,會感受精力都花在了一塊兒輔助工做上。

優化

針對這個問題,咱們專門優化了 framework 的個數,將類似業務的 framework 進行了合併,最終 framework 的數量減小到了10個一下,組件之間的依賴圖變成這樣:

優化以後效果也很明顯,咱們對於各個framework的維護,變得簡單多了。

兩個彩蛋

另外在優化的過程,有兩個值得一提的是:

  1. 以前「信息流「和」推送「還存在環狀依賴的問題,就會致使當你想把 」推送「的framework合併到業務中心的時候,居然還得讓業務中心去依賴信息流,這個固然是沒法忍受的,解決辦法也比較經典,就是讓依賴下沉,把 Push 依賴的信息流的協議,放到了業務中心中。
  2. 此次的優化,實際上是將」鬆散「變成了」耦合「,和咱們平時常提到的觀點恰好相反,可是確實是咱們當前甚至從此一段時間內作因此我想說的是,」耦合「其實只是一個特徵,雖然大部分狀況是缺陷的特徵,可是當耦合成爲需求的時候,耦合就不是缺陷了。(有沒有一點在哪裏聽過的感受)

小結

咱們談」架構「的時候,說的最多的就是」取捨「,什麼叫」取捨「,就是說你不能很簡單的就判別出哪一個是好的,哪一個是很差的,老是以爲有點左右爲難。而如何取捨?業務就是很是重要的一個標杆,只有結合業務,才能判斷出哪一個是最適合本身的。咱們結合了業務,對本身的 framework 的數量進行了精簡,固然也可能會根據業務的變化,在將來某天,須要將現有的framework拆分的更細。

第二個案例:餓了麼移動APP的架構演進 —— 造成體系的認識

你作的項目,技術架構是怎麼樣的?

幾乎全部人在被面試或者面試別人的的時候,都會(被)問到這個問題,不少人會回答,咱們架構是MVC(MVVM),少數人還會使用MVP或者VIPER,咱們姑且都稱爲MV(X),可是真的架構僅僅就是MV(X)嗎?其實我以爲MV(X)雖然是架構中比較重要的部分,可是仍是遠遠不能說架構 = MV(X)。

爲何呢?帶着這個問題,咱們來看第二個例子,在這個案例中,咱們關注下面幾點:

  1. 架構是如何隨着業務的變化而變化的(這個也是對上面觀點的一個證明)。
  2. 咱們談到架構就提的 MV(X),處於架構中的哪一個部分。
  3. 經過」餓了麼「的架構演變,體會一下每一個階段的側重點是什麼,對於架構有一個體繫上的認識。

文章地址:

餓了麼移動APP的架構演進
https://www.jianshu.com/p/2141fb0dc62c

」餓了麼「的架構經歷了4個階段的演化:

  1. 第一階段 MVC
  2. 第二階段 Module Decoupled (組件化)
  3. 第三階段 Hybrid
  4. 第四階段 React-Native & Hot Patch

第一階段 MVC

這個古老而經典的模式,不用多說。它是一個軟件」從無到有「,」短平快「開發的首選。也是大部分規模比較小的 App 幾乎大部分時間精力都會與之打交道的一個架構,以致於人們提架構比彈MVC。

固然這個架構隨着業務的劇增,很快就會出現弊端,朝着Massive-View-Controller的方向奔去。

第二階段 Module Decoupled

隨着代碼量不斷增長,功能模塊愈來愈多,無論是分工開發協做,仍是已有模塊的複用和維護,組件化都成了這個階段的重點。組件化有個兩個關鍵:

  1. 如何劃分組件。
  2. 如何實現組件之間的通訊。

對於第一個問題,」餓了麼「採用的方案,基本是業界廣爲使用的分類方案,將組件分爲共有組件和業務組件,

  • 公共組件提供了一些業務無關的基礎服務:好比網絡庫、數據庫、JSONModel等
  • 業務組件則對應具體的一塊業務,好比登陸業務組件,訂單組件等

對於兩種組件的管理:

  • 對於公共組件,使用CocoaPods進行版本管理(這點和咱們目前不太同樣,由於咱們是SDK提供方,咱們引用的第三方庫,不肯定咱們的SDK使用方是否使用,是否更改源碼,因此咱們的方式,是將穩定版本的源碼,混淆後打包進咱們的代碼)。
  • 對於業務組件,這個和咱們大致相似,採起了業務模塊註冊機制的方式來達到解耦的目的,每一個業務模塊對外提供相應的業務接口,再啓動時向一箇中心註冊本身的Scheme(咱們是協議)。

而在具體某個業務組件內部,則能夠根據不一樣開發人員,不一樣隊伍的偏好,來實現不一樣的代碼架構,好比MVC、MVVM、MVP等,也都不會影響總體系統架構。

這時的架構圖,看上去長這樣:

咱們能夠看到,MV(X) 已經不是關注的所有了,不少模塊已經和 MV(X) 不怎麼搭邊了。

因此說,架構不等於 MV(X),其實 MV(X) 關注的只是」應用層「的部分

關於分層:
通常的,能夠將App分爲三層:應用層、service層、data access層。

  • 應用層 是直接和用戶打交道的部分,咱們經常使用到的 UIViewController,Android的 Activity,負責了數據的展現、流向、用戶交互的處理。
  • service 層 是在應用層的下面,爲應用層服務器的,對於應用層來講就像一個API調用延遲爲0ms的Server API。通常會放在應用層的代碼:網絡接口調用、公共系統服務API(GPS定位、隱私權限訪問)、一些 UTil 代碼(因此我以爲好比一個 UIViewController 的一些私有方法和一些提工具性質的category,其實應該算serveice 層)。
  • data access 提供和對於數據的」增刪改查「的接口層。

第三階段 Hybrid

業務的變化又來啦,當用戶規模達到比較大的數量,此次不只僅是功能的增長,每兩週一版已經知足不了產品、運營躁動的心了;同時,用純 Native 代碼編寫的 App,若是上線後有錯誤,只能等下一次提交市場。在現在互聯網競爭如此激烈的時代,一次線上錯誤有時也會帶來很大的影響。因此這時候,不少純粹展現性的模塊會使用 H5 的方式來實現。

可是這種方式也有它的弊端:

  • 每次加載頁面須要請求服務器,渲染時間比較長。
  • 調用本地硬件設備存在必定的不便。

對於這個問題,也有不少方案能夠權衡,好比能夠提早將網頁打包好,以減小網絡傳輸的時間,同時提供一系列的插件來訪問本地的硬件設備。

「餓了麼」這裏的作法是,綜合了 Native 和 H5 的優缺點,將頁面作了一個劃分,純粹展現性的模塊使用 H5;而更多的數據操做、動畫渲染性的模塊使用 Native。

架構圖長成這樣子:

業務再一次再架構的演化中扮演了重要的角色。

第四階段 React-Native & Hot Patch

又要頻繁迭代,又要用戶體驗,這時就考慮到了RN;另外,餓了麼這個階段用戶已通過億,線上一個小 bug 均可能影響幾萬人的使用,因此這個階段,重點在於 RN 模塊的引入,以及 Hot Patch 熱修復功能的引入。

在 RN 的使用方面,依然有一個取捨,要回答下面的問題:

  • 哪些頁面使用 RN,哪些頁面不用 RN。
  • 是整個模塊使用 RN,仍是一個模塊的部分頁面使用 RN。
  • RN 和 Native 頁面是2選1的關係,仍是說是一個備份。
  • RN 和 Native 頁面如何通訊。

「餓了麼」的作法是:對於20%最重要的頁面,作了一個 RN 的鏡像,也就是一個備份,而後經過服務器的配置,來切換Native 仍是 RN,這樣若是 Native 頁面出現問題的時候,先經過開關將線上的頁面切換成 RN,先保證線上正常使用,而後使用 Hot Patch 完成修補後,再切換回 Native App 原生頁面。

這時的架構圖:

不得不說,這種作法不必定適合別的團隊,畢竟一個頁面,要寫 Native 、 RN 兩套代碼,而且要一直維護,花的代價都有點大,不是每一個團隊都有精力去這麼搞的。其實這點,也正說明了,你須要根據本身業務,設計出一個最適合本身項目的架構。

小結

小結一下:

  1. 業務一直在影響架構的變遷。
  2. MV(X) 其實只是「應用層」的事,對於架構應該有個系統的認識。
  3. 架構的設計,並非有現成的拿來用就 OK 的事,還有不少細節的部分須要作取捨,依賴業務需求和經驗。

第三個案例:《猿題庫 iOS 客戶端架構設計》—— 好的架構具備哪些特質

第三個案例咱們迴歸 MV(X),畢竟它確實是咱們平常開發接觸比較多的一部分。

對了這個案例,想關注的「點」是

  1. MVC 和 MVVM 的優缺點。
  2. 如何可以規避缺點,結合優勢,改進架構,設計一個適合本身的MV(X)架構。
  3. 這個思想的底層原理是什麼,在別的場景下的設計可以通用。

文章地址:

猿題庫 iOS 客戶端架構設計
http://gracelancy.com/blog/2016/01/06/ape-ios-arch-design/

MVC

優勢:

  1. 易理解,對應現實生活中也是這樣的。
  2. 易上手,iOS、Android 默認就是個 MVC 的環境。

缺點:

  1. 當指責不是那麼明確,不知道該放哪時,代碼就會被放在"Controller"裏面吧,Controller愈來愈難維護。

其實對於上面這個缺點,唐巧也在一篇文章中寫道,這個問題其實也不能說是 MVC 的缺點,是咱們沒有拆分好代碼。能夠看看唐巧的《被誤解的 MVC 和被神化的 MVVM》,提出了一些如何解決 Controler 臃腫的解決辦法,而後也表達了對於 MVVM 的質疑,具體的作法能夠去讀這篇文章。這也正說明了你們對於架構的理解和態度真的是有區別的。

MVVM

具體關於MVVM的概念能夠參考 Objc 的《MVVM 介紹》,這裏就不具體說 MVVM 的概念了。

不瞭解MVVM的同窗,知道這幾點就行:

  1. MVVM將ViewController視做View。
  2. 關於 View Model,只須要知道兩件事:持有model;View能夠徹底經過一個View Model決定本身如何展現。
  3. View 和 View Model,View Model 和 Model之間經過數據綁定,使得 Model改變的時候,能同步更新 View Model,進而更新 View。

優勢:

  1. 減輕了 Controller 的負擔,拆分了代碼
  2. View Model有比較好的測試性。
  3. 結合 RAC, 能夠將數據和 View 通訊的代碼精簡到不多。

缺點:

  1. 上手成本高。
  2. 因爲使用數據綁定,界面的 bug 變的不易調試。
  3. ViewModel 接管了 ViewController 的大部分職責,慢慢也可能變的臃腫。

綜合二者

來看下 Lancy 的設計,是如何將二者綜合,規避缺點,保留優勢的,先上圖:

對於上圖的說明:

  • 一個View Controller 持有一個 Data Controller。
  • Data Controller,是數據管理模塊,負責數據的生命週期:獲取、保存、更新。
  • 一個 View Controller 裏面有多個 View,每一個 View 對應一個 View Model,這裏的 View Model 概念和 MVVM 裏的相似,惟一不一樣的是這裏的 View Model 和 Model ,沒有綁定機制。
  • View 的展現樣式,徹底決定於 View Model。

結合產品 UI,再按照數據流的方式闡述,如下面的 CollectionView 爲例。

  1. View Controller 持有 一個 Data Controller,初始化以後,調用 Data Controller 獲取用戶打開的課程。(1)
  2. Data Controller 經過 API 獲取數據,封裝成 Model 並返回 (2,3)
  3. View Controller 將2中返回的數據,生成 View Model,調用 View 的 bindDataWithViewModel 方法裝配給對應的 View。(4)
  4. View Controller 會調用 View 的渲染方法,View 經過 View model 直接進行渲染。(5)
  5. 若是有用戶事件,經過代理的方式,傳遞給 View Controller,讓View Controller 來決定下一步的處理。(6)

這麼方式的優缺點:

優勢:

  1. 指責分明,肯定給 Controller 肩負。
  2. 耦合度低,測試性高。指責分明帶來的效果就是耦合度低,同一個功能,能夠分別由不一樣的開發人員分別進行開發界面和邏輯,只須要確立好接口便可。
  3. 學習成本低,不用事件綁定,不須要學習 RAC。
  4. 易於調試 Bug,不使用綁定帶來的好處。

缺點:

  1. 當頁面的交互邏輯很是多時,須要頻繁的在 DC-VC-VM 裏來回傳遞信息,形成了大量膠水代碼。
  2. 沒有綁定,帶來額外的代碼(綁定真的是雙刃劍)

小結

針對這個案例,我以爲最應該咱們思考的就是,做者 Lancy,在設計架構的時候的思路是怎麼樣的?爲何要那麼設計?是怎麼取捨的?總結一下:

  1. 由於想讓團隊可以快速上手,以及bug能夠快速調試,因此沒有使用綁定機制。(從學習成本、開發成本、以調試角度)
  2. 依然保證了指責的明確劃分。(好的架構必定要明確劃分職責,甚至均衡的劃分)
  3. 方便測試依然是重要的一個設計標準。(好的架構要易於測試)
  4. 還有至關重要的一個標準——解耦(好的架構要易於維護,解耦意味着比較易於維護)
  5. 上面提到了缺點之一是「當頁面交互邏輯很是多時,會不太合適」,這也說明了,做者採用了這個架構,實際上是基於頁面交互不是不少的狀況(用戶交互確實帶來Model的改動不是不少,當前界面並不能修改用戶所開的課程)。因此業務依然是影響架構設計的總要因素。
  6. 還有一點不知道你們有沒有在乎,上面提到了「數據流」,對着這個架構咱們能清晰的說出「數據流」,這個我認爲也是一個好的架構應該具備的特性。數據流若是很模糊,有不少分支,那咱們的維護成本將大大增長,一個清晰的數據流,意味着你不管在這個流的那個節點繼續執行下需,都能獲得正確的結果。

基於對這個案例的分析,最應該思考的是,設計一個架構的思路,換言之,你要內心明白,怎樣纔是一個好的架構。

總結

總結一下,今天說的這三個案例,其實就是爲了說明一下幾點:

  1. 懂業務對於架構的重要性。
  2. 架構 != MV(X),站在更加宏觀的角度看問題,對於打開思路更有幫助。
  3. 當咱們設計架構的時候,怎樣纔是一個好的架構。

其實「架構」真的是個很大的話題,不少知識均可以拿出來單獨學習和分享。

  • 設計原則和設計模式(設計的基本功)
  • 數據結構和算法(設計的基本功)
  • MV(X)/Viper
  • 組件化 (光這個就特別多能夠講的)
  • 網絡層的架構設計(好比離散的仍是集約的)
  • 持久化層的設計
  • Hybrid 的設計
  • RN、Hot Patch
  • 無埋點
  • pod 私有庫維護 SDK
  • 面向過程/面向對象
  • AOP
  • 。。。。。

但願之後能陸續的爲你們分享,擅長哪一個方向,或者對哪一個方向感興趣的小夥伴也能夠給你們分享一下,讓你們的設計能力一點點提升上來。

參考

MVVM 介紹
https://objccn.io/issue-13-1/
被誤解的 MVC 和被神化的 MVVM
http://blog.devtang.com/2015/11/02/mvc-and-mvvm/
iOS應用架構談系列
https://casatwy.com/iosying-yong-jia-gou-tan-kai-pian.html
猿題庫 iOS 客戶端架構設計
http://gracelancy.com/blog/2016/01/06/ape-ios-arch-design/
餓了麼移動APP的架構演進
https://www.jianshu.com/p/2141fb0dc62c
iOS應用層架構之CDD
http://mrpeak.cn/blog/cdd/
iOS應用架構現狀分析
http://mrpeak.cn/blog/ios-arch/
iOS 架構模式–解密 MVC,MVP,MVVM以及VIPER架構
http://www.cocoachina.com/ios/20160108/14916.html

相關文章
相關標籤/搜索