開發(fā)ios app相關(guān)那些事

自從做Team Leader之后,身上權(quán)責(zé)發(fā)生了變化,于是讓我煩惱的不再是具體某個功能,某個界面的實現(xiàn),而是如何在現(xiàn)有代碼的基礎(chǔ)上做漸進式的改進,創(chuàng)造出比較合適規(guī)范和框架,使得組內(nèi)成員更快更好地完成任務(wù)。


合適的人

首先明確一點,合適的人是指純技術(shù)團隊的建設(shè)。一支戰(zhàn)斗力再強的技術(shù)團隊,面對一個朝三暮四,分分鐘推翻自己原有想法的產(chǎn)品經(jīng)理/項目經(jīng)理,再好的戲也唱不出來。花幾個月加班加點做項目,還沒發(fā)布,直接推翻重做,這時候你就得去樓下ATM機看看卡內(nèi)余額了:余額夠了,收拾收拾好找下一家了。

計算機界有句名言:計算機相關(guān)的所有問題都可以通過增加一個額外的抽象層來解決。但是軟件開發(fā)卻不是這樣:增加層(人手)在一定程度上可以加快開發(fā)進度,當(dāng)過了某個閾值后其效果就顯得不是那么明顯,甚至?xí)鸱葱Чτ谝粋€項目而言需要的往往不是更多的成員,而是適量的合適成員。每一個人因為不同的教育背景,從業(yè)背景,項目經(jīng)歷(技術(shù)選型,學(xué)習(xí)經(jīng)歷,項目管理)對程序開發(fā)都會有不同的理解和思維模式。反應(yīng)在業(yè)務(wù)上就是各種各樣的代碼風(fēng)格。舉例來說:有些人恨不得把所有單一功能都一一獨立出來封裝成類,而有些人卻喜歡一個大類洋洋灑灑寫上上千行。大部分情況下我都是傾向于前者,但是就像我時常吐槽的那樣:It depends。不僅僅是軟件開發(fā),幾乎所有的事到最終都會歸結(jié)到一個統(tǒng)一的問題上:怎樣才是一個度?一群理念相去甚遠的人在一起工作是件異常痛苦的事:相當(dāng)一部分的時間會浪費在解釋,爭論和排遣由此帶來的沮喪和憤怒上。古人語:道不同,不相為謀。但到了真正的工作中卻不能如此隨性,缺乏足夠動力的老人,能力出眾的技術(shù)骨干,干勁十足卻缺乏經(jīng)驗的新人都需要互相體諒,學(xué)習(xí)和磨合。所以大部分的創(chuàng)業(yè)團隊的技術(shù)團隊因為理念相近,往往效率會足夠高,而大公司內(nèi)的開發(fā)小組卻永遠無法達到那樣的效率,更需要相應(yīng)的規(guī)范和程序框架。

得出上面這個結(jié)論的另一個理由是我對人的可塑造性是持悲觀態(tài)度的:多數(shù)人并沒有跳出自己思維局限性的意愿,動力和能力。少數(shù)人在沒有任何外界壓力的情況下仍會不斷總結(jié)學(xué)習(xí)進步(主動學(xué)習(xí)型),而其余的人要么沒有任何意愿,關(guān)心的只是完成任務(wù)和拿到工資而已,要么想要進步而不得法。而你的團隊不可能全由主動學(xué)習(xí)型的成員組成,這時候規(guī)范和程序框架的引入才能夠讓各種類型的人更好的合作。


合適的規(guī)范

大家都理解軟件開發(fā)需要合適的規(guī)范:代碼規(guī)范,程序規(guī)范,流程規(guī)范等等,以此來減少意外的出現(xiàn):最少驚訝原則。但在實際執(zhí)行中卻會碰到各種情況,其中最大的問題是:怎么鑒別哪些規(guī)范是需要強制執(zhí)行,哪些規(guī)范是推薦執(zhí)行。規(guī)范的強制執(zhí)行帶來的是代碼的可讀性提升和二義性減少,而壞處也是顯而易見的:對于大部分有想法的程序員而言這種規(guī)定太死板,容易引起抵觸心理,產(chǎn)生不安定因素。這種情況常見于各種標(biāo)準(zhǔn)的外包公司。而如果大部分的規(guī)范設(shè)定為推薦執(zhí)行,在沒有良好的引導(dǎo)下,規(guī)范容易被忽視。 網(wǎng)上有很多關(guān)于ObjC的代碼規(guī)范,比如蘋果自家的規(guī)范和《Google Objective-C Style Guide》等。這些規(guī)范一般只有兩種分級:推薦和不推薦。而我更推薦把代碼規(guī)范分成五個等級:強制要求,強烈推薦(但不強制),良好,可接受和不可接受。以下僅舉部分例子加以說明。


符合蘋果規(guī)范的命名方式。

1-類名開頭大寫,方法和變量名以駝峰法命名。強烈要求,這沒有什么好說的,蘋果系統(tǒng)類庫和絕大多數(shù)的第三方開源庫都是如此。但在部分蘋果的sample中也看到過用m做前綴表示類成員變量的寫法,這些都是屬于遺產(chǎn)代碼的問題,仍舊是可接受范圍,但是自己代碼內(nèi)部使用類似匈牙利的命名法就是不可接受。

2-類名使用至少三個字符做前綴,內(nèi)部方法使用兩個下劃線做前綴。強烈推薦。上面的做法可以最大程度避免和系統(tǒng)類庫發(fā)生重名的情況:因為蘋果宣稱保留所有兩位字符前綴的使用權(quán),同時其內(nèi)部方法命名以一個下劃線做前綴。

3-使用K&R Style還是Allman Style都是可接受的范圍,但是強烈推薦在一個文件內(nèi)保持一種形式。

4-在保證代碼可讀性的基礎(chǔ)上保持代碼的簡短和統(tǒng)一性:小類,小方法,統(tǒng)一的函數(shù)返回。小類,小方法可以保證他人閱讀時更方便地關(guān)注類邏輯,而不是具體細節(jié),而統(tǒng)一的函數(shù)返回可以減少意外錯誤和降低錯誤排查的難度。而保證代碼的簡短和不羅嗦也是很重要一點,經(jīng)常會看到如下代碼: > (count > 1) { return YES; } { return NO; }

真心無法直視。


良好的代碼/工程結(jié)構(gòu)

為整個工程創(chuàng)建worksapce。

按照權(quán)責(zé)分門別類存放資源文件:每種類型的資源存放于獨立的目錄下:圖片,聲音,配置文件等等。而圖片又可以按照類型分別存放在不同的子目錄下:全局類型,背景圖,logo,登錄等等。

合理的代碼結(jié)構(gòu)。推薦如下的工程目錄結(jié)構(gòu)

Core:工程內(nèi)一些通用的機制實現(xiàn)類:統(tǒng)一的任務(wù)管理,模塊管理,服務(wù)管理。

General:公用類和方法,包括工程內(nèi)ViewController,UITableViewCell基類(Base),公用Category(Category),公用UI組件(CustomUI),公用輔助方法(Helper)和宏定義(Marco)。

Model:公用數(shù)據(jù)模型

Sections:不同程序單元。如登錄,設(shè)置等等。其下又可以按照功能分成不同的子目錄:當(dāng)前單元使用的自定義UI組件,管理類,數(shù)據(jù)模型和ViewController等等。

Vendors:第三方庫。


合適的框架

一個合適的框架不是銀彈,在我看來框架要解決的問題從來不是:有了框架之后,工程就能無比正確地進行下去。好的框架能夠做到的事僅僅只是:降低通用問題的復(fù)雜度和減少發(fā)生錯誤的可能性。個人認為一個良好iOS App框架應(yīng)該是有如下特點:


定義清晰的層次結(jié)構(gòu)

橫向上,各模塊互相獨立,僅通過有限的幾個接口進行通訊。最理想的狀態(tài)是除核心模塊外,其他模塊都是可拔插。縱向上,各層次間依賴關(guān)系清晰,基本不出現(xiàn)逆向依賴的情況。

橫向模塊一般依賴于業(yè)務(wù)需求,常被定義成各種Service或Manager。一種好的做法是有個統(tǒng)一的Service管理器負責(zé)相應(yīng)Serivce的加載,卸載,監(jiān)聽和分發(fā)App級別的通知給相應(yīng)Service,如前后臺切換,收到內(nèi)存警告等。這樣做一方面容易實現(xiàn)上面說的模塊的可插拔化,另一方面也保證了公用特性處理的一致性。在這方面微信就做得不錯,基本所有的模塊都是從MMService繼承而來,由MMServiceCenter進行管理。當(dāng)然從dump出來的頭文件也可以發(fā)現(xiàn)一些管理上的紊亂,比如一些ViewController都是繼承自MMService。

縱向的層次劃分基本各個App不會有太大區(qū)別,一般可以分為三個層次:


展現(xiàn)層(Presentation layer),負責(zé)管理UI和UIViewController

邏輯層(Business/Service Layer),負責(zé)邏輯數(shù)據(jù)的定義和轉(zhuǎn)發(fā),起到承上啟下的作用。

數(shù)據(jù)訪問層(Data Access Layer),負責(zé)具體API構(gòu)造,網(wǎng)絡(luò)請求,數(shù)據(jù)持久化等。


各層根據(jù)業(yè)務(wù)邏輯的復(fù)雜性內(nèi)部又會使用單層或者多層結(jié)構(gòu)。以數(shù)據(jù)訪問層為例,一般又可以細分為網(wǎng)絡(luò)層,持久化層。而一般而言,展現(xiàn)層(UIView和UIViewController)都是直接使用邏輯層提供的Model進行展現(xiàn),但是某些場景下往往需要不同的Model有相同的界面展示(如我們的App易信中,會話界面,收藏界面,問一問功能都需要進行圖片的展現(xiàn),但這三個模塊下的Model定義并不一致),這就需要增加額外的ViewModel層用于粘合展現(xiàn)層和邏輯Model。

遵守SOLID原則和慎用各種設(shè)計模式。這是個老生常談的話題了,并不是iOS開發(fā)獨有,展開講可以講上幾天幾夜,不贅述。

定義自己的UI基類:UIView,UIViewController,UITableviewCell。這一點的好處不言而喻,所有的子View,Controller,Cell都能夠很方便的繼承基類的共有的行為,樣式。但也會引進很大的管理風(fēng)險:組內(nèi)成員總會經(jīng)不起誘惑往基類塞各種并不普適的特性,引起基類權(quán)責(zé)的無限膨脹。大基類不僅增加組內(nèi)成員對代碼的理解難度,同時也增加出現(xiàn)問題時的排查難度。從這方面講,微信的UIViewController基類設(shè)計就極端失敗:MMUIViewController這個類光頭文件就有上百行。

提供方便好用的工具類。一些好用的工具類往往會成為框架重要的有機組成部分,方便快捷地解決局部問題,同時又不引入過多的復(fù)雜度。NSTimer的retain cycle是個很容易掉去的坑,那么提供一個基于Block或者weak delegate的NSTimer的封裝就是不錯的選擇。使用KVO容易發(fā)生add和remove的不配對調(diào)用,那么就引入THObserversAndBinders或者FB的KVOContorller。某些核心模塊需要被多個模塊依賴時,引入類似XMPP的GCDMulticastDelegate就能夠方便地進行解耦。

好的范例。在前幾年使用C++的那段暗無天日的日子里,我常想的一個問題是:如何在API層面去限制和規(guī)避一些錯誤。比如往線程池里面扔的task必須是堆上分配的對象,那么如何去強制傳入的指針指向的是堆地址而不是棧地址呢?這種傻問題大部分情況下是無解的,有時候有解卻是個異常別扭的解。而現(xiàn)在我更相信破窗理論所提供的可能性:做好示范,接下來的一切都會水到渠成。


最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

推薦閱讀更多精彩內(nèi)容