Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> Android資訊 >> Android 開發軟件架構思考以及經驗總結

Android 開發軟件架構思考以及經驗總結

編輯:Android資訊

一、萌芽

作為一只編程經驗並不怎麼豐富的程序猿來講,我一直覺得架構師是一個比較神秘的職業,架構設計就更加的高大上了。經過今年的幾個項目,之前曾發文敘述我的從MVC到MVP項目重構實戰經驗,也曾說過我准備對目前手底下的項目進行重構。但是,前段時間,我改變了我的想法。開發模式的重構,僅僅只是換了一個套路,也許在重構的過程中對業務的邏輯進行了一次梳理,也是在基於前人的代碼設計上進行了一些優化。但是,這遠遠還不夠,這不是我理想中的開發場景。在項目開發的過程中,也發現存在許多的問題,但是都是一些零散的問題,我很多時候希望能夠改變現狀,更加優雅地編程,然後實際的情況卻是陷入了迭代功能開發和bug修復的死循環。現在回過頭來想想,我理想中應該是開發應該是一種由規劃和設計指導的開發,那麼架構設計就顯的尤為重要了。

二、初識架構

1、閱讀《架構之美》之論架構

僅看完了《架構之美》的第一部分:論架構,對架構有了一個大概的認識。下圖是這部分的知識點概要:

書中很受啟發的概念:

  • 架構是一種折中,一種取捨。架構師要學會的就是平衡,質量與成本之間的平衡;
  • 架構師首先關注的不是系統的功能,而是滿足需求,滿足品質;
  • 架構設計要做的是讓關注點分離,並且對每個關注點進行設計一定的結構,該結構都有利於解答這一個關注點所定義的問題;
  • 好的架構應該是可以指導產品、開發、測試人員都對這一設計感到非常的舒適可靠,該設計覆蓋了所有該軟件系統相關利益的人員以及其中的關注點;
  • 只設計你知道需要的東西,多余的設計是一種浪費;
  • 架構幾乎影響了該系統相關的所有的人和事,決定了該軟件系統是否健康。

2、分析行業內各個APP的架構演進

這裡僅僅通過Google搜索各個app在架構演進方面的一些文章,從中分析他們為什麼要演進?怎麼演進?帶來了哪些好處?
簡單的整理如下:

(1)架構為什麼需要演進

  • 項目需求擴張,舊的架構不適應新的需求
  • 開發團隊人員增加,協作要求變高
  • 新技術引入
  • 更高的軟件質量要求

(2)他們是怎麼演進的

  • 餓了麼移動APP的架構演進 2016-01-20
    • 模塊解耦
      • 共有組件
      • 業務組件
    • Excalibur映射系統,注冊機制
    • 引入Hybrid框架
    • React-Native & Hot Patch
  • 攜程移動App架構優化之旅 2016-04-07
    • 工程結構調整、業務之前解耦,產品間相互獨立,頁面跳轉使用事件總線或者URL總線方式
    • 統一基礎功能業務組件,SDK化
    • 性能數據采集、監控
    • Native的插件化和HotFix
  • 糯米移動組件架構演進之路 2016-05-24
    • 組件化
    • 統一服務入口
    • Hybrid框架優化
  • 蘇寧11.11:蘇寧易購移動端的架構優化實踐 2016-11-11
    • 分層解耦,解決縱向解耦
    • 中介型引用結構(protocol和url方式),橫向解耦
    • H5容器優化
    • 網絡鏈路優化
    • 移動App性能監控系統

(3)帶來的好處

  • 進行了模塊化的解耦,產品相對獨立,應對需求變化、技術更新更加靈活,團隊協作更加方便,並減少了許多是無用功,也給團隊留下了一些技術積累;
  • 進行了必要的統一規范,組織結構更加清晰,系統更加健康;
  • 引入了新的技術框架,,產品獲得更好的體驗;
  • 進行了系統的優化工作,軟件的品質更高,體驗更好;

3、Google搜索關鍵字:架構設計

搜索引擎對於我們來說是最棒的學習工具,我通過搜索架構設計等關鍵字,閱讀了一些文章,並仔細研讀Keegan小鋼的博客文章《小鋼的架構思考》系列。這幾篇文章在發表之初曾閱讀過,但是當時並不怎麼理解,大概是對架構還沒有一個大概的認識。在請教一位前輩的時候,他和說了對架構的一個理解,並再次推薦了這幾篇文章。所以我再次閱讀了好幾遍。下圖是文中關於架構設計的知識概要。

(1)知識概要

(2)個人小結

架構分為三個階段:規劃、設計、構建,每個階段架構的設計有不同職能。在規劃階段,考慮的是產品的需求、質量的需求,技術的可行性分析以及預研。在設計階段,考慮的如果將一個復雜的系統拆分,並設計如何進行組織這些拆分的模塊。在構建階段,考慮的就是具體的實施問題,並且要保證一定的伸縮擴展性,因為架構是不斷演進的。文中引用了《軟件架構設計》一書的一個模型圖,我覺得有必要在此貼出來。最近也在思考軟件模塊化的設計,模塊化的設計也許各有理解,在此先不做討論。如下圖:

這張圖我起初理解不是很透徹,我曾嘗試自己去畫一些圖來表達我的一些想法。但是,當我再次回過頭看到這張圖的時候,才恍然大悟。
架構的設計可以從兩個維度來考慮,一是架構思維,二是架構原則。思維是我們的思考方式,是我們解決問題的方法。原則是我們思考問題的方向,是我們解決問題的一些標准。

三、架構的定義

對於架構的定義,業界都各有看法,也曾微信私信請教過一些行業內有豐富經驗的前輩。《軟件架構設計》一書則將架構定義總結為組成派和決策派:

  • 組成派:架構=組件+交互:軟件系統的架構將系統描述為計算組件及組件之間的交互。
  • 決策派:架構=重要決策集:軟件架構是在一些重要方面所作出的決策的集合。

keegan小鋼在《小鋼的架構思考:什麼是架構》文中提到:軟件架構是規劃、設計和構建軟件的過程和結果。《架構之美》一書在1.1.3架構的含義中提出:架構說明了設計和構建一個系統所使用的結構。《Software Architecture in Practice,Second Edition》中提出:一個程序或計算機的軟件架構是系統的一種結構或一組結構,它包含軟件元素、這些元素的外部可見的屬性,以及元素之間的關系。

本人並沒有經歷過大型的軟件系統,做過的也只是移動端App的開發,所以個人也只敢從移動端app的架構設計出發,給出我一個狹義的理解。我認為,移動端的app架構是一種基於產品和技術的進行統籌管理最終所形成的共識。可能大部分的app開發尤其是小團隊app的開發大多是由產品驅動的開發,需求來了,那就技術實現。需求變了,那就改。畢竟,應用層的開發是對業務負責的,必須保證正常的發布。所以大多數的情況下,程序猿不得不在產品經理面前妥協,這樣對於開發人員的工作就會變的很被動。所以,就出現了程序猿和產品狗的撕逼笑談。這種現象的原因在於項目各個相關利益人員沒有對產品和技術達成共識,這正是移動端架構設計所要解決的問題。

四、產品

產品,是我們產品經理們設計的結果,也是開發人員開發的最終成果,是前後兩種人群的共同目標。作為軟件的架構設計者應該充分理解產品的設計理念,除了明白已經設計的功能業務,還得具有一定的預見,掌握產品的發展趨勢。下面主要從開發的角度來談一談產品。

1、產品設計(做什麼)

作為一名開發人員,我不能很專業的來談產品的設計,但是這裡我還是希望以一個開發人員的角度來講產品設計。什麼是產品設計,我覺得可以從以下幾個方面來思考。

(1)、用戶群體(什麼人用)

顧名思義,我們設計開發出來的產品最終是讓人用的。所以首先我們得定位產品的用戶是誰?用戶群體代表了我們產品的市場。所以產品做的好不好,最終市場說了算,用戶說了算。離開了用戶,不理解用戶,不注重用戶的體驗,一切都是無用功。

(2)、核心理念(要做什麼)

你知道你最每天累死累活一行一行敲出來的是什麼樣的產品嗎?可能對於我們開發人員很容易陷入到一個版本一個版本的迭代當中,這些永無止境的工作叫人忘記了思考,忘記了問下產品人員,我們最終是要做的什麼?一年後我們的產品將是個什麼樣的狀態,我們的最終願景是什麼?我們將會怎麼一步步去實現我們最終的願景?可能你會說,這些和我開發有什麼關系。接到需求,我把他開發出來實現不就ok了。然而,在我們的小組裡不乏有這些怨言,產品人員不斷的修改,我TM代碼改過來改過去。我們的leader在這方面很強調我們開發人員應該擁有自己的主動權,可以反駁產品不合理的設計。但是,前提是你至少理解產品的核心理念,我們最終要做什麼。

2、迭代計劃(計劃怎麼做)

對於一個產品,用戶的需求是很多的,而且隨著時間不斷改變的。需求可以分兩種,一種是人性本能的需求,還有一種,是我們的產品催生的需求。這兩種需求都是合理的,也正是我們需要滿足用戶的。對於各式各樣的需求我們怎麼有計劃的去實現呢?在敏捷開發中,我們將這些需求放到一個“需求池”中,然後進行計劃安排在不同版本的迭代中。這個工作,不僅是產品人員去決定,開發人員也應該起一定的決策作用。產品人員需要從產品的角度去考慮,開發人員需要從技術實現的角度去考慮,最終的計劃應該是兩者的共同決策。特別注意的是,根據產品的特性,技術人員也應該提出技術方面的需求。合理的迭代計劃可以保證正常的開發節奏,完成迭代目標。

3、開發資源(用什麼做)

(1)、開發團隊配置(人)

在《人件》一書中提到了軟件開發中人的因素很重要,合理配置開發團隊是非常重要的。一個App的開發團隊至少需要5個角色,即產品、交互、UI、軟件、測試。不同角色也分不同的層次,比如軟件分初級、中級、高級。不同角色、不同層次合理搭配,才能夠獲得更高的工作效率,保證產品開發順利進行。

(2)、數據內容配置(物)

產品最終呈現給用戶的是數據,數據分兩種。一種是私有的數據,是由開發商自己生產的數據。一種是平台自生的數據,是由用戶生產的。如果是自己生產的數據,就得考慮數據來源,數據的覆蓋率,數據的准確性,合法性等。如果是用戶生產數據,就得考慮用戶生產數據的動力、入口以及數據安全性、傳播性等。

(3)、開發投入預算(錢)

萬事俱備,只欠東風。完成一款app開發,需要一支專業的開發團隊,這裡的人力成本也是很高的。當然我這裡只談開發的預算,至於運營就不說了。我們得考慮,開發周期多長、需要多少人、後期維護怎麼辦。比如一個APP需要5個人開發,2個月的時間,開發兩個版本,按照每人1W的工資來計算的話,也需要 10W。這估計是最低級別的算法了。所以,如果是創業公司,我們在組建開發團隊的時候,也得看看預算是多少,多少錢能辦多大事,當然如果是那些拿到投資無所謂的老板來時得另算了,不過今年死的太多的公司以前都是大手筆。錢燒完了,也就沒有了。如果是大公司,可能不帶這麼摳門的。不過也應該去考慮,開發團隊會消耗公司多少資源,我們能否獲得相應或者更高的產出。

(4)、第三方資源

目前的開發而言,很多資源是可以尋找第三方合作的。比如,服務器、雲存儲、支付接口、登錄接口、內容數據以及開發過程中的一些開源框架等等。我們需要選擇、商務談判直到集成到自己的APP中。

4、產品質量(做的怎麼樣)

(1)、用戶體驗

現在對於我們來說,用戶體驗是一個說爛了的詞。那是因為,用戶體驗真的很重要,決定了一個產品的成敗。產品開發完成後,最終到達用戶的手中。產品好不好,用戶說了算。哪些因素影響到用戶體驗呢?我想大概可以從5個角色各自的職責出發來看,產品的設計是否直達用戶痛點?交互是否符合人的喜好、習慣,UI是否讓用戶覺得舒適?軟件的性能好不好?軟件的缺陷是否多不多?

(2)、軟件性能

從技術的角度來講,我們可以通過軟件的性能來分析一個軟件產品的質量。今年許多的技術文章都在談性能優化,軟件的性能主要從軟件的啟動速度、流暢度、內存、功耗、流量、apk體積等幾個方面來評判。如果想做好一個應用,性能優化應該納入到日常的開發中持續進行。具體如何優化,這裡就不再多說了。

(3)、產品安全

產品的安全性可以從兩個角度來看,產品的生產商和產品的最終用戶。對於生產商而言,有許多的內容是需要受到法律保護的,有許多的敏感信息,核心技術、網絡接口等是不可以洩露的。對於用戶而言,我們肯定在本地或者服務器存儲了大量的用戶信息,比如賬號密碼,一些信息一旦洩露將嚴重傷害到用戶的個人利益。所以,為了保護自己以及用戶利益,我們必須要生產一個安全可靠的產品。那麼對於一個應用端的開發者而言,我們的編譯出的apk最終會到用戶手中。所以,我們需要通過代碼混淆、數據加密、權限限制等一些技術手段來保護我們的應用。

(4)、質量評測

一個應用做的好不好,我認為可以主要從上述用戶體驗、軟件性能、產品安全三個維度來進行評判。那麼,我們該如何組織這些評判工作呢?我們有在進行這些工作嗎?就目前而言,我相信大多數的產品、開發、測試人員都或多或少的參與到這些工作當中,但是也許沒有將一些數據量化、沒有系統的組織這些工作。目前大部分的應用都集成了行為采集,產品的下載量、用戶的活躍度等也都是體現產品用戶體驗的主要參數。開發團隊內部一直在進行性能優化的工作,比如異常修復、bug修復、內容洩露,過度繪制,apk瘦身。我們也進行了代碼混淆、數據加密、apk簽名加密的工作。但是,你知道你的產品質量如何嗎?相比同類產品來,你哪些做的好,哪些做的不好嗎?所以,我覺得將上述這些零碎的工作有系統的組織起來,將一些影響因素進行量化,讓我們更加清楚的了解我們的產品質量是一件非常有意義的事情。

5、風險規避

(1)、人力變動風險

人是善變的,尤其對於IT來說,人員的流動就更加的頻繁了,公司內部的調整,員工跳槽等等。所以,對於一直開發團隊,必須要考慮到人員變動的風險。如果,某某不在了,項目是否可以正常運行。開發團隊之間是否能夠交叉熟悉各自之間的業務。

(2)、上層決策風險

是否經歷過一個項目做到一大半業務被停掉了的情況?而這個時候,你做的是個半吊子。如果出現了這種情況,我們該怎麼辦?假設就在剛才你的老板說你現在的項目不做了,那麼如何才能最大程度的挽回損失?如何進行項目的收尾工作?而不至於在項目又突然重啟的時候接收的是一個爛攤子。

(3)、項目延期風險

我們在項目開發的時候會進行評審,然後按照迭代計劃開發,但是在開發過程中一定會有許多問題影響我們的預期,比如需求變動、技術難題等等。項目延期在軟件項目的開發中是普遍存在的問題,對於某些迭代而言,可能並不對整個項目造成重大影響,但是這個問題是一定需要考慮的。並且,我們應該嚴格的掌控項目的進度,平衡這些問題,保證能夠按時交付產品。

(4)、軟件缺陷風險

我們應該隨時能夠提供一個穩定的版本,這是我們的leader所要求的。軟件的缺陷存在是正常的,我們不停的寫bug,也在不停的修改bug,對於那些隱藏很深的bug也許沒有讓測試測出來,最後流通到用戶的手中,這個時候我們如何完成緊急修復?如何快速響應能給到用戶一個穩定可靠的版本。這些是我們需要考慮的,任何時候,都應該有PlanB。

(5)、人為失誤風險

前段時間,公司內由於操作失誤,上架更新一個apk的時候不小心發錯了機型,導致使用該機型的用戶升級後程序無法使用。然後,由於這個機型缺少維護,找不到代碼,僅僅只能找到一個apk文件,然後只能考慮反編譯升級等等。我想,類似於這類的人為失誤還有很多,比如代碼提交錯誤,集成路徑出錯等等。人總有一不小心的時候,所以,我們在設計的時候,應該將這些因素考慮進去,如何在出現失誤的時候主動警告,如何在用戶錯誤已經發生的時候啟動緊急方案,將不良影響降到最低。

6、產品交付

(1)、測試版本

在敏捷迭代開發中,我們基本上能夠一周提交兩個測試版本。我們開發一部分、修復一部分,都可以提交一個可測試的版本,這樣可以最大程度的降低開發風險,有利於軟件的穩定性。

(2)、灰度機制

如果你產品的用戶量夠大,這個時候發布新的版本就得慎重考慮,用戶才是你的產品的檢驗員。目前基本都是使用灰度發布的策略,先給少量的用戶發布,看看用戶的反饋,而後逐步發布給所有用戶。

(3)、版本管理

我們在開發過程中有許多的版本,也有很多分法。如debug和release版本,有的時候還需要給內容提供測試數據的data版本,還有的時候上一個版本還沒有正式發布我們就需要開發下一個版本的功能。我們如何去管理各個版本的代碼以及如何通過版本名來區分這些版本?我們需要制定一定的管理規范,並且這一規范是否在開發團隊中達成共識,就顯得非常重要。

五、技術開發

前面啰嗦了很多,終於寫到這裡了。對於一個開發人員來說,怎麼做才是我們的關鍵問題所在。只會Android開發,所以以下只討論Android。我主要從以下幾個方面來談一談怎麼做這個問題。

1、技術選型

(1)、 開發平台

移動端的開發目前主要是兩大陣營Android、iOS,其他的就不多說了。

(2)、 開發工具

  • 編譯工具:Eclipse&Ant、AndroidStudio&Gradle,作為Android開發者,目前毫無疑問應該選擇AndroidStudio&Gradle;
  • 代碼倉庫:Git 、SVN ,工具有海龜、AndroidStudio也集成了VCS;
  • Maven倉庫:可以使用nexus創建自己的maven私服;
  • 持續集成:Jinkens、Buildbot、Travis CI、Strider、Integrity;

(3)、 開發語言

Java、Kotin、Grovvy、SQL等等;

(4)、 開發模式

MVC、MVP、MVVM、clean等,各有優缺點,在此不做詳細說明;

(5)、 開源框架

都說了不要重復造輪子,因為你造的輪子不一定不人家的好用,對於我們開發者而言,有一件非常好的事情就是我們有太多的開源免費的第三方庫供我們使用,這樣給我們省去了大量的工作,做到更加高效的開發。但是,如何選擇,是否引入使我們需要考慮的一個問題。下面列出一些常用的第三方庫,更多請點擊。

  • 網絡:OKHttp、 android-asyn-http、 volley、 Retrofit
  • 事件總線:otto、 EventBus
  • 依賴注入:Dagger、 RoboGuice、 ButterKnife
  • 圖片:Fresco、Glide、 Picasso
  • 數據庫:GreenDao、 Ormlite、LitePal
  • Json解析: Gson、Jackson、 FastJson
  • 響應式編程: RxJava、 RxAndroid
  • 異常統計平台:騰訊Bugly、Crashlytics
  • 性能優化: blockcanary、 leakcanary

(6)、 新興技術

軟件開發而言,新技術的發展相當迅速,然而我們實際落地到項目中卻需要很長的時間,因為新的技術剛出來一是需要學習成本,二是需要承擔新技術不夠成熟,存在缺陷帶來的一些風險。當然,我們應該積極的引入好的新的東西,跟得上時代的步伐才好。下面列舉的一些也許都算不上新的東西,但是也是近年來大家所追捧的新技術。

  • AndroidSupport:DataBinding、MaterialDesign等;
  • 混合開發:ReactNative、Hybrid、Weex等;
  • 編程語言:Java8、Kotlin;
  • 熱修復:AndFix、HotFix、Tinker等;
  • 構建:InstantRun、Freeline

2、業務拆分

我們在進行業務拆分的時候,我認為可以將業務分成三類:

(1)、常用基礎業務

基礎業務主要是我們的app的一些基礎功能,像我們公司有BFC團隊給我們開發了文件上傳下載、網絡請求、行為采集、賬號系統等SDK,免除我們一些重復的勞動工作。怎麼去定義什麼業務才是基礎業務呢?我覺得可以這麼去區分。如果你的業務在行業普通的應用app都有需要,那麼這些這些就是具有普遍適用性的基礎業務。我們根據不同的功能進行拆分。

(2)、通用技術業務

通用技術業務我覺得是和自己app相關並且有技術性很強的業務,可能是你應用的核心技術部分,比如美顏這一類軟件的圖片處理,小猿搜題這類的圖片識別等就是一項通用技術型業務。通用技術業務的特點就是在和你同一類的app都會有需要使用的技術,我們可以根據不同的技術領域進行拆分。

(3)、特定功能業務

特定功能業務就是屬於你自己app的特定功能了,一般可以按照功能進行拆分成不同模塊。比如說我目前的一鍵搜(類似於小猿搜題)主要有搜題、查單詞、翻譯三大功能。那麼就可以分拆為三大塊。搜題要經過拍照、框題、圖片處理、網絡請求等步驟,每個步驟都可以看成一塊小業務,以此進行拆分。特定功能業務大部分僅適用於你自身的APP。

以上的說法僅從自身的經驗出發來進行描述,在我們實際的開發中可能會有一些特殊情況,或者有不同的拆分分方法。總之,業務的拆分還需要根據實際情況來。

3、架構設計(關注點分離、抽象)

(1)、核心概念

關注點分離

世上本沒有架構,關注點一分離就有了架構,我們將一個軟件系統的開發從多個維度將我們的工作進行拆分,對於每個領域進行設計,將各個領域有系統的組織起來,這種組織結構就是架構。然而如何將一個復雜的系統將關注點進行合理的分離,這個是非常有挑戰的。

抽象

抽象,這是在請教一位前輩時最後給我強調的一點。如果你對app是跟著交互走、一個頁面一個頁面寫的,那麼很顯然,你沒有對你的業務進行抽象,而只是在實現。作為java的設計思想也很強調抽象的概念。那抽象到底是什麼呢?抽象就是你要做什麼!更簡單的理解就是,寫interface而不是class。不知道大家有沒有這樣的經歷,在我們的MVP的開發當中,我們有個Model,也有一個IModel,但是我們寫完了Model才知道怎麼寫IModel,最後成了粘貼復制的體力勞動。如果你是這麼做的,你可以自己思考下,假如我們先寫是IModel,而不是Model,那就是怎麼樣的體驗呢?這就是將你的業務進行抽象。在架構的設計當中,你只需要知道你要做些什麼?而不需要去過多的關注你具體怎麼去實現它,這才是設計。

(2)、設計思維

面向過程(Procedure Oriented)

眾所周知,在C語言的開發中,我們的邏輯大多是根據任務的流程走。這是面向過程的典型例子。面向過程關注的是工作的流程、一步一步的完成任務。

面向對象(Object Oriented)

Java語言作為面向對象開發的典型代表,這是我們所熟知的。我們將計算機按照人的思維來進行設計,每一個對象都持有自己的屬性,並且持有自己的操作方法。對象之間有繼承,組合等關系,通過組織這些關系來完成我們的程序。就像社會的人和物一樣,人與人之間各種復雜的關系組合完成了社會各項活動的運轉。

面向切面 (Aspect-Oriented)

面向切面是為彌補面向對象中的一些缺陷而生的,我們將某些功能封裝到一起,提供對外的接口,方便在任何地方調用。就如SharedPreferences, Json, Xml, File, Device, System, Log, 格式轉換等,這些通常會在until包裡邊。它就相當於一個橫截面,我們可以隨時面向這個橫截面完成操作,而自己的邏輯裡邊不再需要重復的設計。

面向服務

面向服務是將系統進行拆分,分成一個個獨立的程序或組件,並對外提供某一項服務。每項服務之間通過某種協議進行通信,並進行分開部署,如HTTP,從而達到松耦合的目的。

以上四種思維重點在於看待問題的角度不同,不同的角度解決問題的方案就不一樣,當然各種角度各有優劣。那麼對於在android開發中是否都只是按照OOP原則來設計呢?很顯然不是。面對不同的需求,不同的場景,我們需要及時調整自己的思維,靈活運用,尋找最適合的角度,拿出最優的設計方案,這才是我們所追求的。

(3)、設計原則

高內聚

怎麼理解高內聚?我認為我們在拆分時某一細分領域只完成單一的功能,其內部的事情自己處理。從表面來看比如一個model的class,對外提供了一個接口,那麼他有一個輸入,一個輸出。單獨看這個接口而言,它是高內聚的。當然,其內部的組織結構有可能千差萬別,所以內聚的形式又各有不同。所以我們將他們分類為功能內聚、順序內聚、時間內聚等等。

低耦合

耦合指的是模塊之間存在依賴關系,關系相互依賴就會相互制衡,這是必然的。所以,如果耦合度太高的話,將會導致牽一發而動全身的後果,這個使我們不想看到的,也極大的影響的程序版本的迭代以及bug的修復。根據依賴關系的不同,我們分為了非直接耦合、數據耦合、內容耦合、開關耦合、控制耦合、外部耦合等等。我們要完成一個系統的開發,必須要將各個模塊有效的組織起來,這種組織關系便無法避免存在了耦合,我們要做的是盡量減少這些依賴關系,尤其避免交叉依賴,將耦合度降低到最低,把我們的程序設計的更加的靈活。

適度設計

我們在設計的時候如果考慮不周,那麼設計不夠,不能滿足現有或者可預知的需求,從發展的眼光來看,會導致後期的開發中出現很多的問題。如果想的太多,很容易進行過度的設計,從而將一個簡單的系統設計的很復雜,那麼就給當前的開發將增加了許多無意義的工作,降低了開發效率。那麼怎樣的設計才是合理的設計呢?我認為能夠同時滿足現有的需求和可預知的需求,並且面對架構的調整時能夠很方便的進行擴展。這樣的設計,是非常好的設計。如何才能達到這樣的效果呢?我個人覺得在對系統進行設計時,關注點分離的顆粒度需要把握好,系統不過就是將不同單一小模塊進行組織而已,那麼這些細小的模塊就是架構設計的基礎,這就好比建房的那些磚頭。這些磚頭是什麼呢?他麼可以是是一個對外提供接口的公共方法,也可以是私有的內部方法,也可以是某某持用的成員變量。當然往大裡看,他可以是某一個功能模塊。在上述行業內各個app的架構演進中,都很強調進行模塊化的改造。所以,分離好你的系統,才能夠靈活的組織起來,以不變應萬變。

(4)、設計方案

指導模型下圖在文中已經提到,這裡再次引入,因為這張圖對我的啟發真的很大,也表達出了我心之所想。面對一個復雜的系統,我們怎麼樣去分離,怎麼樣去組織,我認為這張圖已經傳達出了其中的精髓,所以我認為這是架構設計的指導模型,無論你是什麼MVC、MVP、MVVM之類的,都可以從中去理解。

模型分解

根據實踐開發中個人的理解,我將此圖再次進行了簡化如下:

橫向分塊

根據上圖的簡化模型,我們可以這麼理解,在橫向我們根據業務功能進行模塊劃分。比如主題商店,我們可以分為壁紙、鈴聲等等模塊,每個模塊間解耦。同時,在每一層的業務間再次進行分塊,比如壁紙在數據層就有圖片的請求、加載、緩存、裁剪處理等等。

縱向分層

接下來我們在對每個模塊的業務根據職責分為展現層、業務層、數據層。數據層主要負責數據的獲取、封裝等工作,業務層主要更加上層的需要調配各數據層最終將數據返回給展現層,展現層的工作就是將數據展現在UI界面上,並且響應人的各種指令切換UI,操作新的數據。

接口通信

在橫向來看,我們將業務進行了分塊,保證塊與塊之間相互之間沒有任何依賴,保證了絕對的解耦。從縱向來看,每個層級之間的依賴很明顯是無法避免的,所以我們可以保證上層僅依賴下層的接口,從而達到降低其耦合度的目的。

如上圖所示,通過上述橫向分塊、縱向分層、接口通信這三大步驟之後,我們可以將一個系統進行了很好的分解,並得到一個理想模型。當然,這是一個理想的模型。在我們的實際開發中可能無法避免一些交叉等特殊情況,我們還需要從實際情況出發。但是有一點,我們可以保證接口的分離,已達到更低的耦合度的目的。

統一管理

統一管理,是對於我們的設計中有一些東西是需要統一管理起來的。通過上述原則,我們將一個復雜的系統進行了拆解,已達到架構設計中將關注點分離的目的。然而在實際的開發中,我們除了要進行業務的分拆,也需要對某些業務進行統一的管理。比如說一些模式的開關管理,比如說我們在進行網絡請求時需要在測試環境和正式環境之間的切換,我們可以將這些模式切換的開關放到一個地方,方便我們進行管理,而不要去到各個地方去修改。再比如說我們的請求url地址,是否可以寫到一起進行統一的管理。還有在某些應用中會通過一個中間人來進行統一管理數據的流通、頁面的跳轉,這也是一個可以嘗試的方案,詳細請看蘇寧易購移動端的架構優化實踐文中提到的模塊管理器、Url跳轉管理器。統一管理的意思就是將分拆的某一類小的模塊某一些特性放到某一處進行統一的管理。但是這樣會存在一個問題,比如前面舉例說到的統一開關管理,這造成了開關耦合,如何去避免呢?我覺得可以將開關默認寫到自己的模塊裡邊,並公開出修改的接口,方便上層進行統一的修改,以達到統一管理的目的。這樣的話,即使這個模塊拆離出來,也不會受到影響。但是,這樣的話,其安全性受到了一定的影響。架構設計總是這樣,你總需要選擇一個折中適合自己的方案。

我們通過上述橫向分塊、縱向分層的方法將一個系統切成不同的小塊,這些小塊負責某一單一的職責,然後通過接口將塊與塊之間進行了間接性的連接,依賴的是接口而不是實例,以弱化這種模塊間通信造成的耦合。當然,上述模型僅僅只是一個理想狀態的模型,如果是一個非常復雜的系統,那麼層級之間也能拆分出更多的層級。比如,在數據層,我們在MVP模式的開發下使用Model來完成,當Model層的業務變得非常復雜時,有部分人會考慮拆分出Data層放在最底層,最為最基礎的數據操作等。最後,為了方便我們對模塊進行組合並進行管理,我們可以考慮在小模塊中開放出接口,供上層進行統一的控制管理。最後,我想說的時,我們在進行業務分離拆解時可以考慮按照上述的方案來做,最終還得根據實際情況來進行設計。

4、開發實現

當完成我們的設計工作後,我們進入了開發編碼階段,在這個階段主要表達我們的設計,並最終取得實實在在的成果。當進入這個階段之前,我們的設計不能僅僅是一份文檔,而應該是開發人員和架構設計者達成的某種共識。再好的設計,也需要獲得良好的表達和實現。下面主要談一談在實現過程中需要考慮的問題。

(1)、項目分包

項目的分包結構體現一個軟件的架構,我們在進行分包的時候總有一種困惑。因為我們存在多種分法,比如我們可以分為根據類的功能分為activity、fragment、adapter、util等,有的時候,我們又根據功能模塊分,比如一鍵搜中有查單詞模塊、有搜題模塊,同時又存在網絡請求,軟件升級等小的外圍通用功能模塊。存在的問題就是模塊之間又存在一些可以復用的東西,那麼我們進行拆分明顯出現了代碼的冗余。如果按照兩種方案同時分,那就肯定存在了架構的混亂。我們該如何達到這兩種的平衡?我認為,這個也需要更加項目的大小而來,如果是非常小的項目,也不存業務擴展的可能,我們就可以采用上述的第一種方案,簡單的分類就好。但是,對於較大的項目,我建議使用第二種方案。下面,我簡單列一個模型僅供參考:

+ app
    +main
        +com.jfg
            +common //常用基礎業務
                +util
                +wedget
                +base
            +function //通用技術業務
                +camera
                +sensor
            +moudule //特定功能業務
                +mouduleA
                    +model
                    +presenter
                    +view
                +mouduleB
                    +model
                    +presenter
                    +view
                +mouduleC
            +demo //主程序
                +app
                +activity

如上所示,我們根據開始的項目業務拆分分包如上,將常用的基礎業務放到common包裡邊,這個包在大多數情況是不變的,並且為app提供基礎性的服務,不過我們盡量不要放到這個common包裡邊,如果這個common包變得足夠大的時候,就一定要思考是不是該拆分了。因為common給人的感覺就是什麼都是,那就讓我們無法快速認知這個包所擔當的職責。我們可以這樣理解,common包是面向切面而設計的一些業務,但也不是絕對的。接下來我們先聊module這個包,實際這裡是將業務進行了模塊化的分拆,如上我們拆分出了moudleA和moudleB,這兩者之間要求沒有任何的聯系。但是,我們會存在一個問題,那就是moudleA和moudleB某些業務是一樣的,我們拆開顯得重復了許多體力活。這應該是大多數開發者面對的困擾,這種該怎麼去平衡呢?我是這麼考慮的。如果,moudle和moudleB存在重疊的業務,我們將這些業務提取到function包或者common包中,這樣降低了業務的層級。我們允許moudle包的各模塊業務依賴於function和common為我們提供的基礎服務。為了更好的區分模塊A和模塊B雖然重疊但在邏輯上是各自屬於各自的,我們有兩種方法來做。第一種是將兩種業務進行一定的抽象,實現的過程還是放到各個moudle業務中。第二種方案定義兩個接口類,各自定義各自的接口。在具體的實現類中實現了這兩個接口類的方法,內部在進行相同的邏輯操作。這樣,對外看來,邏輯上moudleA和moduleB是分離的。總之,如何分包還得權衡利弊,盡量以一種思維來進行劃分,以避免設計混亂。

(2)、抽象接口

如果說在架構設計中抽象很重要,你可能有些迷糊,但是如果要你先寫interface或者abstract class 而不是class時,你就可能感覺得到抽象的意義。我們將一個系統分解成幾個大的模塊,一個模塊查分成不同的層級,每個層級再次拆分成不同的細節業務。最後,我們很清晰的知道我們要完成某一項功能需要做哪些事?對的,做哪些事就就是一個個接口,我們在編碼時先寫接口再寫實現有利於幫助我們對業務進行拆分和抽象。我們都知道做一件事情一般情況都需要提供一些條件,做完了會有返回結果。這些都可以在接口的設計中完成。我們需要注意是一個接口只做一件事情,如果有兩件事非常相似也要盡量拆分而不是合並。在接口命名方面做到見名知意,怎麼去評判,就是如果你的接口沒有注釋也同樣能讓人知道你的接口是做什麼的就好。

(3)、數據存儲

數據存儲常用的有SQLite、SharedPreference、文件等,緩存是否也可以算是一種。這裡想強調的就是要注意數據存儲的規范性以及安全性,如果是數據庫還有必要考慮其擴展性,如果不滿足需求將會需要進行升級。

(4)、性能管理

這裡源自於對性能優化的一點體會,對於服務端的開發我們很珍惜服務器資源,應該是看的見的需要銀子買的。然而,對於客戶端的開發我們常常忽略了這一點。雖然手機設備現在擁有大內存,但是如何寫出一個優秀的程序,性能也是一個非常重要的指標。性能優化處理,那是我們在更正錯誤,那麼之後應該是少犯錯誤。性能體驗不夠好,無非就是對機器設備的內存、CPU、GPU資源無節制的使用,造成資源的浪費,當機器設備無法承受時就會應用就會出現卡段、死機、異常等不良反應,嚴重影響了應用的體驗。我們要做的就是要有很強的性能管理意識,對於內存、CPU、GPU等資源按需借用,並做到有借有還,即用完後記得釋放資源。

(5)、特殊處理

我們在開發的過程中,總有那麼多問題並不是按照正常思路出牌的,這些得歸功於我們強大的測試團隊。不同的手法,就能得到不同的結果,然後就給了我們一堆的bug。所以,我們在軟件的開發中需要特別注意一些特殊情況的處理,這些最終往往還是邏輯上的死角。以下簡單總結了一些:

功能沖突

功能沖突可以分為兩種,一個是應用內部的功能沖突,二是應用之間的功能沖突。應用內沖突比如A功能和B功能都使用了某資源文件,如果在同時使用就會出現問題,我們通常加同步鎖來防止這種沖突。應用外的沖突有很多,比如多媒體、鬧鐘、日歷、鈴聲、電話等都肯能引起這些沖突,比如你正在播放一段視頻,這個時候來了一個電話,那我該優先哪一個呢?還有當鬧鐘響起的時候,彈出一個界面是豎屏的,那麼他就會強制將當前的界面變為豎屏,而如果你這個時候如果是橫屏的話該怎麼辦呢?類似於這類還有很多,以後再細細總結。

極限操作

我們的測試人員喜歡對著某一個按鈕狂點、或者在機器上安裝無數的應用使內存爆滿,或者在磁盤裡邊塞滿各種文件。這些場景雖然並不是理性的用戶所出現的,但實際也是程序的缺陷。所以,我們要注意對這些問題進行處理。

網絡問題

不可用的網絡,信號很弱的網絡,網路在wifi和流量之間切換,2G網絡和4G網絡,網絡請求超時等都需要我們針對實際情況進行處理,比如切回到流量的時候進行下載是否有提醒用戶。這些處理也算是各個應用的標配了,就不再多說了。

為null處理

這應該是最常見的問題了,我們平時改bug或者從後台異常抓取的大多數都是空指針異常。首先,我們得搞清楚為null的原因是什麼?然後我們需要進行為null的判斷,並警告。

(6)、Log打印

這裡把Log打印單獨拿出來是應為我覺得很需要重視。Log是用來干嘛的?很顯然是用來幫助我們查找問題的,然後我們大多數的情況下是問題來了再去加打印,並且TAG五花八門的,是有錯誤的地方用Log.d,而只是查看信息卻是用的Log.e,我們查問題的時候要去閱讀很多的代碼邏輯,最後再定位到位置。我們在修復bug的時候花了大量的時候再閱讀代碼,這個太影響工作效率了。如果我們在編碼之初就對Log有了很好的規范設計,有異常的地方就用Log.e,可能出現問題的地方就用Log.w等等,關鍵點的信息用Log.i,臨時調試的用Log.d這樣區分不是很好嗎?我們在控制台一樣就能夠分辨自己需要的信息。我們應該充分應用這個工具,幫助我們快速定位問題。

(7)、軟件重構

重構是因為業務的需要,也是因為對代碼更高的質量要求,重構無處不在。我們不要為了重構而重構,也不要一直停滯不前,該重構時不重構,欠下太多的技術債務。重構有小到一個方法的重構,也有大到整個系統架構的重構。重構是軟件迭代升級的一個必要過程,也是我們能夠滿足當前需要,並且能夠適應未來的發展,獲得良好的擴展性的必要手段。重構並不難,也不是什麼大事,重點在於重構背後的目的、思想、設計是否清晰。

(8)、兼容適配

兼容適配的問題是我們開發一個頭疼的問題,Android設備無法八門的屏幕尺寸、層次不齊的Android系統版本。除了進行針對性的處理,還得提醒產品設計人員在設計之初就得考慮兼容性問題。

5、軟件測試

軟件測試是我們開發中非常重要的一到工序,除了能夠客觀的感應我們所開發的軟件質量水平,最終目的還是在於幫助開發人員修復軟件缺陷,提高軟件的質量。除了開發人員提交測試之前的自測,我們需要專業的測試人員來進行測試。人工測試的效率相對較低,所以我們應該考慮通過技術手段完成自動化的測試,如單元測試等。這樣有利於軟件的穩定,也同樣的有助於開發人員提高代碼質量。

6、開發規范

(1)、設計一致

什麼樣的設計才是有規范的設計呢?我個人認為一個項目保持一致的設計思想就是有規范的設計。我們可以這樣去理解,在某一類的情況下,我們按照某一類似的方案來解決這一類問題。面對復雜的系統,我們一種設計思想也許無法滿足架構的需求,但是我們只需要明白,這種事情這麼干,那種事情那麼干,相互之間靈活的組合卻也不存在交叉,給人設計思路清晰的感覺。

(2)、編碼清晰

什麼樣的代碼才是高質量的代碼?我覺得結構簡單,邏輯清晰,一看就懂的代碼就是一份高質量的代碼。所以,我們可以拋開那些編碼規范、命名規范等等,重新去審視自己的代碼,看看讀起來是不是很舒服。如果來了一個新同事,對你對項目一無所知,是否能夠很快速的理解你的思維?最後幾點有必要提出,一是慎用設計模式,二是盡量少寫文檔注釋,三是遵循Java的面向對象六大設計原則。我想這三點就是編碼的原則,遵守這些原則,形成一種習慣,自然而然就是一種規范。

(3)、文檔有效

什麼樣的文檔才是有效的文檔,我認為能說明核心問題的文檔就是有效的文檔。作為軟件開發人員,我們沒有耐心去閱讀一份復雜啰嗦的文檔。文檔只需要給我們呈現代碼無法說明的問題,幫助我們快速理解項目結構,備忘重點問題,追溯歷史記錄。文檔的形式又很多,比如我們Git的提交記錄、tag,項目結構圖、核心功能流程圖等。總之,文檔是給人看的,以盡量少的文檔來說明核心問題就好。

7、日常工作

作為一名合格的軟件開發人員,我們有許多的日常工作,如Bug修復、異常處理、Monkey、性能優化、代碼質量改善等待。這些事情並一定要求你每天都要做,但是每天都得關注,做到心中有數。如此,才能夠培養一個很好的編程習慣,寫出優秀的代碼,優秀的程序。

六、統籌規劃

1、開發驅動

一個項目的正常運轉一定是由某一方主導項目的進行,不斷的提出產品需求,並組織項目成員分工合作,完成產品的開發交付,以下是兩種驅動開發模型。

TDD:測試驅動開發(Test-Driven Development)

測試驅動開發指的是由測試主導開發的工作,從產品的使用出發,對產品的功能提出測試要求,組織項目中各個角色完成開發任務。

BDD:行為驅動開發(Behavior Driven Development)

敏捷開發便是行為驅動的開發,更加強調產品的設計,鼓勵項目中各個角色提出自己對項目開發的觀點,已獲得更優秀的產品功能,完成產品的開發。

2、敏捷開發

下圖引自網絡上的一張關於敏捷開發的圖片,目前我們團隊基本也是根據這個模型進行敏捷開發的。我覺得在敏捷開發中更加強調的各個角色之間的隨時溝通和快速響應,我們並不對整個系統進行一份完整而詳細的設計,而是進行階段的設計開發工作,並謀求不斷的迭代更新。在敏捷開發的過程中,普遍存在的問題就是溝通不及時、產品變動大,所以如何動態的進行統籌管理變的非常重要。我們通過需求評審、交互評審、視覺評審、Bug評審等由各個有關角色的人員參加評審會議,共同完成決策,以保證軟件開發的順利進行。不得不說,這個過程中還是存在許多的問題,溝通的問題,產品變動的問題,產品功能細節開發過程的中流程性的問題等等,在此不詳細說了,後期有時間再進行總結。

3、達成共識

敏捷開發中有一個特點就是,產品開發決策是由項目各個角色成員共同完成的,各個角色領域的問題又是由該角色自身最終拍板。那麼隨之而來的就出現了一個問題,各個角色所決定的問題又被其他的角色所制衡。比如說,產品經理設計的功能在開發人員而言存在技術難題,交互的設計存在邏輯上的漏洞。我想,這些問題是一個產品不能按照預期時間完成的真實原因。那麼,哪一個角色來統籌管理這些問題呢?通常,我們有架構師、項目經理、老板等等角色來對項目進行把控和管理。

軟件架構的設計來源於產品的需求,並決定了產品的最終形態。然而處於敏捷開發中的我們而言,產品的需求變化很快,同時要求我們開發人員能夠快速響應這種變化。那麼,如何保持軟件的整體架構和產品的設計同步更新就顯的非常重要。

對於開發者而言,我們首先要對項目有一個整體的認知,隨時掌握產品的動態。這些包括產品的設計、迭代計劃、開發資源、質量要求、交付要求、風險規避方案等。然後根據產品的需求變化,動態調整自己的軟件架構,這些工作包括,技術選型、架構設計、代碼重構、文檔更新等,以適應新的需求,並把這種架構共享給相關人員以達成共識。這種共識,是需要對產品和技術進行統籌規劃才能夠完成的。也只有項目各個相關利益人員能夠達成這種共識,我們的溝通才會更有效,才能做出各方人員都滿意的產品。

七、總結

寫到最後,我回過頭來看看,才發現對架構的整體認識站在了決策派的一邊,即這種共識便是在產品規劃、設計、開發階段一些重要方面所作出的決策的集合。這些決策是我們項目各個角色成員通過計劃會、評審會、迭代會等達成的共識,並最終表現在我們的產品上。產品、交互、UI、開發、測試,每個角色對自己所在領域負責的同時也需要隨時掌握其他領域的信息,以便自己做出正確的決策。但是在對軟件技術實現的架構設計上,我就偏向了組成派,將軟件系統的業務進行了拆分和組合,已達成系統運轉。我必須承認,此刻我的認識還是不夠通透,在本文中各個方面大多還是泛泛而談,每個問題深入下去還有許多可以去研究的,希望能夠在以後的工作能夠有更深刻的領悟。

八、 參考文獻

  • 《小鋼的架構思考系列》
  • 餓了麼移動APP的架構演進
  • 攜程移動App架構優化之旅
  • 糯米移動組件架構演進之路
  • 蘇寧易購移動端的架構優化實踐
  • Android App 整體架構設計的思考
  • android開發一般都使用什麼框架?
  • 手機天貓解耦之路
  • 什麼是 Agile Software Development(敏捷軟件開發)?
  • 《架構之美》
  • 《軟件架構設計》

後記

經過這段時間對架構的學習和思考,我發現這些理論不僅可以運用在軟件架構中,同樣也適用於工作、生活當中。試著將我們的工作任務進行分離,減少每項任務之間的交叉,避免東一榔頭西一棒子,有條理的完成各項工作。這樣一來,你的工作目標是清晰的,也更加容易的完成既定目標。同樣的,我們可以通過這一理論還規劃自己的人生。將我們的事業、家庭、興趣愛好分離,再對每一項分離出更細的關注點,每個關注點在不同的階段定下自己小目標。這樣,我們對自己就可以有了更清晰的認識,認識自己已經擁有什麼?最終想要什麼?計劃怎麼做?當前怎麼做?當然,並不是每一步都是能夠按照既定目標走的,我們需要不斷的更新對自己的認識,做出更加合適的決策。

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved