Android開發(fā)軟件架構(gòu)思考以及經(jīng)驗(yàn)總結(jié)
一、萌芽
作為一只編程經(jīng)驗(yàn)并不怎么豐富的程序猿來講,我一直覺得架構(gòu)師是一個(gè)比較神秘的職業(yè),架構(gòu)設(shè)計(jì)就更加的高大上了。經(jīng)過今年的幾個(gè)項(xiàng)目,之前曾發(fā)文敘述我的從MVC到MVP項(xiàng)目重構(gòu)實(shí)戰(zhàn)經(jīng)驗(yàn),也曾說過我準(zhǔn)備對(duì)目前手底下的項(xiàng)目進(jìn)行重構(gòu)。但是,前段時(shí)間,我改變了我的想法。開發(fā)模式的重構(gòu),僅僅只是換了一個(gè)套路,也許在重構(gòu)的過程中對(duì)業(yè)務(wù)的邏輯進(jìn)行了一次梳理,也是在基于前人的代碼設(shè)計(jì)上進(jìn)行了一些優(yōu)化。但是,這遠(yuǎn)遠(yuǎn)還不夠,這不是我理想中的開發(fā)場(chǎng)景。在項(xiàng)目開發(fā)的過程中,也發(fā)現(xiàn)存在許多的問題,但是都是一些零散的問題,我很多時(shí)候希望能夠改變現(xiàn)狀,更加優(yōu)雅地編程,然后實(shí)際的情況卻是陷入了迭代功能開發(fā)和bug修復(fù)的死循環(huán)?,F(xiàn)在回過頭來想想,我理想中應(yīng)該是開發(fā)應(yīng)該是一種由規(guī)劃和設(shè)計(jì)指導(dǎo)的開發(fā),那么架構(gòu)設(shè)計(jì)就顯的尤為重要了。
二、初識(shí)架構(gòu)
1、閱讀《架構(gòu)之美》之論架構(gòu)
僅看完了《架構(gòu)之美》的第一部分:論架構(gòu),對(duì)架構(gòu)有了一個(gè)大概的認(rèn)識(shí)。下圖是這部分的知識(shí)點(diǎn)概要:
書中很受啟發(fā)的概念:
- 架構(gòu)是一種折中,一種取舍。架構(gòu)師要學(xué)會(huì)的就是平衡,質(zhì)量與成本之間的平衡;
- 架構(gòu)師首先關(guān)注的不是系統(tǒng)的功能,而是滿足需求,滿足品質(zhì);
- 架構(gòu)設(shè)計(jì)要做的是讓關(guān)注點(diǎn)分離,并且對(duì)每個(gè)關(guān)注點(diǎn)進(jìn)行設(shè)計(jì)一定的結(jié)構(gòu),該結(jié)構(gòu)都有利于解答這一個(gè)關(guān)注點(diǎn)所定義的問題;
- 好的架構(gòu)應(yīng)該是可以指導(dǎo)產(chǎn)品、開發(fā)、測(cè)試人員都對(duì)這一設(shè)計(jì)感到非常的舒適可靠,該設(shè)計(jì)覆蓋了所有該軟件系統(tǒng)相關(guān)利益的人員以及其中的關(guān)注點(diǎn);
- 只設(shè)計(jì)你知道需要的東西,多余的設(shè)計(jì)是一種浪費(fèi);
- 架構(gòu)幾乎影響了該系統(tǒng)相關(guān)的所有的人和事,決定了該軟件系統(tǒng)是否健康。
2、分析行業(yè)內(nèi)各個(gè)APP的架構(gòu)演進(jìn)
這里僅僅通過Google搜索各個(gè)app在架構(gòu)演進(jìn)方面的一些文章,從中分析他們?yōu)槭裁匆葸M(jìn)?怎么演進(jìn)?帶來了哪些好處?
簡單的整理如下:
(1)架構(gòu)為什么需要演進(jìn)
- 項(xiàng)目需求擴(kuò)張,舊的架構(gòu)不適應(yīng)新的需求
- 開發(fā)團(tuán)隊(duì)人員增加,協(xié)作要求變高
- 新技術(shù)引入
- 更高的軟件質(zhì)量要求
(2)他們是怎么演進(jìn)的
- 餓了么移動(dòng)APP的架構(gòu)演進(jìn) 2016-01-20
- 共有組件
- 業(yè)務(wù)組件
- 模塊解耦
- Excalibur映射系統(tǒng),注冊(cè)機(jī)制
- 引入Hybrid框架
- React-Native & Hot Patch
- 攜程移動(dòng)App架構(gòu)優(yōu)化之旅 2016-04-07
- 工程結(jié)構(gòu)調(diào)整、業(yè)務(wù)之前解耦,產(chǎn)品間相互獨(dú)立,頁面跳轉(zhuǎn)使用事件總線或者URL總線方式
- 統(tǒng)一基礎(chǔ)功能業(yè)務(wù)組件,SDK化
- 性能數(shù)據(jù)采集、監(jiān)控
- Native的插件化和HotFix
- 糯米移動(dòng)組件架構(gòu)演進(jìn)之路 2016-05-24
- 組件化
- 統(tǒng)一服務(wù)入口
- Hybrid框架優(yōu)化
- 蘇寧11.11:蘇寧易購移動(dòng)端的架構(gòu)優(yōu)化實(shí)踐 2016-11-11
- 分層解耦,解決縱向解耦
- 中介型引用結(jié)構(gòu)(protocol和url方式),橫向解耦
- H5容器優(yōu)化
- 網(wǎng)絡(luò)鏈路優(yōu)化
- 移動(dòng)App性能監(jiān)控系統(tǒng)
(3)帶來的好處
- 進(jìn)行了模塊化的解耦,產(chǎn)品相對(duì)獨(dú)立,應(yīng)對(duì)需求變化、技術(shù)更新更加靈活,團(tuán)隊(duì)協(xié)作更加方便,并減少了許多是無用功,也給團(tuán)隊(duì)留下了一些技術(shù)積累;
- 進(jìn)行了必要的統(tǒng)一規(guī)范,組織結(jié)構(gòu)更加清晰,系統(tǒng)更加健康;
- 引入了新的技術(shù)框架,,產(chǎn)品獲得更好的體驗(yàn);
- 進(jìn)行了系統(tǒng)的優(yōu)化工作,軟件的品質(zhì)更高,體驗(yàn)更好;
3、Google搜索關(guān)鍵字:架構(gòu)設(shè)計(jì)
搜索引擎對(duì)于我們來說是最棒的學(xué)習(xí)工具,我通過搜索架構(gòu)設(shè)計(jì)等關(guān)鍵字,閱讀了一些文章,并仔細(xì)研讀Keegan小鋼的博客文章《小鋼的架構(gòu)思考》系列。這幾篇文章在發(fā)表之初曾閱讀過,但是當(dāng)時(shí)并不怎么理解,大概是對(duì)架構(gòu)還沒有一個(gè)大概的認(rèn)識(shí)。在請(qǐng)教一位前輩的時(shí)候,他和說了對(duì)架構(gòu)的一個(gè)理解,并再次推薦了這幾篇文章。所以我再次閱讀了好幾遍。下圖是文中關(guān)于架構(gòu)設(shè)計(jì)的知識(shí)概要。
(1)知識(shí)概要
(2)個(gè)人小結(jié)
架構(gòu)分為三個(gè)階段:規(guī)劃、設(shè)計(jì)、構(gòu)建,每個(gè)階段架構(gòu)的設(shè)計(jì)有不同職能。在規(guī)劃階段,考慮的是產(chǎn)品的需求、質(zhì)量的需求,技術(shù)的可行性分析以及預(yù)研。在設(shè)計(jì)階段,考慮的如果將一個(gè)復(fù)雜的系統(tǒng)拆分,并設(shè)計(jì)如何進(jìn)行組織這些拆分的模塊。在構(gòu)建階段,考慮的就是具體的實(shí)施問題,并且要保證一定的伸縮擴(kuò)展性,因?yàn)榧軜?gòu)是不斷演進(jìn)的。文中引用了《軟件架構(gòu)設(shè)計(jì)》一書的一個(gè)模型圖,我覺得有必要在此貼出來。最近也在思考軟件模塊化的設(shè)計(jì),模塊化的設(shè)計(jì)也許各有理解,在此先不做討論。如下圖:
這張圖我起初理解不是很透徹,我曾嘗試自己去畫一些圖來表達(dá)我的一些想法。但是,當(dāng)我再次回過頭看到這張圖的時(shí)候,才恍然大悟。
架構(gòu)的設(shè)計(jì)可以從兩個(gè)維度來考慮,一是架構(gòu)思維,二是架構(gòu)原則。思維是我們的思考方式,是我們解決問題的方法。原則是我們思考問題的方向,是我們解決問題的一些標(biāo)準(zhǔn)。
三、架構(gòu)的定義
對(duì)于架構(gòu)的定義,業(yè)界都各有看法,也曾微信私信請(qǐng)教過一些行業(yè)內(nèi)有豐富經(jīng)驗(yàn)的前輩。《軟件架構(gòu)設(shè)計(jì)》一書則將架構(gòu)定義總結(jié)為組成派和決策派:
- 組成派:架構(gòu)=組件+交互:軟件系統(tǒng)的架構(gòu)將系統(tǒng)描述為計(jì)算組件及組件之間的交互。
- 決策派:架構(gòu)=重要決策集:軟件架構(gòu)是在一些重要方面所作出的決策的集合。
keegan小鋼在《小鋼的架構(gòu)思考:什么是架構(gòu)》文中提到:軟件架構(gòu)是規(guī)劃、設(shè)計(jì)和構(gòu)建軟件的過程和結(jié)果?!都軜?gòu)之美》一書在1.1.3架構(gòu)的含義中提出:架構(gòu)說明了設(shè)計(jì)和構(gòu)建一個(gè)系統(tǒng)所使用的結(jié)構(gòu)?!禨oftware Architecture in Practice,Second Edition》中提出:一個(gè)程序或計(jì)算機(jī)的軟件架構(gòu)是系統(tǒng)的一種結(jié)構(gòu)或一組結(jié)構(gòu),它包含軟件元素、這些元素的外部可見的屬性,以及元素之間的關(guān)系。
本人并沒有經(jīng)歷過大型的軟件系統(tǒng),做過的也只是移動(dòng)端App的開發(fā),所以個(gè)人也只敢從移動(dòng)端app的架構(gòu)設(shè)計(jì)出發(fā),給出我一個(gè)狹義的理解。我認(rèn)為,移動(dòng)端的app架構(gòu)是一種基于產(chǎn)品和技術(shù)的進(jìn)行統(tǒng)籌管理最終所形成的共識(shí)??赡艽蟛糠值腶pp開發(fā)尤其是小團(tuán)隊(duì)app的開發(fā)大多是由產(chǎn)品驅(qū)動(dòng)的開發(fā),需求來了,那就技術(shù)實(shí)現(xiàn)。需求變了,那就改。畢竟,應(yīng)用層的開發(fā)是對(duì)業(yè)務(wù)負(fù)責(zé)的,必須保證正常的發(fā)布。所以大多數(shù)的情況下,程序猿不得不在產(chǎn)品經(jīng)理面前妥協(xié),這樣對(duì)于開發(fā)人員的工作就會(huì)變的很被動(dòng)。所以,就出現(xiàn)了程序猿和產(chǎn)品狗的撕逼笑談。這種現(xiàn)象的原因在于項(xiàng)目各個(gè)相關(guān)利益人員沒有對(duì)產(chǎn)品和技術(shù)達(dá)成共識(shí),這正是移動(dòng)端架構(gòu)設(shè)計(jì)所要解決的問題。
四、產(chǎn)品
產(chǎn)品,是我們產(chǎn)品經(jīng)理們?cè)O(shè)計(jì)的結(jié)果,也是開發(fā)人員開發(fā)的最終成果,是前后兩種人群的共同目標(biāo)。作為軟件的架構(gòu)設(shè)計(jì)者應(yīng)該充分理解產(chǎn)品的設(shè)計(jì)理念,除了明白已經(jīng)設(shè)計(jì)的功能業(yè)務(wù),還得具有一定的預(yù)見,掌握產(chǎn)品的發(fā)展趨勢(shì)。下面主要從開發(fā)的角度來談一談產(chǎn)品。
1、產(chǎn)品設(shè)計(jì)(做什么)
作為一名開發(fā)人員,我不能很專業(yè)的來談產(chǎn)品的設(shè)計(jì),但是這里我還是希望以一個(gè)開發(fā)人員的角度來講產(chǎn)品設(shè)計(jì)。什么是產(chǎn)品設(shè)計(jì),我覺得可以從以下幾個(gè)方面來思考。
(1)、用戶群體(什么人用)
顧名思義,我們?cè)O(shè)計(jì)開發(fā)出來的產(chǎn)品最終是讓人用的。所以首先我們得定位產(chǎn)品的用戶是誰?用戶群體代表了我們產(chǎn)品的市場(chǎng)。所以產(chǎn)品做的好不好,最終市場(chǎng)說了算,用戶說了算。離開了用戶,不理解用戶,不注重用戶的體驗(yàn),一切都是無用功。
(2)、核心理念(要做什么)
你知道你最每天累死累活一行一行敲出來的是什么樣的產(chǎn)品嗎?可能對(duì)于我們開發(fā)人員很容易陷入到一個(gè)版本一個(gè)版本的迭代當(dāng)中,這些永無止境的工作叫人忘記了思考,忘記了問下產(chǎn)品人員,我們最終是要做的什么?一年后我們的產(chǎn)品將是個(gè)什么樣的狀態(tài),我們的最終愿景是什么?我們將會(huì)怎么一步步去實(shí)現(xiàn)我們最終的愿景?可能你會(huì)說,這些和我開發(fā)有什么關(guān)系。接到需求,我把他開發(fā)出來實(shí)現(xiàn)不就ok了。然而,在我們的小組里不乏有這些怨言,產(chǎn)品人員不斷的修改,我TM代碼改過來改過去。我們的leader在這方面很強(qiáng)調(diào)我們開發(fā)人員應(yīng)該擁有自己的主動(dòng)權(quán),可以反駁產(chǎn)品不合理的設(shè)計(jì)。但是,前提是你至少理解產(chǎn)品的核心理念,我們最終要做什么。
2、迭代計(jì)劃(計(jì)劃怎么做)
對(duì)于一個(gè)產(chǎn)品,用戶的需求是很多的,而且隨著時(shí)間不斷改變的。需求可以分兩種,一種是人性本能的需求,還有一種,是我們的產(chǎn)品催生的需求。這兩種需求都是合理的,也正是我們需要滿足用戶的。對(duì)于各式各樣的需求我們?cè)趺从杏?jì)劃的去實(shí)現(xiàn)呢?在敏捷開發(fā)中,我們將這些需求放到一個(gè)“需求池”中,然后進(jìn)行計(jì)劃安排在不同版本的迭代中。這個(gè)工作,不僅是產(chǎn)品人員去決定,開發(fā)人員也應(yīng)該起一定的決策作用。產(chǎn)品人員需要從產(chǎn)品的角度去考慮,開發(fā)人員需要從技術(shù)實(shí)現(xiàn)的角度去考慮,最終的計(jì)劃應(yīng)該是兩者的共同決策。特別注意的是,根據(jù)產(chǎn)品的特性,技術(shù)人員也應(yīng)該提出技術(shù)方面的需求。合理的迭代計(jì)劃可以保證正常的開發(fā)節(jié)奏,完成迭代目標(biāo)。
3、開發(fā)資源(用什么做)
(1)、開發(fā)團(tuán)隊(duì)配置(人)
在《人件》一書中提到了軟件開發(fā)中人的因素很重要,合理配置開發(fā)團(tuán)隊(duì)是非常重要的。一個(gè)App的開發(fā)團(tuán)隊(duì)至少需要5個(gè)角色,即產(chǎn)品、交互、UI、軟件、測(cè)試。不同角色也分不同的層次,比如軟件分初級(jí)、中級(jí)、高級(jí)。不同角色、不同層次合理搭配,才能夠獲得更高的工作效率,保證產(chǎn)品開發(fā)順利進(jìn)行。
(2)、數(shù)據(jù)內(nèi)容配置(物)
產(chǎn)品最終呈現(xiàn)給用戶的是數(shù)據(jù),數(shù)據(jù)分兩種。一種是私有的數(shù)據(jù),是由開發(fā)商自己生產(chǎn)的數(shù)據(jù)。一種是平臺(tái)自生的數(shù)據(jù),是由用戶生產(chǎn)的。如果是自己生產(chǎn)的數(shù)據(jù),就得考慮數(shù)據(jù)來源,數(shù)據(jù)的覆蓋率,數(shù)據(jù)的準(zhǔn)確性,合法性等。如果是用戶生產(chǎn)數(shù)據(jù),就得考慮用戶生產(chǎn)數(shù)據(jù)的動(dòng)力、入口以及數(shù)據(jù)安全性、傳播性等。
(3)、開發(fā)投入預(yù)算(錢)
萬事俱備,只欠東風(fēng)。完成一款app開發(fā),需要一支專業(yè)的開發(fā)團(tuán)隊(duì),這里的人力成本也是很高的。當(dāng)然我這里只談開發(fā)的預(yù)算,至于運(yùn)營就不說了。我們得考慮,開發(fā)周期多長、需要多少人、后期維護(hù)怎么辦。比如一個(gè)APP需要5個(gè)人開發(fā),2個(gè)月的時(shí)間,開發(fā)兩個(gè)版本,按照每人1W的工資來計(jì)算的話,也需要 10W。這估計(jì)是最低級(jí)別的算法了。所以,如果是創(chuàng)業(yè)公司,我們?cè)诮M建開發(fā)團(tuán)隊(duì)的時(shí)候,也得看看預(yù)算是多少,多少錢能辦多大事,當(dāng)然如果是那些拿到投資無所謂的老板來時(shí)得另算了,不過今年死的太多的公司以前都是大手筆。錢燒完了,也就沒有了。如果是大公司,可能不帶這么摳門的。不過也應(yīng)該去考慮,開發(fā)團(tuán)隊(duì)會(huì)消耗公司多少資源,我們能否獲得相應(yīng)或者更高的產(chǎn)出。
(4)、第三方資源
目前的開發(fā)而言,很多資源是可以尋找第三方合作的。比如,服務(wù)器、云存儲(chǔ)、支付接口、登錄接口、內(nèi)容數(shù)據(jù)以及開發(fā)過程中的一些開源框架等等。我們需要選擇、商務(wù)談判直到集成到自己的APP中。
4、產(chǎn)品質(zhì)量(做的怎么樣)
(1)、用戶體驗(yàn)
現(xiàn)在對(duì)于我們來說,用戶體驗(yàn)是一個(gè)說爛了的詞。那是因?yàn)?,用戶體驗(yàn)真的很重要,決定了一個(gè)產(chǎn)品的成敗。產(chǎn)品開發(fā)完成后,最終到達(dá)用戶的手中。產(chǎn)品好不好,用戶說了算。哪些因素影響到用戶體驗(yàn)?zāi)?我想大概可以從5個(gè)角色各自的職責(zé)出發(fā)來看,產(chǎn)品的設(shè)計(jì)是否直達(dá)用戶痛點(diǎn)?交互是否符合人的喜好、習(xí)慣,UI是否讓用戶覺得舒適?軟件的性能好不好?軟件的缺陷是否多不多?
(2)、軟件性能
從技術(shù)的角度來講,我們可以通過軟件的性能來分析一個(gè)軟件產(chǎn)品的質(zhì)量。今年許多的技術(shù)文章都在談性能優(yōu)化,軟件的性能主要從軟件的啟動(dòng)速度、流暢度、內(nèi)存、功耗、流量、apk體積等幾個(gè)方面來評(píng)判。如果想做好一個(gè)應(yīng)用,性能優(yōu)化應(yīng)該納入到日常的開發(fā)中持續(xù)進(jìn)行。具體如何優(yōu)化,這里就不再多說了。
(3)、產(chǎn)品安全
產(chǎn)品的安全性可以從兩個(gè)角度來看,產(chǎn)品的生產(chǎn)商和產(chǎn)品的最終用戶。對(duì)于生產(chǎn)商而言,有許多的內(nèi)容是需要受到法律保護(hù)的,有許多的敏感信息,核心技術(shù)、網(wǎng)絡(luò)接口等是不可以泄露的。對(duì)于用戶而言,我們肯定在本地或者服務(wù)器存儲(chǔ)了大量的用戶信息,比如賬號(hào)密碼,一些信息一旦泄露將嚴(yán)重傷害到用戶的個(gè)人利益。所以,為了保護(hù)自己以及用戶利益,我們必須要生產(chǎn)一個(gè)安全可靠的產(chǎn)品。那么對(duì)于一個(gè)應(yīng)用端的開發(fā)者而言,我們的編譯出的apk最終會(huì)到用戶手中。所以,我們需要通過代碼混淆、數(shù)據(jù)加密、權(quán)限限制等一些技術(shù)手段來保護(hù)我們的應(yīng)用。
(4)、質(zhì)量評(píng)測(cè)
一個(gè)應(yīng)用做的好不好,我認(rèn)為可以主要從上述用戶體驗(yàn)、軟件性能、產(chǎn)品安全三個(gè)維度來進(jìn)行評(píng)判。那么,我們?cè)撊绾谓M織這些評(píng)判工作呢?我們有在進(jìn)行這些工作嗎?就目前而言,我相信大多數(shù)的產(chǎn)品、開發(fā)、測(cè)試人員都或多或少的參與到這些工作當(dāng)中,但是也許沒有將一些數(shù)據(jù)量化、沒有系統(tǒng)的組織這些工作。目前大部分的應(yīng)用都集成了行為采集,產(chǎn)品的下載量、用戶的活躍度等也都是體現(xiàn)產(chǎn)品用戶體驗(yàn)的主要參數(shù)。開發(fā)團(tuán)隊(duì)內(nèi)部一直在進(jìn)行性能優(yōu)化的工作,比如異常修復(fù)、bug修復(fù)、內(nèi)容泄露,過度繪制,apk瘦身。我們也進(jìn)行了代碼混淆、數(shù)據(jù)加密、apk簽名加密的工作。但是,你知道你的產(chǎn)品質(zhì)量如何嗎?相比同類產(chǎn)品來,你哪些做的好,哪些做的不好嗎?所以,我覺得將上述這些零碎的工作有系統(tǒng)的組織起來,將一些影響因素進(jìn)行量化,讓我們更加清楚的了解我們的產(chǎn)品質(zhì)量是一件非常有意義的事情。
5、風(fēng)險(xiǎn)規(guī)避
(1)、人力變動(dòng)風(fēng)險(xiǎn)
人是善變的,尤其對(duì)于IT來說,人員的流動(dòng)就更加的頻繁了,公司內(nèi)部的調(diào)整,員工跳槽等等。所以,對(duì)于一直開發(fā)團(tuán)隊(duì),必須要考慮到人員變動(dòng)的風(fēng)險(xiǎn)。如果,某某不在了,項(xiàng)目是否可以正常運(yùn)行。開發(fā)團(tuán)隊(duì)之間是否能夠交叉熟悉各自之間的業(yè)務(wù)。
(2)、上層決策風(fēng)險(xiǎn)
是否經(jīng)歷過一個(gè)項(xiàng)目做到一大半業(yè)務(wù)被停掉了的情況?而這個(gè)時(shí)候,你做的是個(gè)半吊子。如果出現(xiàn)了這種情況,我們?cè)撛趺崔k?假設(shè)就在剛才你的老板說你現(xiàn)在的項(xiàng)目不做了,那么如何才能最大程度的挽回?fù)p失?如何進(jìn)行項(xiàng)目的收尾工作?而不至于在項(xiàng)目又突然重啟的時(shí)候接收的是一個(gè)爛攤子。
(3)、項(xiàng)目延期風(fēng)險(xiǎn)
我們?cè)陧?xiàng)目開發(fā)的時(shí)候會(huì)進(jìn)行評(píng)審,然后按照迭代計(jì)劃開發(fā),但是在開發(fā)過程中一定會(huì)有許多問題影響我們的預(yù)期,比如需求變動(dòng)、技術(shù)難題等等。項(xiàng)目延期在軟件項(xiàng)目的開發(fā)中是普遍存在的問題,對(duì)于某些迭代而言,可能并不對(duì)整個(gè)項(xiàng)目造成重大影響,但是這個(gè)問題是一定需要考慮的。并且,我們應(yīng)該嚴(yán)格的掌控項(xiàng)目的進(jìn)度,平衡這些問題,保證能夠按時(shí)交付產(chǎn)品。
(4)、軟件缺陷風(fēng)險(xiǎn)
我們應(yīng)該隨時(shí)能夠提供一個(gè)穩(wěn)定的版本,這是我們的leader所要求的。軟件的缺陷存在是正常的,我們不停的寫bug,也在不停的修改bug,對(duì)于那些隱藏很深的bug也許沒有讓測(cè)試測(cè)出來,最后流通到用戶的手中,這個(gè)時(shí)候我們?nèi)绾瓮瓿删o急修復(fù)?如何快速響應(yīng)能給到用戶一個(gè)穩(wěn)定可靠的版本。這些是我們需要考慮的,任何時(shí)候,都應(yīng)該有PlanB。
(5)、人為失誤風(fēng)險(xiǎn)
前段時(shí)間,公司內(nèi)由于操作失誤,上架更新一個(gè)apk的時(shí)候不小心發(fā)錯(cuò)了機(jī)型,導(dǎo)致使用該機(jī)型的用戶升級(jí)后程序無法使用。然后,由于這個(gè)機(jī)型缺少維護(hù),找不到代碼,僅僅只能找到一個(gè)apk文件,然后只能考慮反編譯升級(jí)等等。我想,類似于這類的人為失誤還有很多,比如代碼提交錯(cuò)誤,集成路徑出錯(cuò)等等。人總有一不小心的時(shí)候,所以,我們?cè)谠O(shè)計(jì)的時(shí)候,應(yīng)該將這些因素考慮進(jìn)去,如何在出現(xiàn)失誤的時(shí)候主動(dòng)警告,如何在用戶錯(cuò)誤已經(jīng)發(fā)生的時(shí)候啟動(dòng)緊急方案,將不良影響降到最低。
6、產(chǎn)品交付
(1)、測(cè)試版本
在敏捷迭代開發(fā)中,我們基本上能夠一周提交兩個(gè)測(cè)試版本。我們開發(fā)一部分、修復(fù)一部分,都可以提交一個(gè)可測(cè)試的版本,這樣可以最大程度的降低開發(fā)風(fēng)險(xiǎn),有利于軟件的穩(wěn)定性。
(2)、灰度機(jī)制
如果你產(chǎn)品的用戶量夠大,這個(gè)時(shí)候發(fā)布新的版本就得慎重考慮,用戶才是你的產(chǎn)品的檢驗(yàn)員。目前基本都是使用灰度發(fā)布的策略,先給少量的用戶發(fā)布,看看用戶的反饋,而后逐步發(fā)布給所有用戶。
(3)、版本管理
我們?cè)陂_發(fā)過程中有許多的版本,也有很多分法。如debug和release版本,有的時(shí)候還需要給內(nèi)容提供測(cè)試數(shù)據(jù)的data版本,還有的時(shí)候上一個(gè)版本還沒有正式發(fā)布我們就需要開發(fā)下一個(gè)版本的功能。我們?nèi)绾稳ス芾砀鱾€(gè)版本的代碼以及如何通過版本名來區(qū)分這些版本?我們需要制定一定的管理規(guī)范,并且這一規(guī)范是否在開發(fā)團(tuán)隊(duì)中達(dá)成共識(shí),就顯得非常重要。
五、技術(shù)開發(fā)
前面啰嗦了很多,終于寫到這里了。對(duì)于一個(gè)開發(fā)人員來說,怎么做才是我們的關(guān)鍵問題所在。只會(huì)Android開發(fā),所以以下只討論Android。我主要從以下幾個(gè)方面來談一談怎么做這個(gè)問題。
1、技術(shù)選型
(1)、 開發(fā)平臺(tái)
移動(dòng)端的開發(fā)目前主要是兩大陣營Android、iOS,其他的就不多說了。
(2)、 開發(fā)工具
- 編譯工具:Eclipse&Ant、AndroidStudio&Gradle,作為Android開發(fā)者,目前毫無疑問應(yīng)該選擇AndroidStudio&Gradle;
- 代碼倉庫:Git 、SVN ,工具有海龜、AndroidStudio也集成了VCS;
- Maven倉庫:可以使用nexus創(chuàng)建自己的maven已屏蔽;
- 持續(xù)集成:Jinkens、Buildbot、Travis CI、Strider、Integrity;
(3)、 開發(fā)語言
Java、Kotin、Grovvy、SQL等等;
(4)、 開發(fā)模式
MVC、MVP、MVVM、clean等,各有優(yōu)缺點(diǎn),在此不做詳細(xì)說明;
(5)、 開源框架
都說了不要重復(fù)造輪子,因?yàn)槟阍斓妮喿硬灰欢ú蝗思业暮糜?,?duì)于我們開發(fā)者而言,有一件非常好的事情就是我們有太多的開源免費(fèi)的第三方庫供我們使用,這樣給我們省去了大量的工作,做到更加高效的開發(fā)。但是,如何選擇,是否引入使我們需要考慮的一個(gè)問題。下面列出一些常用的第三方庫,更多請(qǐng)點(diǎn)擊。
- 網(wǎng)絡(luò):OKHttp、 android-asyn-http、 volley、 Retrofit
- 事件總線:otto、 EventBus
- 依賴注入:Dagger、 RoboGuice、 ButterKnife
- 圖片:Fresco、Glide、 Picasso
- 數(shù)據(jù)庫:GreenDao、 Ormlite、LitePal
- Json解析: Gson、Jackson、 FastJson
- 響應(yīng)式編程: RxJava、 RxAndroid
- 異常統(tǒng)計(jì)平臺(tái):騰訊Bugly、Crashlytics
- 性能優(yōu)化: blockcanary、 leakcanary
(6)、 新興技術(shù)
軟件開發(fā)而言,新技術(shù)的發(fā)展相當(dāng)迅速,然而我們實(shí)際落地到項(xiàng)目中卻需要很長的時(shí)間,因?yàn)樾碌募夹g(shù)剛出來一是需要學(xué)習(xí)成本,二是需要承擔(dān)新技術(shù)不夠成熟,存在缺陷帶來的一些風(fēng)險(xiǎn)。當(dāng)然,我們應(yīng)該積極的引入好的新的東西,跟得上時(shí)代的步伐才好。下面列舉的一些也許都算不上新的東西,但是也是近年來大家所追捧的新技術(shù)。
- AndroidSupport:DataBinding、MaterialDesign等;
- 混合開發(fā):ReactNative、Hybrid、Weex等;
- 編程語言:Java8、Kotlin;
- 熱修復(fù):AndFix、HotFix、Tinker等;
- 構(gòu)建:InstantRun、Freeline
2、業(yè)務(wù)拆分
我們?cè)谶M(jìn)行業(yè)務(wù)拆分的時(shí)候,我認(rèn)為可以將業(yè)務(wù)分成三類:
(1)、常用基礎(chǔ)業(yè)務(wù)
基礎(chǔ)業(yè)務(wù)主要是我們的app的一些基礎(chǔ)功能,像我們公司有BFC團(tuán)隊(duì)給我們開發(fā)了文件上傳下載、網(wǎng)絡(luò)請(qǐng)求、行為采集、賬號(hào)系統(tǒng)等SDK,免除我們一些重復(fù)的勞動(dòng)工作。怎么去定義什么業(yè)務(wù)才是基礎(chǔ)業(yè)務(wù)呢?我覺得可以這么去區(qū)分。如果你的業(yè)務(wù)在行業(yè)普通的應(yīng)用app都有需要,那么這些這些就是具有普遍適用性的基礎(chǔ)業(yè)務(wù)。我們根據(jù)不同的功能進(jìn)行拆分。
(2)、通用技術(shù)業(yè)務(wù)
通用技術(shù)業(yè)務(wù)我覺得是和自己app相關(guān)并且有技術(shù)性很強(qiáng)的業(yè)務(wù),可能是你應(yīng)用的核心技術(shù)部分,比如美顏這一類軟件的圖片處理,小猿搜題這類的圖片識(shí)別等就是一項(xiàng)通用技術(shù)型業(yè)務(wù)。通用技術(shù)業(yè)務(wù)的特點(diǎn)就是在和你同一類的app都會(huì)有需要使用的技術(shù),我們可以根據(jù)不同的技術(shù)領(lǐng)域進(jìn)行拆分。
(3)、特定功能業(yè)務(wù)
特定功能業(yè)務(wù)就是屬于你自己app的特定功能了,一般可以按照功能進(jìn)行拆分成不同模塊。比如說我目前的一鍵搜(類似于小猿搜題)主要有搜題、查單詞、翻譯三大功能。那么就可以分拆為三大塊。搜題要經(jīng)過拍照、框題、圖片處理、網(wǎng)絡(luò)請(qǐng)求等步驟,每個(gè)步驟都可以看成一塊小業(yè)務(wù),以此進(jìn)行拆分。特定功能業(yè)務(wù)大部分僅適用于你自身的APP。
以上的說法僅從自身的經(jīng)驗(yàn)出發(fā)來進(jìn)行描述,在我們實(shí)際的開發(fā)中可能會(huì)有一些特殊情況,或者有不同的拆分分方法??傊?,業(yè)務(wù)的拆分還需要根據(jù)實(shí)際情況來。
3、架構(gòu)設(shè)計(jì)(關(guān)注點(diǎn)分離、抽象)
(1)、核心概念
關(guān)注點(diǎn)分離
世上本沒有架構(gòu),關(guān)注點(diǎn)一分離就有了架構(gòu),我們將一個(gè)軟件系統(tǒng)的開發(fā)從多個(gè)維度將我們的工作進(jìn)行拆分,對(duì)于每個(gè)領(lǐng)域進(jìn)行設(shè)計(jì),將各個(gè)領(lǐng)域有系統(tǒng)的組織起來,這種組織結(jié)構(gòu)就是架構(gòu)。然而如何將一個(gè)復(fù)雜的系統(tǒng)將關(guān)注點(diǎn)進(jìn)行合理的分離,這個(gè)是非常有挑戰(zhàn)的。
抽象
抽象,這是在請(qǐng)教一位前輩時(shí)最后給我強(qiáng)調(diào)的一點(diǎn)。如果你對(duì)app是跟著交互走、一個(gè)頁面一個(gè)頁面寫的,那么很顯然,你沒有對(duì)你的業(yè)務(wù)進(jìn)行抽象,而只是在實(shí)現(xiàn)。作為java的設(shè)計(jì)思想也很強(qiáng)調(diào)抽象的概念。那抽象到底是什么呢?抽象就是你要做什么!更簡單的理解就是,寫interface而不是class。不知道大家有沒有這樣的經(jīng)歷,在我們的MVP的開發(fā)當(dāng)中,我們有個(gè)Model,也有一個(gè)IModel,但是我們寫完了Model才知道怎么寫IModel,最后成了粘貼復(fù)制的體力勞動(dòng)。如果你是這么做的,你可以自己思考下,假如我們先寫是IModel,而不是Model,那就是怎么樣的體驗(yàn)?zāi)?這就是將你的業(yè)務(wù)進(jìn)行抽象。在架構(gòu)的設(shè)計(jì)當(dāng)中,你只需要知道你要做些什么?而不需要去過多的關(guān)注你具體怎么去實(shí)現(xiàn)它,這才是設(shè)計(jì)。
(2)、設(shè)計(jì)思維
面向過程(Procedure Oriented)
眾所周知,在C語言的開發(fā)中,我們的邏輯大多是根據(jù)任務(wù)的流程走。這是面向過程的典型例子。面向過程關(guān)注的是工作的流程、一步一步的完成任務(wù)。
面向?qū)ο?Object Oriented)
Java語言作為面向?qū)ο箝_發(fā)的典型代表,這是我們所熟知的。我們將計(jì)算機(jī)按照人的思維來進(jìn)行設(shè)計(jì),每一個(gè)對(duì)象都持有自己的屬性,并且持有自己的操作方法。對(duì)象之間有繼承,組合等關(guān)系,通過組織這些關(guān)系來完成我們的程序。就像社會(huì)的人和物一樣,人與人之間各種復(fù)雜的關(guān)系組合完成了社會(huì)各項(xiàng)活動(dòng)的運(yùn)轉(zhuǎn)。
面向切面 (Aspect-Oriented)
面向切面是為彌補(bǔ)面向?qū)ο笾械囊恍┤毕荻?,我們將某些功能封裝到一起,提供對(duì)外的接口,方便在任何地方調(diào)用。就如SharedPreferences, Json, Xml, File, Device, System, Log, 格式轉(zhuǎn)換等,這些通常會(huì)在until包里邊。它就相當(dāng)于一個(gè)橫截面,我們可以隨時(shí)面向這個(gè)橫截面完成操作,而自己的邏輯里邊不再需要重復(fù)的設(shè)計(jì)。
面向服務(wù)
面向服務(wù)是將系統(tǒng)進(jìn)行拆分,分成一個(gè)個(gè)獨(dú)立的程序或組件,并對(duì)外提供某一項(xiàng)服務(wù)。每項(xiàng)服務(wù)之間通過某種協(xié)議進(jìn)行通信,并進(jìn)行分開部署,如HTTP,從而達(dá)到松耦合的目的。
以上四種思維重點(diǎn)在于看待問題的角度不同,不同的角度解決問題的方案就不一樣,當(dāng)然各種角度各有優(yōu)劣。那么對(duì)于在android開發(fā)中是否都只是按照OOP原則來設(shè)計(jì)呢?很顯然不是。面對(duì)不同的需求,不同的場(chǎng)景,我們需要及時(shí)調(diào)整自己的思維,靈活運(yùn)用,尋找最適合的角度,拿出最優(yōu)的設(shè)計(jì)方案,這才是我們所追求的。
(3)、設(shè)計(jì)原則
高內(nèi)聚
怎么理解高內(nèi)聚?我認(rèn)為我們?cè)诓鸱謺r(shí)某一細(xì)分領(lǐng)域只完成單一的功能,其內(nèi)部的事情自己處理。從表面來看比如一個(gè)model的class,對(duì)外提供了一個(gè)接口,那么他有一個(gè)輸入,一個(gè)輸出。單獨(dú)看這個(gè)接口而言,它是高內(nèi)聚的。當(dāng)然,其內(nèi)部的組織結(jié)構(gòu)有可能千差萬別,所以內(nèi)聚的形式又各有不同。所以我們將他們分類為功能內(nèi)聚、順序內(nèi)聚、時(shí)間內(nèi)聚等等。
低耦合
耦合指的是模塊之間存在依賴關(guān)系,關(guān)系相互依賴就會(huì)相互制衡,這是必然的。所以,如果耦合度太高的話,將會(huì)導(dǎo)致牽一發(fā)而動(dòng)全身的后果,這個(gè)使我們不想看到的,也極大的影響的程序版本的迭代以及bug的修復(fù)。根據(jù)依賴關(guān)系的不同,我們分為了非直接耦合、數(shù)據(jù)耦合、內(nèi)容耦合、開關(guān)耦合、控制耦合、外部耦合等等。我們要完成一個(gè)系統(tǒng)的開發(fā),必須要將各個(gè)模塊有效的組織起來,這種組織關(guān)系便無法避免存在了耦合,我們要做的是盡量減少這些依賴關(guān)系,尤其避免交叉依賴,將耦合度降低到最低,把我們的程序設(shè)計(jì)的更加的靈活。
適度設(shè)計(jì)
我們?cè)谠O(shè)計(jì)的時(shí)候如果考慮不周,那么設(shè)計(jì)不夠,不能滿足現(xiàn)有或者可預(yù)知的需求,從發(fā)展的眼光來看,會(huì)導(dǎo)致后期的開發(fā)中出現(xiàn)很多的問題。如果想的太多,很容易進(jìn)行過度的設(shè)計(jì),從而將一個(gè)簡單的系統(tǒng)設(shè)計(jì)的很復(fù)雜,那么就給當(dāng)前的開發(fā)將增加了許多無意義的工作,降低了開發(fā)效率。那么怎樣的設(shè)計(jì)才是合理的設(shè)計(jì)呢?我認(rèn)為能夠同時(shí)滿足現(xiàn)有的需求和可預(yù)知的需求,并且面對(duì)架構(gòu)的調(diào)整時(shí)能夠很方便的進(jìn)行擴(kuò)展。這樣的設(shè)計(jì),是非常好的設(shè)計(jì)。如何才能達(dá)到這樣的效果呢?我個(gè)人覺得在對(duì)系統(tǒng)進(jìn)行設(shè)計(jì)時(shí),關(guān)注點(diǎn)分離的顆粒度需要把握好,系統(tǒng)不過就是將不同單一小模塊進(jìn)行組織而已,那么這些細(xì)小的模塊就是架構(gòu)設(shè)計(jì)的基礎(chǔ),這就好比建房的那些磚頭。這些磚頭是什么呢?他么可以是是一個(gè)對(duì)外提供接口的公共方法,也可以是私有的內(nèi)部方法,也可以是某某持用的成員變量。當(dāng)然往大里看,他可以是某一個(gè)功能模塊。在上述行業(yè)內(nèi)各個(gè)app的架構(gòu)演進(jìn)中,都很強(qiáng)調(diào)進(jìn)行模塊化的改造。所以,分離好你的系統(tǒng),才能夠靈活的組織起來,以不變應(yīng)萬變。
(4)、設(shè)計(jì)方案
指導(dǎo)模型下圖在文中已經(jīng)提到,這里再次引入,因?yàn)檫@張圖對(duì)我的啟發(fā)真的很大,也表達(dá)出了我心之所想。面對(duì)一個(gè)復(fù)雜的系統(tǒng),我們?cè)趺礃尤シ蛛x,怎么樣去組織,我認(rèn)為這張圖已經(jīng)傳達(dá)出了其中的精髓,所以我認(rèn)為這是架構(gòu)設(shè)計(jì)的指導(dǎo)模型,無論你是什么MVC、MVP、MVVM之類的,都可以從中去理解。
模型分解
根據(jù)實(shí)踐開發(fā)中個(gè)人的理解,我將此圖再次進(jìn)行了簡化如下:
橫向分塊
根據(jù)上圖的簡化模型,我們可以這么理解,在橫向我們根據(jù)業(yè)務(wù)功能進(jìn)行模塊劃分。比如主題商店,我們可以分為壁紙、鈴聲等等模塊,每個(gè)模塊間解耦。同時(shí),在每一層的業(yè)務(wù)間再次進(jìn)行分塊,比如壁紙?jiān)跀?shù)據(jù)層就有圖片的請(qǐng)求、加載、緩存、裁剪處理等等。
縱向分層
接下來我們?cè)趯?duì)每個(gè)模塊的業(yè)務(wù)根據(jù)職責(zé)分為展現(xiàn)層、業(yè)務(wù)層、數(shù)據(jù)層。數(shù)據(jù)層主要負(fù)責(zé)數(shù)據(jù)的獲取、封裝等工作,業(yè)務(wù)層主要更加上層的需要調(diào)配各數(shù)據(jù)層最終將數(shù)據(jù)返回給展現(xiàn)層,展現(xiàn)層的工作就是將數(shù)據(jù)展現(xiàn)在UI界面上,并且響應(yīng)人的各種指令切換UI,操作新的數(shù)據(jù)。
接口通信
在橫向來看,我們將業(yè)務(wù)進(jìn)行了分塊,保證塊與塊之間相互之間沒有任何依賴,保證了絕對(duì)的解耦。從縱向來看,每個(gè)層級(jí)之間的依賴很明顯是無法避免的,所以我們可以保證上層僅依賴下層的接口,從而達(dá)到降低其耦合度的目的。
如上圖所示,通過上述橫向分塊、縱向分層、接口通信這三大步驟之后,我們可以將一個(gè)系統(tǒng)進(jìn)行了很好的分解,并得到一個(gè)理想模型。當(dāng)然,這是一個(gè)理想的模型。在我們的實(shí)際開發(fā)中可能無法避免一些交叉等特殊情況,我們還需要從實(shí)際情況出發(fā)。但是有一點(diǎn),我們可以保證接口的分離,已達(dá)到更低的耦合度的目的。
統(tǒng)一管理
統(tǒng)一管理,是對(duì)于我們的設(shè)計(jì)中有一些東西是需要統(tǒng)一管理起來的。通過上述原則,我們將一個(gè)復(fù)雜的系統(tǒng)進(jìn)行了拆解,已達(dá)到架構(gòu)設(shè)計(jì)中將關(guān)注點(diǎn)分離的目的。然而在實(shí)際的開發(fā)中,我們除了要進(jìn)行業(yè)務(wù)的分拆,也需要對(duì)某些業(yè)務(wù)進(jìn)行統(tǒng)一的管理。比如說一些模式的開關(guān)管理,比如說我們?cè)谶M(jìn)行網(wǎng)絡(luò)請(qǐng)求時(shí)需要在測(cè)試環(huán)境和正式環(huán)境之間的切換,我們可以將這些模式切換的開關(guān)放到一個(gè)地方,方便我們進(jìn)行管理,而不要去到各個(gè)地方去修改。再比如說我們的請(qǐng)求url地址,是否可以寫到一起進(jìn)行統(tǒng)一的管理。還有在某些應(yīng)用中會(huì)通過一個(gè)中間人來進(jìn)行統(tǒng)一管理數(shù)據(jù)的流通、頁面的跳轉(zhuǎn),這也是一個(gè)可以嘗試的方案,詳細(xì)請(qǐng)看蘇寧易購移動(dòng)端的架構(gòu)優(yōu)化實(shí)踐文中提到的模塊管理器、Url跳轉(zhuǎn)管理器。統(tǒng)一管理的意思就是將分拆的某一類小的模塊某一些特性放到某一處進(jìn)行統(tǒng)一的管理。但是這樣會(huì)存在一個(gè)問題,比如前面舉例說到的統(tǒng)一開關(guān)管理,這造成了開關(guān)耦合,如何去避免呢?我覺得可以將開關(guān)默認(rèn)寫到自己的模塊里邊,并公開出修改的接口,方便上層進(jìn)行統(tǒng)一的修改,以達(dá)到統(tǒng)一管理的目的。這樣的話,即使這個(gè)模塊拆離出來,也不會(huì)受到影響。但是,這樣的話,其安全性受到了一定的影響。架構(gòu)設(shè)計(jì)總是這樣,你總需要選擇一個(gè)折中適合自己的方案。
我們通過上述橫向分塊、縱向分層的方法將一個(gè)系統(tǒng)切成不同的小塊,這些小塊負(fù)責(zé)某一單一的職責(zé),然后通過接口將塊與塊之間進(jìn)行了間接性的連接,依賴的是接口而不是實(shí)例,以弱化這種模塊間通信造成的耦合。當(dāng)然,上述模型僅僅只是一個(gè)理想狀態(tài)的模型,如果是一個(gè)非常復(fù)雜的系統(tǒng),那么層級(jí)之間也能拆分出更多的層級(jí)。比如,在數(shù)據(jù)層,我們?cè)贛VP模式的開發(fā)下使用Model來完成,當(dāng)Model層的業(yè)務(wù)變得非常復(fù)雜時(shí),有部分人會(huì)考慮拆分出Data層放在最底層,最為最基礎(chǔ)的數(shù)據(jù)操作等。最后,為了方便我們對(duì)模塊進(jìn)行組合并進(jìn)行管理,我們可以考慮在小模塊中開放出接口,供上層進(jìn)行統(tǒng)一的控制管理。最后,我想說的時(shí),我們?cè)谶M(jìn)行業(yè)務(wù)分離拆解時(shí)可以考慮按照上述的方案來做,最終還得根據(jù)實(shí)際情況來進(jìn)行設(shè)計(jì)。
4、開發(fā)實(shí)現(xiàn)
當(dāng)完成我們的設(shè)計(jì)工作后,我們進(jìn)入了開發(fā)編碼階段,在這個(gè)階段主要表達(dá)我們的設(shè)計(jì),并最終取得實(shí)實(shí)在在的成果。當(dāng)進(jìn)入這個(gè)階段之前,我們的設(shè)計(jì)不能僅僅是一份文檔,而應(yīng)該是開發(fā)人員和架構(gòu)設(shè)計(jì)者達(dá)成的某種共識(shí)。再好的設(shè)計(jì),也需要獲得良好的表達(dá)和實(shí)現(xiàn)。下面主要談一談在實(shí)現(xiàn)過程中需要考慮的問題。
(1)、項(xiàng)目分包
項(xiàng)目的分包結(jié)構(gòu)體現(xiàn)一個(gè)軟件的架構(gòu),我們?cè)谶M(jìn)行分包的時(shí)候總有一種困惑。因?yàn)槲覀兇嬖诙喾N分法,比如我們可以分為根據(jù)類的功能分為activity、fragment、adapter、util等,有的時(shí)候,我們又根據(jù)功能模塊分,比如一鍵搜中有查單詞模塊、有搜題模塊,同時(shí)又存在網(wǎng)絡(luò)請(qǐng)求,軟件升級(jí)等小的外圍通用功能模塊。存在的問題就是模塊之間又存在一些可以復(fù)用的東西,那么我們進(jìn)行拆分明顯出現(xiàn)了代碼的冗余。如果按照兩種方案同時(shí)分,那就肯定存在了架構(gòu)的混亂。我們?cè)撊绾芜_(dá)到這兩種的平衡?我認(rèn)為,這個(gè)也需要更加項(xiàng)目的大小而來,如果是非常小的項(xiàng)目,也不存業(yè)務(wù)擴(kuò)展的可能,我們就可以采用上述的第一種方案,簡單的分類就好。但是,對(duì)于較大的項(xiàng)目,我建議使用第二種方案。下面,我簡單列一個(gè)模型僅供參考:
- + app
- +main
- +com.jfg
- +common //常用基礎(chǔ)業(yè)務(wù)
- +util
- +wedget
- +base
- +function //通用技術(shù)業(yè)務(wù)
- +camera
- +sensor
- +moudule //特定功能業(yè)務(wù)
- +mouduleA
- +model
- +presenter
- +view
- +mouduleB
- +model
- +presenter
- +view
- +mouduleC
- +demo //主程序
- +app
- +activity
如上所示,我們根據(jù)開始的項(xiàng)目業(yè)務(wù)拆分分包如上,將常用的基礎(chǔ)業(yè)務(wù)放到common包里邊,這個(gè)包在大多數(shù)情況是不變的,并且為app提供基礎(chǔ)性的服務(wù),不過我們盡量不要放到這個(gè)common包里邊,如果這個(gè)common包變得足夠大的時(shí)候,就一定要思考是不是該拆分了。因?yàn)閏ommon給人的感覺就是什么都是,那就讓我們無法快速認(rèn)知這個(gè)包所擔(dān)當(dāng)?shù)穆氊?zé)。我們可以這樣理解,common包是面向切面而設(shè)計(jì)的一些業(yè)務(wù),但也不是絕對(duì)的。接下來我們先聊module這個(gè)包,實(shí)際這里是將業(yè)務(wù)進(jìn)行了模塊化的分拆,如上我們拆分出了moudleA和moudleB,這兩者之間要求沒有任何的聯(lián)系。但是,我們會(huì)存在一個(gè)問題,那就是moudleA和moudleB某些業(yè)務(wù)是一樣的,我們拆開顯得重復(fù)了許多體力活。這應(yīng)該是大多數(shù)開發(fā)者面對(duì)的困擾,這種該怎么去平衡呢?我是這么考慮的。如果,moudle和moudleB存在重疊的業(yè)務(wù),我們將這些業(yè)務(wù)提取到function包或者common包中,這樣降低了業(yè)務(wù)的層級(jí)。我們?cè)试Smoudle包的各模塊業(yè)務(wù)依賴于function和common為我們提供的基礎(chǔ)服務(wù)。為了更好的區(qū)分模塊A和模塊B雖然重疊但在邏輯上是各自屬于各自的,我們有兩種方法來做。第一種是將兩種業(yè)務(wù)進(jìn)行一定的抽象,實(shí)現(xiàn)的過程還是放到各個(gè)moudle業(yè)務(wù)中。第二種方案定義兩個(gè)接口類,各自定義各自的接口。在具體的實(shí)現(xiàn)類中實(shí)現(xiàn)了這兩個(gè)接口類的方法,內(nèi)部在進(jìn)行相同的邏輯操作。這樣,對(duì)外看來,邏輯上moudleA和moduleB是分離的??傊?,如何分包還得權(quán)衡利弊,盡量以一種思維來進(jìn)行劃分,以避免設(shè)計(jì)混亂。
(2)、抽象接口
如果說在架構(gòu)設(shè)計(jì)中抽象很重要,你可能有些迷糊,但是如果要你先寫interface或者abstract class 而不是class時(shí),你就可能感覺得到抽象的意義。我們將一個(gè)系統(tǒng)分解成幾個(gè)大的模塊,一個(gè)模塊查分成不同的層級(jí),每個(gè)層級(jí)再次拆分成不同的細(xì)節(jié)業(yè)務(wù)。最后,我們很清晰的知道我們要完成某一項(xiàng)功能需要做哪些事?對(duì)的,做哪些事就就是一個(gè)個(gè)接口,我們?cè)诰幋a時(shí)先寫接口再寫實(shí)現(xiàn)有利于幫助我們對(duì)業(yè)務(wù)進(jìn)行拆分和抽象。我們都知道做一件事情一般情況都需要提供一些條件,做完了會(huì)有返回結(jié)果。這些都可以在接口的設(shè)計(jì)中完成。我們需要注意是一個(gè)接口只做一件事情,如果有兩件事非常相似也要盡量拆分而不是合并。在接口命名方面做到見名知意,怎么去評(píng)判,就是如果你的接口沒有注釋也同樣能讓人知道你的接口是做什么的就好。
(3)、數(shù)據(jù)存儲(chǔ)
數(shù)據(jù)存儲(chǔ)常用的有SQLite、SharedPreference、文件等,緩存是否也可以算是一種。這里想強(qiáng)調(diào)的就是要注意數(shù)據(jù)存儲(chǔ)的規(guī)范性以及安全性,如果是數(shù)據(jù)庫還有必要考慮其擴(kuò)展性,如果不滿足需求將會(huì)需要進(jìn)行升級(jí)。
(4)、性能管理
這里源自于對(duì)性能優(yōu)化的一點(diǎn)體會(huì),對(duì)于服務(wù)端的開發(fā)我們很珍惜服務(wù)器資源,應(yīng)該是看的見的需要銀子買的。然而,對(duì)于客戶端的開發(fā)我們常常忽略了這一點(diǎn)。雖然手機(jī)設(shè)備現(xiàn)在擁有大內(nèi)存,但是如何寫出一個(gè)優(yōu)秀的程序,性能也是一個(gè)非常重要的指標(biāo)。性能優(yōu)化處理,那是我們?cè)诟e(cuò)誤,那么之后應(yīng)該是少犯錯(cuò)誤。性能體驗(yàn)不夠好,無非就是對(duì)機(jī)器設(shè)備的內(nèi)存、CPU、GPU資源無節(jié)制的使用,造成資源的浪費(fèi),當(dāng)機(jī)器設(shè)備無法承受時(shí)就會(huì)應(yīng)用就會(huì)出現(xiàn)卡段、死機(jī)、異常等不良反應(yīng),嚴(yán)重影響了應(yīng)用的體驗(yàn)。我們要做的就是要有很強(qiáng)的性能管理意識(shí),對(duì)于內(nèi)存、CPU、GPU等資源按需借用,并做到有借有還,即用完后記得釋放資源。
(5)、特殊處理
我們?cè)陂_發(fā)的過程中,總有那么多問題并不是按照正常思路出牌的,這些得歸功于我們強(qiáng)大的測(cè)試團(tuán)隊(duì)。不同的手法,就能得到不同的結(jié)果,然后就給了我們一堆的bug。所以,我們?cè)谲浖拈_發(fā)中需要特別注意一些特殊情況的處理,這些最終往往還是邏輯上的死角。以下簡單總結(jié)了一些:
功能沖突
功能沖突可以分為兩種,一個(gè)是應(yīng)用內(nèi)部的功能沖突,二是應(yīng)用之間的功能沖突。應(yīng)用內(nèi)沖突比如A功能和B功能都使用了某資源文件,如果在同時(shí)使用就會(huì)出現(xiàn)問題,我們通常加同步鎖來防止這種沖突。應(yīng)用外的沖突有很多,比如多媒體、鬧鐘、日歷、鈴聲、電話等都肯能引起這些沖突,比如你正在播放一段視頻,這個(gè)時(shí)候來了一個(gè)電話,那我該優(yōu)先哪一個(gè)呢?還有當(dāng)鬧鐘響起的時(shí)候,彈出一個(gè)界面是豎屏的,那么他就會(huì)強(qiáng)制將當(dāng)前的界面變?yōu)樨Q屏,而如果你這個(gè)時(shí)候如果是橫屏的話該怎么辦呢?類似于這類還有很多,以后再細(xì)細(xì)總結(jié)。
極限操作
我們的測(cè)試人員喜歡對(duì)著某一個(gè)按鈕狂點(diǎn)、或者在機(jī)器上安裝無數(shù)的應(yīng)用使內(nèi)存爆滿,或者在磁盤里邊塞滿各種文件。這些場(chǎng)景雖然并不是理性的用戶所出現(xiàn)的,但實(shí)際也是程序的缺陷。所以,我們要注意對(duì)這些問題進(jìn)行處理。
網(wǎng)絡(luò)問題
不可用的網(wǎng)絡(luò),信號(hào)很弱的網(wǎng)絡(luò),網(wǎng)路在wifi和流量之間切換,2G網(wǎng)絡(luò)和4G網(wǎng)絡(luò),網(wǎng)絡(luò)請(qǐng)求超時(shí)等都需要我們針對(duì)實(shí)際情況進(jìn)行處理,比如切回到流量的時(shí)候進(jìn)行下載是否有提醒用戶。這些處理也算是各個(gè)應(yīng)用的標(biāo)配了,就不再多說了。
為null處理
這應(yīng)該是最常見的問題了,我們平時(shí)改bug或者從后臺(tái)異常抓取的大多數(shù)都是空指針異常。首先,我們得搞清楚為null的原因是什么?然后我們需要進(jìn)行為null的判斷,并警告。
(6)、Log打印
這里把Log打印單獨(dú)拿出來是應(yīng)為我覺得很需要重視。Log是用來干嘛的?很顯然是用來幫助我們查找問題的,然后我們大多數(shù)的情況下是問題來了再去加打印,并且TAG五花八門的,是有錯(cuò)誤的地方用Log.d,而只是查看信息卻是用的Log.e,我們查問題的時(shí)候要去閱讀很多的代碼邏輯,最后再定位到位置。我們?cè)谛迯?fù)bug的時(shí)候花了大量的時(shí)候再閱讀代碼,這個(gè)太影響工作效率了。如果我們?cè)诰幋a之初就對(duì)Log有了很好的規(guī)范設(shè)計(jì),有異常的地方就用Log.e,可能出現(xiàn)問題的地方就用Log.w等等,關(guān)鍵點(diǎn)的信息用Log.i,臨時(shí)調(diào)試的用Log.d這樣區(qū)分不是很好嗎?我們?cè)诳刂婆_(tái)一樣就能夠分辨自己需要的信息。我們應(yīng)該充分應(yīng)用這個(gè)工具,幫助我們快速定位問題。
(7)、軟件重構(gòu)
重構(gòu)是因?yàn)闃I(yè)務(wù)的需要,也是因?yàn)閷?duì)代碼更高的質(zhì)量要求,重構(gòu)無處不在。我們不要為了重構(gòu)而重構(gòu),也不要一直停滯不前,該重構(gòu)時(shí)不重構(gòu),欠下太多的技術(shù)債務(wù)。重構(gòu)有小到一個(gè)方法的重構(gòu),也有大到整個(gè)系統(tǒng)架構(gòu)的重構(gòu)。重構(gòu)是軟件迭代升級(jí)的一個(gè)必要過程,也是我們能夠滿足當(dāng)前需要,并且能夠適應(yīng)未來的發(fā)展,獲得良好的擴(kuò)展性的必要手段。重構(gòu)并不難,也不是什么大事,重點(diǎn)在于重構(gòu)背后的目的、思想、設(shè)計(jì)是否清晰。
(8)、兼容適配
兼容適配的問題是我們開發(fā)一個(gè)頭疼的問題,Android設(shè)備無法八門的屏幕尺寸、層次不齊的Android系統(tǒng)版本。除了進(jìn)行針對(duì)性的處理,還得提醒產(chǎn)品設(shè)計(jì)人員在設(shè)計(jì)之初就得考慮兼容性問題。
5、軟件測(cè)試
軟件測(cè)試是我們開發(fā)中非常重要的一到工序,除了能夠客觀的感應(yīng)我們所開發(fā)的軟件質(zhì)量水平,最終目的還是在于幫助開發(fā)人員修復(fù)軟件缺陷,提高軟件的質(zhì)量。除了開發(fā)人員提交測(cè)試之前的自測(cè),我們需要專業(yè)的測(cè)試人員來進(jìn)行測(cè)試。人工測(cè)試的效率相對(duì)較低,所以我們應(yīng)該考慮通過技術(shù)手段完成自動(dòng)化的測(cè)試,如單元測(cè)試等。這樣有利于軟件的穩(wěn)定,也同樣的有助于開發(fā)人員提高代碼質(zhì)量。
6、開發(fā)規(guī)范
(1)、設(shè)計(jì)一致
什么樣的設(shè)計(jì)才是有規(guī)范的設(shè)計(jì)呢?我個(gè)人認(rèn)為一個(gè)項(xiàng)目保持一致的設(shè)計(jì)思想就是有規(guī)范的設(shè)計(jì)。我們可以這樣去理解,在某一類的情況下,我們按照某一類似的方案來解決這一類問題。面對(duì)復(fù)雜的系統(tǒng),我們一種設(shè)計(jì)思想也許無法滿足架構(gòu)的需求,但是我們只需要明白,這種事情這么干,那種事情那么干,相互之間靈活的組合卻也不存在交叉,給人設(shè)計(jì)思路清晰的感覺。
(2)、編碼清晰
什么樣的代碼才是高質(zhì)量的代碼?我覺得結(jié)構(gòu)簡單,邏輯清晰,一看就懂的代碼就是一份高質(zhì)量的代碼。所以,我們可以拋開那些編碼規(guī)范、命名規(guī)范等等,重新去審視自己的代碼,看看讀起來是不是很舒服。如果來了一個(gè)新同事,對(duì)你對(duì)項(xiàng)目一無所知,是否能夠很快速的理解你的思維?最后幾點(diǎn)有必要提出,一是慎用設(shè)計(jì)模式,二是盡量少寫文檔注釋,三是遵循Java的面向?qū)ο罅笤O(shè)計(jì)原則。我想這三點(diǎn)就是編碼的原則,遵守這些原則,形成一種習(xí)慣,自然而然就是一種規(guī)范。
(3)、文檔有效
什么樣的文檔才是有效的文檔,我認(rèn)為能說明核心問題的文檔就是有效的文檔。作為軟件開發(fā)人員,我們沒有耐心去閱讀一份復(fù)雜啰嗦的文檔。文檔只需要給我們呈現(xiàn)代碼無法說明的問題,幫助我們快速理解項(xiàng)目結(jié)構(gòu),備忘重點(diǎn)問題,追溯歷史記錄。文檔的形式又很多,比如我們Git的提交記錄、tag,項(xiàng)目結(jié)構(gòu)圖、核心功能流程圖等??傊?,文檔是給人看的,以盡量少的文檔來說明核心問題就好。
7、日常工作
作為一名合格的軟件開發(fā)人員,我們有許多的日常工作,如Bug修復(fù)、異常處理、Monkey、性能優(yōu)化、代碼質(zhì)量改善等待。這些事情并一定要求你每天都要做,但是每天都得關(guān)注,做到心中有數(shù)。如此,才能夠培養(yǎng)一個(gè)很好的編程習(xí)慣,寫出優(yōu)秀的代碼,優(yōu)秀的程序。
六、統(tǒng)籌規(guī)劃
1、開發(fā)驅(qū)動(dòng)
一個(gè)項(xiàng)目的正常運(yùn)轉(zhuǎn)一定是由某一方主導(dǎo)項(xiàng)目的進(jìn)行,不斷的提出產(chǎn)品需求,并組織項(xiàng)目成員分工合作,完成產(chǎn)品的開發(fā)交付,以下是兩種驅(qū)動(dòng)開發(fā)模型。
TDD:測(cè)試驅(qū)動(dòng)開發(fā)(Test-Driven Development)
測(cè)試驅(qū)動(dòng)開發(fā)指的是由測(cè)試主導(dǎo)開發(fā)的工作,從產(chǎn)品的使用出發(fā),對(duì)產(chǎn)品的功能提出測(cè)試要求,組織項(xiàng)目中各個(gè)角色完成開發(fā)任務(wù)。
BDD:行為驅(qū)動(dòng)開發(fā)(Behavior Driven Development)
敏捷開發(fā)便是行為驅(qū)動(dòng)的開發(fā),更加強(qiáng)調(diào)產(chǎn)品的設(shè)計(jì),鼓勵(lì)項(xiàng)目中各個(gè)角色提出自己對(duì)項(xiàng)目開發(fā)的觀點(diǎn),已獲得更優(yōu)秀的產(chǎn)品功能,完成產(chǎn)品的開發(fā)。
2、敏捷開發(fā)
下圖引自網(wǎng)絡(luò)上的一張關(guān)于敏捷開發(fā)的圖片,目前我們團(tuán)隊(duì)基本也是根據(jù)這個(gè)模型進(jìn)行敏捷開發(fā)的。我覺得在敏捷開發(fā)中更加強(qiáng)調(diào)的各個(gè)角色之間的隨時(shí)溝通和快速響應(yīng),我們并不對(duì)整個(gè)系統(tǒng)進(jìn)行一份完整而詳細(xì)的設(shè)計(jì),而是進(jìn)行階段的設(shè)計(jì)開發(fā)工作,并謀求不斷的迭代更新。在敏捷開發(fā)的過程中,普遍存在的問題就是溝通不及時(shí)、產(chǎn)品變動(dòng)大,所以如何動(dòng)態(tài)的進(jìn)行統(tǒng)籌管理變的非常重要。我們通過需求評(píng)審、交互評(píng)審、視覺評(píng)審、Bug評(píng)審等由各個(gè)有關(guān)角色的人員參加評(píng)審會(huì)議,共同完成決策,以保證軟件開發(fā)的順利進(jìn)行。不得不說,這個(gè)過程中還是存在許多的問題,溝通的問題,產(chǎn)品變動(dòng)的問題,產(chǎn)品功能細(xì)節(jié)開發(fā)過程的中流程性的問題等等,在此不詳細(xì)說了,后期有時(shí)間再進(jìn)行總結(jié)。
3、達(dá)成共識(shí)
敏捷開發(fā)中有一個(gè)特點(diǎn)就是,產(chǎn)品開發(fā)決策是由項(xiàng)目各個(gè)角色成員共同完成的,各個(gè)角色領(lǐng)域的問題又是由該角色自身最終拍板。那么隨之而來的就出現(xiàn)了一個(gè)問題,各個(gè)角色所決定的問題又被其他的角色所制衡。比如說,產(chǎn)品經(jīng)理設(shè)計(jì)的功能在開發(fā)人員而言存在技術(shù)難題,交互的設(shè)計(jì)存在邏輯上的漏洞。我想,這些問題是一個(gè)產(chǎn)品不能按照預(yù)期時(shí)間完成的真實(shí)原因。那么,哪一個(gè)角色來統(tǒng)籌管理這些問題呢?通常,我們有架構(gòu)師、項(xiàng)目經(jīng)理、老板等等角色來對(duì)項(xiàng)目進(jìn)行把控和管理。
軟件架構(gòu)的設(shè)計(jì)來源于產(chǎn)品的需求,并決定了產(chǎn)品的最終形態(tài)。然而處于敏捷開發(fā)中的我們而言,產(chǎn)品的需求變化很快,同時(shí)要求我們開發(fā)人員能夠快速響應(yīng)這種變化。那么,如何保持軟件的整體架構(gòu)和產(chǎn)品的設(shè)計(jì)同步更新就顯的非常重要。
對(duì)于開發(fā)者而言,我們首先要對(duì)項(xiàng)目有一個(gè)整體的認(rèn)知,隨時(shí)掌握產(chǎn)品的動(dòng)態(tài)。這些包括產(chǎn)品的設(shè)計(jì)、迭代計(jì)劃、開發(fā)資源、質(zhì)量要求、交付要求、風(fēng)險(xiǎn)規(guī)避方案等。然后根據(jù)產(chǎn)品的需求變化,動(dòng)態(tài)調(diào)整自己的軟件架構(gòu),這些工作包括,技術(shù)選型、架構(gòu)設(shè)計(jì)、代碼重構(gòu)、文檔更新等,以適應(yīng)新的需求,并把這種架構(gòu)共享給相關(guān)人員以達(dá)成共識(shí)。這種共識(shí),是需要對(duì)產(chǎn)品和技術(shù)進(jìn)行統(tǒng)籌規(guī)劃才能夠完成的。也只有項(xiàng)目各個(gè)相關(guān)利益人員能夠達(dá)成這種共識(shí),我們的溝通才會(huì)更有效,才能做出各方人員都滿意的產(chǎn)品。
七、總結(jié)
寫到最后,我回過頭來看看,才發(fā)現(xiàn)對(duì)架構(gòu)的整體認(rèn)識(shí)站在了決策派的一邊,即這種共識(shí)便是在產(chǎn)品規(guī)劃、設(shè)計(jì)、開發(fā)階段一些重要方面所作出的決策的集合。這些決策是我們項(xiàng)目各個(gè)角色成員通過計(jì)劃會(huì)、評(píng)審會(huì)、迭代會(huì)等達(dá)成的共識(shí),并最終表現(xiàn)在我們的產(chǎn)品上。產(chǎn)品、交互、UI、開發(fā)、測(cè)試,每個(gè)角色對(duì)自己所在領(lǐng)域負(fù)責(zé)的同時(shí)也需要隨時(shí)掌握其他領(lǐng)域的信息,以便自己做出正確的決策。但是在對(duì)軟件技術(shù)實(shí)現(xiàn)的架構(gòu)設(shè)計(jì)上,我就偏向了組成派,將軟件系統(tǒng)的業(yè)務(wù)進(jìn)行了拆分和組合,已達(dá)成系統(tǒng)運(yùn)轉(zhuǎn)。我必須承認(rèn),此刻我的認(rèn)識(shí)還是不夠通透,在本文中各個(gè)方面大多還是泛泛而談,每個(gè)問題深入下去還有許多可以去研究的,希望能夠在以后的工作能夠有更深刻的領(lǐng)悟。
八、 參考文獻(xiàn)
- 《小鋼的架構(gòu)思考系列》
- 餓了么移動(dòng)APP的架構(gòu)演進(jìn)
- 攜程移動(dòng)App架構(gòu)優(yōu)化之旅
- 糯米移動(dòng)組件架構(gòu)演進(jìn)之路
- 蘇寧易購移動(dòng)端的架構(gòu)優(yōu)化實(shí)踐
- Android App 整體架構(gòu)設(shè)計(jì)的思考
- android開發(fā)一般都使用什么框架?
- 手機(jī)天貓解耦之路
- 什么是 Agile Software Development(敏捷軟件開發(fā))?
- 《架構(gòu)之美》
- 《軟件架構(gòu)設(shè)計(jì)》
后記
經(jīng)過這段時(shí)間對(duì)架構(gòu)的學(xué)習(xí)和思考,我發(fā)現(xiàn)這些理論不僅可以運(yùn)用在軟件架構(gòu)中,同樣也適用于工作、生活當(dāng)中。試著將我們的工作任務(wù)進(jìn)行分離,減少每項(xiàng)任務(wù)之間的交叉,避免東一榔頭西一棒子,有條理的完成各項(xiàng)工作。這樣一來,你的工作目標(biāo)是清晰的,也更加容易的完成既定目標(biāo)。同樣的,我們可以通過這一理論還規(guī)劃自己的人生。將我們的事業(yè)、家庭、興趣愛好分離,再對(duì)每一項(xiàng)分離出更細(xì)的關(guān)注點(diǎn),每個(gè)關(guān)注點(diǎn)在不同的階段定下自己小目標(biāo)。這樣,我們對(duì)自己就可以有了更清晰的認(rèn)識(shí),認(rèn)識(shí)自己已經(jīng)擁有什么?最終想要什么?計(jì)劃怎么做?當(dāng)前怎么做?當(dāng)然,并不是每一步都是能夠按照既定目標(biāo)走的,我們需要不斷的更新對(duì)自己的認(rèn)識(shí),做出更加合適的決策。