(轉)iOS應用架構淺談

iOS應用架構淺談

緣由

   

從事iOS工作一年多了,主要從事QQ錢包SDK開發和財付通app維護,隨着對業務的慢慢熟悉,最近在思考這兩款應用架構設計的思想,剛好昨天在微信裏看了一篇iOS大牛對終端應用架構的分享,乘熱打鐵,下面淺談下我對ios應用架構設計的理解,寫的不好或不對的地方,歡迎大家拍磚,我們一起來探討。
假如問你一個iOS or Android app的架構,你會從哪些方面來說呢?
不要急着給出你的答案,可以先在你的腦子裏思考3分鐘,再看下面我要講的內容。

其實對於iOS客戶端應用的架構來說,複雜度不亞於服務端,但側重點和入手點卻跟服務端不太一樣。比如客戶端應用就不需要考慮類似服務端大併發量的問題,正常的app就根本不需要考慮。因爲我個人做Android的時間不長,如果你是Android開發者,你可以側重看我提出的一些架構思想,畢竟不管做什麼,思路是相通的,實現手段不同罷了。


當我們討論客戶端應用架構的時候,我們在討論什麼?


其實市面上大部分應用不外乎就是顛過來倒過去地做以下這些事情:

簡單來說就是調API,展示頁面,然後跳轉到別的地方再調API,再展示頁面。

App確實就是主要做這些事情,但是支撐這些事情的基礎,就是做架構要考慮的事情。

  • *調用網絡API

  • *頁面展示

  • *數據的本地持久化

  • *動態部署方案

上面這四大點,稍微細說一下就是:

  • 如何讓業務開發工程師方便安全地調用網絡API?然後儘可能保證用戶在各種網絡環境下都能有良好的體驗?

  • 頁面如何組織,才能儘可能降低業務方代碼的耦合度?儘可能降低業務方開發界面的複雜度,提高他們的效率?

  • 當數據有在本地存取的需求的時候,如何能夠保證數據在本地的合理安排?如何儘可能地減小性能消耗?

  • iOS應用有審覈週期,如何能夠通過不發版本的方式展示新的內容給用戶?如何修復緊急bug?

上面幾點是針對App說的,下面還有一些是針對團隊說的:

  • 收集用戶數據,給產品和運營提供參考

  • 合理地組織各業務方開發的業務模塊,以及相關基礎模塊

  • daily build 自動打包,提供給產品體驗,給測試觀測性能

所以當我們討論客戶端應用架構的時候,我們討論的差不多就是這些問題。

  

架構設計的方法 


所有事情最難的時候都是開始做的時候,當你開始着手設計並實現某一層的架構乃至整個app的架構的時候,很有可能會出現暫時的無從下手的情況。不管你採用什麼方法,全局觀、高度的代碼審美能力、靈活使用各種設計模式一定都是貫穿其中的。 

第一步:搞清楚要解決哪些問題,並找到解決這些問題的充要條件

  你必須得清楚你要做什麼,業務方希望要什麼。而不是爲了架構而架構,也不是爲了體驗新技術而改架構方案。以前是MVC,最近流行MVVM,如果過去的MVC是個好架構,沒什麼特別大的缺陷,就不要推倒然後搞成MVVM。

  搞清楚對於業務方而言的真正充要條件很重要!這決定了你的架構是否足夠易用。另外,傳的參數越少,耦合度相對而言就越小,你替換模塊或者升級模塊所花的的代價就越小。

第二步:問題分類,分模塊

  這個不用多說了吧。

第三步:搞清楚各問題之間的依賴關係,建立好模塊交流規範並設計模塊

   關鍵在於建立一套統一的交流規範。要注意的是,一定是建立一套統一的交流規範,不是兩套,不是多套。你要堅持你的價值觀,不要搖擺不定。要是搞出各種五花八門的規範出來,一方面有不切實際的炫技嫌疑,另一方面也會帶來後續維護的災難。

第四步:推演預測一下未來可能的走向,必要時添加新的模塊,記錄更多的基礎數據以備未來之需

  很多稱職的架構師都會在這時候考慮架構未來的走向,以及考慮做完這一輪架構之後,接下來要做的事情。一個好的架構雖然是功在當代利在千秋的工程,但絕對不是一個一勞永逸的工程。軟件是有生命的,你做出來的架構決定了這個軟件它這一生是坎坷還是幸福。

第五步:先解決依賴關係中最基礎的問題,實現基礎模塊,然後再用基礎模塊堆疊出整個架構

   這一步也是驗證你之前的設計是否合理的一步,隨着這一步的推進,你很有可能會遇到需要對架構進行調整的情況。這個階段一定要吹毛求疵高度負責地去開發,不要得過且過,發現架構有問題就及時調整。否則以後調整的成本就非常之大了。

第六步:打點,跑單元測試,跑性能測試,根據數據去優化對應的地方 

你得用這些數據去向你的leader邀功,你也得用這些數據去不斷調整你的架構。

總而言之就是要遵循這些原則:自頂向下設計(1,2,3,4步),自底向上實現(5),先測量,後優化(6)。

 

什麼樣的架構是好架構?

  1. 代碼整齊,分類明確

  2. 不用文檔,或很少文檔,就能讓業務方上手

  3. 思路和方法要統一,儘量不要多元

  4. 沒有橫向依賴,萬不得已不出現跨層訪問

  5. 對業務方該限制的地方有限制,該靈活的地方要給業務方創造靈活實現的條件

  6. 易測試,易拓展

  7. 保持一定量的超前性

  8. 接口少,接口參數少

  9. 高性能

 下面針對每一點詳細講解一下:

代碼整齊,分類明確,沒有common,沒有core

   代碼整齊是每一個工程師的基本素質,先不說你搞定這個問題的方案有多好,解決速度有多快,如果代碼不整齊,一切都白搭。因爲你的代碼是要給別人看的,你自己也要看。如果哪一天架構有修改,正好改到這個地方,你很容易自己都看不懂。另外,破窗理論提醒我們,如果代碼不整齊分類不明確,整個架構會隨着一次一次的拓展而越來越混亂。

  分類明確的字面意思大家一定都瞭解,但還有一個另外的意思,那就是:不要讓一個類或者一個模塊做兩種不同的事情。如果有類或某模塊做了兩種不同的事情,一方面不適合未來拓展,另一方面也會造成分類困難。

不用文檔,或很少文檔,就能讓業務方上手

  誰特麼會去看文檔啊,業務方他們已經被產品經理逼得很忙了。所以你要儘可能讓你的API名字可讀性強,對於iOS來說,objc這門語言的特性把這個做到了極致,函數名長就長一點,不要緊。

  好的函數名:

- (NSDictionary *)exifDataOfImage:(UIImage *)image atIndexPath:(NSIndexPath *)indexPath;

  壞的函數名:

- (id)exifData:(UIImage *)image position:(id)indexPath callback:(id<ErrorDelegate>)delegate;

 爲什麼壞?

1. 不要直接返回id或者傳入id,實在不行,用id<protocol>也比id好。如果連這個都做不到,你要好好考慮你的架構是不是有問題。
2. 要告知業務方要傳的東西是什麼,比如要傳Image,那就寫上ofImage。如果要傳位置,那就要寫上IndexPath,而不是用position這麼籠統的東西
3. 沒有任何理由要把delegate作爲參數傳進去,一定不會有任何情況不得不這麼做的。而且delegate這個參數根本不是這個函數要解決的問題的充要條件,如果你發現你不得不這麼做,那一定是架構有問題!

思路和方法要統一,儘量不要多元

   解決一個問題會有很多種方案,但是一旦確定了一種方案,就不要在另一個地方採用別的方案了。也就是做架構的時候,你得時刻記住當初你決定要處理這樣類型的問題的方案是什麼,以及你的初衷是什麼,不要搖擺不定。另外,你當初設立這個模塊一定是有想法有原因的,要記錄下你的解決思路,不要到時候換個地方你又靈光一現啥的,引入了其他方案,從而導致異構。

  要是一個框架裏面解決同一種類似的問題有各種五花八門的方法或者類,我覺得做這個架構的架構師一定是自己都沒想清楚就開始搞了。

 

沒有橫向依賴,萬不得已不出現跨層訪問

  沒有橫向依賴是很重要的,這決定了你將來要對這個架構做修補所需要的成本有多大。要做到沒有橫向依賴,這是很考驗架構師的模塊分類能力和是否熟悉業務的。

  跨層訪問是指數據流向了跟自己沒有對接關係的模塊。有的時候跨層訪問是不可避免的,比如網絡底層裏面信號從2G變成了3G變成了4G,這是有可能需要跨層通知到View的。但這種情況不多,一旦出現就要想盡一切辦法在本層搞定或者交給上層或者下層搞定,儘量不要出現跨層的情況。跨層訪問同樣也會增加耦合度,當某一層需要整體替換的時候,牽涉面就會很大。

對業務方該限制的地方有限制,該靈活的地方要給業務方創造靈活實現的條件

  把這點做好,很依賴於架構師的經驗。架構師必須要有能力區分哪些情況需要限制靈活性,哪些情況需要創造靈活性。比如對於Core Data技術棧來說,ManagedObject理論上是可以出現在任何地方的,那就意味着任何地方都可以修改ManagedObject,這就導致ManagedObjectContext在同步修改的時候把各種不同來源的修改同步進去。這時候就需要限制靈活性,只對外公開一個修改接口,不暴露任何ManagedObject在外面。

   如果是設計一個ABTest相關的API的時候,我們又希望增加它的靈活性。使得業務方不光可以通過Target-Action的模式實現ABtest,也要可以通過Block的方式實現ABTest,要儘可能滿足靈活性,減少業務方的使用成本。

易測試易拓展

  要實現易測試易拓展,那就要提高模塊化程度,儘可能減少依賴關係,便於mock。另外,如果是高度模塊化的架構,拓展起來將會是一件非常容易的事情。

保持一定量的超前性

  保持適度的技術上的超前性,能夠使得你的架構更新變得相對輕鬆。

  另外,這裏的超前性也不光是技術上的,還有產品上的。誰說架構師就不需要跟產品經理打交道了,沒事多跟產品經理聊聊天,聽聽他對產品未來走向的暢想,你就可以在合理的地方爲他的暢想留一條路子。

接口少,接口參數少

  越少的接口越少的參數,就能越降低業務方的使用成本。當然,充要條件還是要滿足的,如何在滿足充要條件的情況下儘可能地減少接口和參數數量。

高性能 

  爲什麼高性能排在最後一位?

  高性能非常重要,但是在客戶端架構中,它不是第一考慮因素。原因有下:

  • 客戶端業務變化非常之快,做架構時首要考慮因素應當是便於業務方快速滿足產品需求,因此需要儘可能提供簡單易用效果好的接口給業務方,而不是提供高性能的接口給業務方。

  • 蘋果平臺的性能非常之棒,正常情況下很少會出現由於性能不夠導致的用戶體驗問題。

  • 蘋果平臺的優化手段相對有限,甚至於有些時候即便動用了無所不用其極的手段乃至不擇手段犧牲了穩定性,性能提高很有可能也只不過是100ms到90ms的差距。10%的性能提升對於服務端來說很不錯了,因爲服務端動不動就是幾十萬上百萬的訪問量,幾十萬上百萬個10ms是很可觀的。但是對於客戶端的用戶來說,他無法感知這10ms的差別,如果從10s優化成9s用戶還是有一定感知的,但是100ms變90ms,我覺得吧,還是別折騰了。

  但是!不重要不代表用不着去做,關於性能優化這裏有很多學問,需要在工作中慢慢積累。

尾聲

    看了上面的內容,再問一遍自己假如問有一個iOS or Android app的架構,會從哪些方面來思考呢?

發佈了74 篇原創文章 · 獲贊 4 · 訪問量 12萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章