0.something before talk
開啟正文之前,我們先來看一下兩個我們程序員熟知的概念:
軟件開發(fā)之瀑布模型
? 瀑布模型嚴(yán)格把軟件項目的開發(fā)分隔成各個開發(fā)階段:需求分析,要件定義,基本設(shè)計,詳細(xì)設(shè)計,編碼,單元測試,系統(tǒng)測試,壓力測試等。使用里程碑的方式,嚴(yán)格定義了各開發(fā)階段的輸入和輸出,是一種流水線式的整體流程,不可拆分。

軟件開發(fā)之敏捷模式
? 敏捷開發(fā)采用循序漸進(jìn)的方法進(jìn)行軟件開發(fā),把一個大項目分為多個相互聯(lián)系,但也可獨立運行的小項目,分別去完成,在此過程中軟件一直處于可使用狀態(tài)

? 那么從瀑布模型的嚴(yán)格確定產(chǎn)品需求規(guī)劃從一而終實現(xiàn)產(chǎn)品價值,到敏捷拆分產(chǎn)品需求更快發(fā)現(xiàn)設(shè)計弊端修正方向的模式的轉(zhuǎn)變說明了什么呢?說明了變化的變化。

? 魯迅先生曾說過:唯一不變的是變化本身?!竞冒?,其實不是魯迅說的,誰說的?我也不知道】對于軟件開發(fā)來說,變化也是來的讓人猝不及防。需求為什么不明確?需求又變了?所以具體需求到底是個什么鬼樣子?程序員疑問三連!例如就拿我們開發(fā)SDK來說,可能在剛開始開發(fā)時僅僅需要一個簡單功能,但是后期發(fā)現(xiàn)這個功能并不滿足實際需求或者這一個功能不夠,我們需要提供更多的功能支持,那么這個時候你的代碼是要被全部翻盤?還是只輕松修改就能適應(yīng)變化,成為了一個很重要的事情,因為這關(guān)系著你用不用加班到頭禿!你說重不重要?
?
? 那么面對這樣未知變化的情景,我們?nèi)绾伍_始著手碼代碼呢?軟件開發(fā)四原則:Reusability(可重用性), Maintainability(可維護(hù)性), Scalability(可擴展性), Testability(可測試性)前三個都在向我們宣示著讓你的代碼以不變應(yīng)萬變的基本游戲規(guī)則,那么我們在開始編碼時又應(yīng)該怎樣完美踐行這些原則呢?
1.Keeping your code clean
? 我們一定經(jīng)歷過接手別人的代碼后看著代碼撓頭,或者是看著自己n久之前寫的代碼一臉懵的情況,引發(fā)這些焦慮的原因除了不熟悉和記憶之外還有一個更可能的原因:代碼太亂了,根本無從下手。所以在保證好自己的代碼質(zhì)量的同時,保證代碼的干凈整齊也是協(xié)作開發(fā)或者為自己后期優(yōu)化鋪路,有效命名和適當(dāng)注釋提高代碼可讀性的很好的方法,由于各個端的代碼規(guī)范不盡一致而且大家肯定也聽的耳朵長繭,所以此處僅做提醒,不再贅述。
2.降低耦合
? 高內(nèi)聚低耦合是軟件設(shè)計的首要準(zhǔn)則。在著手開發(fā)一個產(chǎn)品的時候任何開發(fā)者都不可能預(yù)見到所有的細(xì)節(jié)設(shè)計,那么這個時候我們需要考慮的就是怎樣從已有需求中劃分模塊-抽象模型-下沉基礎(chǔ)-以組件插拔組裝構(gòu)建整個工程。
2.1適當(dāng)使用分類
2.1.1分類簡介
Category的主要作用是它可以在不改變原來類的基礎(chǔ)上,為類動態(tài)的添加方法。分類的使用應(yīng)該注意以下特點:
1.分類中只能增加方法,不能增加屬性
2.在分類方法中可以訪問原來類的.h文件中聲明的屬性和方法
3.分類可以重新實現(xiàn)原來類中的方法,但是會覆蓋掉原來方法,所以在開發(fā)中盡量避免同名方法覆蓋
4.方法調(diào)用的優(yōu)先級:分類>原來的類>父類,如包含多個分類,則調(diào)用優(yōu)先級與編譯順序有關(guān),最后參與編譯的分類優(yōu)先
分類的原理是:
1.category的方法沒有“完全替換掉”原來類已經(jīng)有的方法,也就是說如果category和原來類都有methodA,那么category附加完成之后,類的方法列表里會有兩個methodA
2.我們平常所說的category的方法會“覆蓋”掉原來類的同名方法,實際上由一可知:這是因為運行時在查找方法的時候是順著方法列表的順序查找的,它只要一找到對應(yīng)名字的方法即返回imp,也就實現(xiàn)了所謂的“方法覆蓋”。
2.1.2為什么要用分類?
? 一個類的不同功能模塊的實現(xiàn)拆分開放在不同的文件內(nèi),這樣可以使文件結(jié)構(gòu)清晰明了,并且避免多各功能接口混雜堆疊 在一個文件造成可用性和維護(hù)性降低的情況。
例如對于不同模塊的業(yè)務(wù)網(wǎng)絡(luò)請求封裝其實可以在網(wǎng)絡(luò)基礎(chǔ)類的基礎(chǔ)上使用分類處理實現(xiàn),這樣可以有效地隔離各個業(yè)務(wù),減少代碼冗雜,可以根據(jù)具體業(yè)務(wù)查詢具體分類,更加清晰易讀。
2.2依賴注入
2.2.1依賴注入簡介
? 如果在 Class A 中,有 Class B 的實例,則稱 Class A 對 Class B 有一個依賴。例如下個例子(因swift能夠更清晰的表述依賴關(guān)系,故使用swift語言展示):
class Person: NSObject {
var cat: Cat!
// ...
}
class Cat: NSObject {
weak var person: Person!
// ...
}
Person類和Cat類就有依賴關(guān)系:

? 一個人擁有一只貓,一只貓屬于一個人,這是一個簡單關(guān)系體現(xiàn),可是假如這個時候貓貓??需要變成狗狗??呢?可以預(yù)見的我們的Person類就需要作出相應(yīng)改變了,如果Person類和Cat類對于多方有很深的依賴的話,那么代碼改動也會變得巨大。這只是一個簡單的例子,尚且或出現(xiàn)如此的變動,更不要說對于不可預(yù)估的復(fù)雜業(yè)務(wù)場景了,有時候被依賴的任何一方變動,迎接我們的可能就是全部代碼的重頭再來。面對這樣的情況,我們就需要解除耦合,使用依賴注入代替強依賴。
? 依賴注入是種實現(xiàn)控制反轉(zhuǎn)用于解決依賴性設(shè)計模式,它提供一種機制,將需要依賴(低層模塊)對象的引用傳遞給被依賴(高層模塊)對象。這樣就可以解除兩個對象之間的強依賴,即使一個對象發(fā)生了變化,另一個對象也可以變更少量代碼甚至是不用變更代碼即可適應(yīng)。
2.2.2依賴注入的常用方法
? 針對于上述Person類和Cat類的例子,我們可以將抽象類型解析為其具體實例,創(chuàng)建一個單獨的層,通過Animal協(xié)議和PetOwner協(xié)議將Person類和Cat類間的強依賴剝離,而不是直接依賴。具體抽象結(jié)果如下所示:
protocol Animal {
// ...
}
protocol PetOwner {
// ...
}
class Person: PetOwner {
var animal: Animal!
// ...
}
class Cat: NSObject {
var petOwner: PetOwner!
// ...
}
1.構(gòu)造函數(shù)注入
依據(jù)上述分層,我們可以在構(gòu)造一個對象時實現(xiàn)注入:
let personA = Person(animal: Cat())
let personB = Person(animal: Dog())
2.屬性注入
我們也可以使用屬性進(jìn)行注入:
let personA = Person()
personA.animal = Cat()
let personB = Person()
personB.animal = Dog()
3.Java中的@Inject
public class Person {
...
@Inject Cat Cat;
...
public Person() {
}
}
? 通過在字段的聲明前添加 @Inject 注解進(jìn)行標(biāo)記,來實現(xiàn)依賴對象的自動注入。但是需要注意,實質(zhì)上,如果你只是寫了一個 @Inject 注解,F(xiàn)ather 并不會被自動注入。你還需要使用一個依賴注入框架,并進(jìn)行簡單的配置?,F(xiàn)在 Java 語言中較流行的依賴注入框架有 Google Guice、Spring 等,而在 Android 上比較流行的有 RoboGuice、Dagger 等。
2.3組件化
? 針對于復(fù)雜多變的場景,抽象分層使用組件化構(gòu)建整個項目架構(gòu)也是一種行之有效的方法。將公共基礎(chǔ)組件下沉,依靠平臺接口與上層具體業(yè)務(wù)模塊對接。代碼解耦抽象為組件是一方面,另一方面怎么把組件有序的管理起來運用于實際業(yè)務(wù)也是很大的一個問題,理想情況如下所示:

特別是站在我們基礎(chǔ)架構(gòu)-移動端的角度,我們不僅僅要規(guī)劃整理單獨的業(yè)務(wù)組件,也不僅僅是抽離出單獨的功能SDK,更重要的是怎樣規(guī)范化組件的配置聯(lián)動,否則抽象出來的多個組件之間互相依賴,牽一發(fā)而動全身,會給開發(fā)造成更大的困難。
幾個大廠的組件化之路大家可以參考下:
3.增強健壯性
? 在開發(fā)項目時我們需要考慮到代碼的健壯性,在大負(fù)載和頻繁操作時依舊保證順利運行,所以需要考慮代碼能否應(yīng)對極端情況。
3.1注意線程管理
? 在客戶端針對頻繁耗時操作,利用多處理器的優(yōu)勢提升響應(yīng)效率,以保證應(yīng)用程序的相應(yīng)性能,但是對于多線程編程時需要注意避免以下常見問題,合理使用線程管理進(jìn)行開發(fā):

多個數(shù)據(jù)訪問同一資源造成競爭,所以要針對必要數(shù)據(jù)進(jìn)行加鎖

加鎖情況下可能會造成死鎖,這時候要具體區(qū)分指定處理優(yōu)先級,避免死鎖

不要濫用線程,以免資源浪費
3.2負(fù)載均衡
負(fù)載均衡策略大多運用于后端服務(wù)支持,是采用分布式集群方案加強網(wǎng)絡(luò)數(shù)據(jù)處理能力、提高網(wǎng)絡(luò)的靈活性和可用性的技術(shù)方案,對于我們SDK來說可以借鑒這種思想。雖然我們客戶端并沒有多臺服務(wù)器支撐,但是我們有多個CPU。比如針對APP啟動時間過長的問題,我們沒有必要把大量啟動配置代碼堆疊在didFinishLaunching方法中,而應(yīng)該有條理性的區(qū)分各項配置具體需要啟動的時機,SDK也是如此,對于初始配置和啟動項應(yīng)有選擇性的合理安排時間,減少最初多事務(wù)壓力。
小結(jié):在面對未知變化時不要害怕編碼,而應(yīng)該梳理已有的需求,發(fā)揮腦洞想一想還有什么是可能后期需要的其他功能,然后按照Reusability, Maintainability,Scalability , Testability的原則去規(guī)劃代碼編程即可。另外對于越來越流行的敏捷開發(fā)來說,并不意味著快速開始編碼,而是需要關(guān)注像上述我們提出的注意點,敏捷開發(fā)實際非常重視“設(shè)計”,并且對開發(fā)人員的設(shè)計水平提出了極高的要求,既要“持續(xù)重構(gòu)”又不能“過度設(shè)計”,稍有不慎就會陷入反復(fù)推翻已有代碼的窘境,善于思考,磨刀不誤砍柴工。
參考: