项望烽:iOS App开发的那些事儿
作者:項(xiàng)望烽
畢業(yè)于浙江大學(xué)
網(wǎng)易云信 iOS端研發(fā)負(fù)責(zé)人?
自從做了Team Leader之后,身上權(quán)責(zé)發(fā)生了變化,于是讓我煩惱的不再是具體某個(gè)功能、界面的實(shí)現(xiàn),而是如何在現(xiàn)有代碼的基礎(chǔ)上做漸進(jìn)式的改進(jìn),創(chuàng)造出比較合適規(guī)范和框架,使得組內(nèi)成員更快更好地完成任務(wù)。一年下來(lái),頗有點(diǎn)想法,于是啰嗦幾句關(guān)于iOS App開發(fā)的那些事兒。
1
合適的人
首先明確一點(diǎn),合適的人是指純技術(shù)團(tuán)隊(duì)的建設(shè)。一支戰(zhàn)斗力再?gòu)?qiáng)的技術(shù)團(tuán)隊(duì),面對(duì)一個(gè)朝三暮四,分分鐘推翻自己原有想法的產(chǎn)品經(jīng)理/項(xiàng)目經(jīng)理,再好的戲也唱不出來(lái)。花幾個(gè)月加班加點(diǎn)做項(xiàng)目,還沒發(fā)布,直接推翻重做,這時(shí)候你就得去樓下ATM機(jī)看看卡內(nèi)余額了:余額夠了,收拾收拾好找下一家了。
計(jì)算機(jī)界有句名言:計(jì)算機(jī)相關(guān)的所有問題都可以通過增加一個(gè)額外的抽象層來(lái)解決。但是軟件開發(fā)卻不是這樣:增加層(人手)在一定程度上可以加快開發(fā)進(jìn)度,當(dāng)過了某個(gè)閾值后其效果就顯得不是那么明顯,甚至?xí)鸱葱Ч?duì)于一個(gè)項(xiàng)目而言需要的往往不是更多的成員,而是適量的合適成員。每一個(gè)人因?yàn)椴煌慕逃尘?#xff0c;從業(yè)背景,項(xiàng)目經(jīng)歷(技術(shù)選型,學(xué)習(xí)經(jīng)歷,項(xiàng)目管理)對(duì)程序開發(fā)都會(huì)有不同的理解和思維模式。反應(yīng)在業(yè)務(wù)上就是各種各樣的代碼風(fēng)格。舉例來(lái)說(shuō):有些人恨不得把所有單一功能都一一獨(dú)立出來(lái)封裝成類,而有些人卻喜歡一個(gè)大類洋洋灑灑寫上上千行。大部分情況下我都是傾向于前者,但是就像我時(shí)常說(shuō)的那樣:It depends。不僅僅是軟件開發(fā),幾乎所有的事到最終都會(huì)歸結(jié)到一個(gè)統(tǒng)一的問題上:怎樣才是一個(gè)度?
一群理念相去甚遠(yuǎn)的人在一起工作是件異常痛苦的事:相當(dāng)一部分的時(shí)間會(huì)浪費(fèi)在解釋、爭(zhēng)論和排遣由此帶來(lái)的沮喪和憤怒上。古人語(yǔ):道不同,不相為謀。但到了真正的工作中卻不能如此隨性,缺乏足夠動(dòng)力的老人、能力出眾的技術(shù)骨干、干勁十足卻缺乏經(jīng)驗(yàn)的新人都需要互相體諒,學(xué)習(xí)和磨合。所以大部分的創(chuàng)業(yè)公司的技術(shù)團(tuán)隊(duì)因?yàn)槔砟钕嘟?#xff0c;往往效率會(huì)足夠高,而大公司內(nèi)的開發(fā)小組卻永遠(yuǎn)無(wú)法達(dá)到那樣的效率,更需要相應(yīng)的規(guī)范和程序框架。
得出上面這個(gè)結(jié)論的另一個(gè)理由是我對(duì)人的可塑造性是持悲觀態(tài)度的:多數(shù)人并沒有跳出自己思維局限性的意愿,動(dòng)力和能力。少數(shù)人在沒有任何外界壓力的情況下仍會(huì)不斷總結(jié)學(xué)習(xí)進(jìn)步(主動(dòng)學(xué)習(xí)型),而其余的人要么沒有任何意愿,關(guān)心的只是完成任務(wù)和拿到工資而已,要么想要進(jìn)步而不得法。而你的團(tuán)隊(duì)不可能全由主動(dòng)學(xué)習(xí)型的成員組成,這時(shí)候規(guī)范和程序框架的引入才能夠讓各種類型的人更好的合作。
2
合適的規(guī)范
大家都理解軟件開發(fā)需要合適的規(guī)范:代碼規(guī)范,程序規(guī)范,流程規(guī)范等等,以此來(lái)減少意外的出現(xiàn):最少驚訝原則。但在實(shí)際執(zhí)行中卻會(huì)碰到各種情況,其中最大的問題是:怎么鑒別哪些規(guī)范是需要強(qiáng)制執(zhí)行,哪些規(guī)范是推薦執(zhí)行。規(guī)范的強(qiáng)制執(zhí)行帶來(lái)的是代碼的可讀性提升和二義性減少,而壞處也是顯而易見的:對(duì)于大部分有想法的程序員而言這種規(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ī)范一般只有兩種分級(jí):推薦和不推薦。而我更推薦把代碼規(guī)范分成五個(gè)等級(jí):強(qiáng)制要求,強(qiáng)烈推薦(但不強(qiáng)制),良好,可接受和不可接受。以下僅舉部分例子加以說(shuō)明。
▌符合蘋果規(guī)范的命名方式
★類名開頭大寫,方法和變量名以駝峰法命名。強(qiáng)烈要求,這沒有什么好說(shuō)的,蘋果系統(tǒng)類庫(kù)和絕大多數(shù)的第三方開源庫(kù)都是如此。但在部分蘋果的sample中也看到過用m做前綴表示類成員變量的寫法,這些都是屬于遺產(chǎn)代碼的問題,仍舊是可接受范圍,但是自己代碼內(nèi)部使用類似匈牙利的命名法就是不可接受。
★類名使用至少三個(gè)字符做前綴,內(nèi)部方法使用兩個(gè)下劃線做前綴。強(qiáng)烈推薦。上面的做法可以最大程度避免和系統(tǒng)類庫(kù)發(fā)生重名的情況:因?yàn)樘O果宣稱保留所有兩位字符前綴的使用權(quán),同時(shí)其內(nèi)部方法命名以一個(gè)下劃線做前綴。
★無(wú)論使用K&R Style還是Allman Style都是可接受的范圍,但是強(qiáng)烈推薦在一個(gè)文件內(nèi)保持一種形式。
★在保證代碼可讀性的基礎(chǔ)上保持代碼的簡(jiǎn)短和統(tǒng)一性:小類,小方法,統(tǒng)一的函數(shù)返回。小類,小方法可以保證他人閱讀時(shí)更方便地關(guān)注類邏輯,而不是具體細(xì)節(jié),而統(tǒng)一的函數(shù)返回可以減少意外錯(cuò)誤和降低錯(cuò)誤排查的難度。而保證代碼的簡(jiǎn)短和不羅嗦也是很重要一點(diǎn),經(jīng)常會(huì)看到如下代碼: ?if (count > 1) { return YES; } { return NO; },
真心無(wú)法直視。
▌良好的代碼/工程結(jié)構(gòu)
★為整個(gè)工程創(chuàng)建worksapce。
★按照權(quán)責(zé)分門別類存放資源文件:每種類型的資源存放于獨(dú)立的目錄下:圖片,聲音,配置文件等等。而圖片又可以按照類型分別存放在不同的子目錄下:全局類型,背景圖,logo,登錄等等。
★合理的代碼結(jié)構(gòu)。推薦如下的工程目錄結(jié)構(gòu)。
Core:工程內(nèi)一些通用的機(jī)制實(shí)現(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:第三方庫(kù)。
3
合適的框架
一個(gè)合適的框架不是銀彈,在我看來(lái)框架要解決的問題從來(lái)不是:有了框架之后,工程就能無(wú)比正確地進(jìn)行下去。好的框架能夠做到的事僅僅只是:降低通用問題的復(fù)雜度和減少發(fā)生錯(cuò)誤的可能性。個(gè)人認(rèn)為一個(gè)良好iOS App框架應(yīng)該是有如下特點(diǎn):
▌定義清晰的層次結(jié)構(gòu)
★橫向上,各模塊互相獨(dú)立,僅通過有限的幾個(gè)接口進(jìn)行通訊。最理想的狀態(tài)是除核心模塊外,其他模塊都是可拔插。縱向上,各層次間依賴關(guān)系清晰,基本不出現(xiàn)逆向依賴的情況。
★橫向模塊一般依賴于業(yè)務(wù)需求,常被定義成各種Service或Manager。一種好的做法是有個(gè)統(tǒng)一的Service管理器負(fù)責(zé)相應(yīng)Serivce的加載,卸載,監(jiān)聽和分發(fā)App級(jí)別的通知給相應(yīng)Service,如前后臺(tái)切換,收到內(nèi)存警告等。這樣做一方面容易實(shí)現(xiàn)上面說(shuō)的模塊的可插拔化,另一方面也保證了公用特性處理的一致性。在這方面微信就做得不錯(cuò),基本所有的模塊都是從MMService繼承而來(lái),由MMServiceCenter進(jìn)行管理。當(dāng)然從dump出來(lái)的頭文件也可以發(fā)現(xiàn)一些管理上的紊亂,比如一些ViewController都是繼承自MMService。
★縱向的層次劃分基本各個(gè)App不會(huì)有太大區(qū)別,一般可以分為三個(gè)層次:
展現(xiàn)層(Presentation layer),負(fù)責(zé)管理UI和UIViewController。
邏輯層(Business/Service Layer),負(fù)責(zé)邏輯數(shù)據(jù)的定義和轉(zhuǎn)發(fā),起到承上啟下的作用。
數(shù)據(jù)訪問層(Data Access Layer),負(fù)責(zé)具體API構(gòu)造,網(wǎng)絡(luò)請(qǐng)求,數(shù)據(jù)持久化等。
各層根據(jù)業(yè)務(wù)邏輯的復(fù)雜性內(nèi)部又會(huì)使用單層或者多層結(jié)構(gòu)。以數(shù)據(jù)訪問層為例,一般又可以細(xì)分為網(wǎng)絡(luò)層,持久化層。而一般而言,展現(xiàn)層(UIView和UIViewController)都是直接使用邏輯層提供的Model進(jìn)行展現(xiàn),但是某些場(chǎng)景下往往需要不同的Model有相同的界面展示(如我們的App易信中,會(huì)話界面,收藏界面,問一問功能都需要進(jìn)行圖片的展現(xiàn),但這三個(gè)模塊下的Model定義并不一致),這就需要增加額外的ViewModel層用于粘合展現(xiàn)層和邏輯Model。
▌遵守SOLID原則和慎用各種設(shè)計(jì)模式
這是個(gè)老生常談的話題了,并不是iOS開發(fā)獨(dú)有,展開講可以講上幾天幾夜,不贅述。
▌定義自己的UI基類:UIView,UIViewController,UITableviewCell
這一點(diǎn)的好處不言而喻,所有的子View,Controller,Cell都能夠很方便的繼承基類的共有的行為,樣式。但也會(huì)引進(jìn)很大的管理風(fēng)險(xiǎn):組內(nèi)成員總會(huì)經(jīng)不起誘惑往基類塞各種并不普適的特性,引起基類權(quán)責(zé)的無(wú)限膨脹。大基類不僅增加組內(nèi)成員對(duì)代碼的理解難度,同時(shí)也增加出現(xiàn)問題時(shí)的排查難度。從這方面講,微信的UIViewController基類設(shè)計(jì)就極端失敗:MMUIViewController這個(gè)類光頭文件就有上百行。
▌提供方便好用的工具類
一些好用的工具類往往會(huì)成為框架重要的有機(jī)組成部分,方便快捷地解決局部問題,同時(shí)又不引入過多的復(fù)雜度。NSTimer的retain cycle是個(gè)很容易掉去的坑,那么提供一個(gè)基于Block或者weak delegate的NSTimer的封裝就是不錯(cuò)的選擇。使用KVO容易發(fā)生add和remove的不配對(duì)調(diào)用,那么就引入THObserversAndBinders或者FB的KVOContorller。某些核心模塊需要被多個(gè)模塊依賴時(shí),引入類似XMPP的GCDMulticastDelegate就能夠方便地進(jìn)行解耦。
▌好的范例
在前幾年使用C++的那段暗無(wú)天日的日子里,我常想的一個(gè)問題是:如何在API層面去限制和規(guī)避一些錯(cuò)誤。比如往線程池里面扔的task必須是堆上分配的對(duì)象,那么如何去強(qiáng)制傳入的指針指向的是堆地址而不是棧地址呢?這種傻問題大部分情況下是無(wú)解的,有時(shí)候有解卻是個(gè)異常別扭的解。而現(xiàn)在我更相信破窗理論所提供的可能性:做好示范,接下來(lái)的一切都會(huì)水到渠成。
更多項(xiàng)望烽的干貨,關(guān)注網(wǎng)易云信微信
網(wǎng)易云信?∣真正穩(wěn)定的IM云服務(wù)
ID:neteaseim 果斷關(guān)注,精彩不斷
點(diǎn)擊?閱讀原文
推薦閱讀:《OMG,隔壁老王竟然是個(gè)GEEK!》
總結(jié)
以上是生活随笔為你收集整理的项望烽:iOS App开发的那些事儿的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 我害怕接入IM云的开发者
- 下一篇: 为什么网易在2016年大举进军云计算?