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