代碼整潔之道

一個神奇的故事
一個程序員來到一個新的地方,這個地方的產(chǎn)品們?nèi)藛査?,你能做xxx嗎?程序員大喊:“當(dāng)然可以!!” 他才思泉涌,他披荊斬棘,很快他在幾天內(nèi)輕松完成了任務(wù)。一年之后,這個地方的產(chǎn)品們又找到了這位程序員,希望他把xxx再做一遍,結(jié)果得到的回答則是:“這也許需要1個月。”人們大驚問他為什么,“因為我們的系統(tǒng)太亂了,每改動一個地方,就要把全部內(nèi)容重新做一遍?!?/p>
為什么會發(fā)生這種事?因為一個團隊在初期或許有著絕妙的設(shè)計,但是不可免的在追求速度的時候會有一丟丟不夠優(yōu)雅的設(shè)計摻雜在里面,等到了將來再需要動這部分不優(yōu)雅的設(shè)計時,它已經(jīng)變成了一坨坨不優(yōu)雅的東西了。
這時如果嘗試加人會怎么樣呢?答案是開發(fā)速度將以指數(shù)級下降。因為培養(yǎng)新人的永遠不可能是老人,而是老代碼。真實的情況,就是某個新人被扔到一團火中,對著代碼大喊原來如此,那么這群新人就會變成汽油,這團火也會隨著項目越大燒的越旺。
因此,清理你的代碼!
理論上,你用多長時間寫代碼,你就應(yīng)該用多長時間去整理它,當(dāng)然這在現(xiàn)實生產(chǎn)中幾乎完全不可能,因此適當(dāng)?shù)拇a行為規(guī)范,就應(yīng)該變成寫代碼過程中不可繞過得一步。極端的說,如果你的代碼給我可以運行,但我無法簡單的理解它,那這段代碼就是一段失敗的代碼。反過來說,即便你的代碼給我時不能運行,但我可以很清楚的理解它是如何運行的,那這段代碼也是一段成功的代碼。
函數(shù)
一、短小
函數(shù)得第一要義是短小,第二要義也是短小,函數(shù)的作用就應(yīng)該是只用寥寥數(shù)語,把你引導(dǎo)至下一個函數(shù)里。
二、只做一件事
函數(shù)應(yīng)該做一件事;做好一件事;只做一件事
三、保持一個函數(shù)內(nèi)相同的抽象等級
這點也是保障前兩點的一個要訣,同時可以帶來一個額外的好處:面向?qū)ο蟆?/p>
四、盡量不要去用switch語句
switch語句非常特殊,它天生就是個大家伙,如下:
以上代碼有一些明顯的問題:
太長了,如果加?xùn)|西它還會更長。
明顯做了很多事。
違反了單一權(quán)責(zé)原則。
違反開閉原則。
簡單來說,解決起來只需要用到抽象工廠,如下:
這里其實用到了接口隔離原則,詳情可以閱讀《架構(gòu)整潔之道》。
五、使用描述性名稱
要真真切切知道你的方法在干什么,一般來說一個方法至少應(yīng)該是一個動作的描述。
六、注意函數(shù)參數(shù)
最理想是零參數(shù),其次是單一或二,如果大于等于三的話可能就要考慮一下了,是不是把這些參數(shù)作為一個數(shù)據(jù)結(jié)構(gòu)管理起來或許更好一些?
七、或許不要用bool作為參數(shù)
這只是一個軟規(guī)則,如果我們用bool變量作為參數(shù)了,那大概率我們就會用到這個變量來進行一個分支方法,那為什么我們不把這些分支分別做一個方法來使用呢。
八、嘗試使用try-catch來處理你的問題
畢竟try和catch已經(jīng)是天然的兩段代碼塊,比起if ?else地獄來說,把log寫在catch里要優(yōu)雅的多。

注釋
別給糟糕的代碼加注釋了——重新寫吧。
——Brian W.Kernighan & P.J.Plaugher
注釋本身并不是一個"純粹的好",更多時候它是一種"必要的惡",畢竟你的代碼越好,需要的注釋便越少,甚至根本不需要。
一、還是盡可能用程序來寫注釋
就像上邊說的一樣,在寫注釋之前,花幾秒想想是不是有更好的方法來拯救這團代碼。
二、好注釋
略。好的注釋自然賞心悅目,這部分暫時不用在這里討論。
三、不要喃喃自語
寫就寫清楚,不要把注釋變成一個謎團
四、不要多余的注釋
如果注釋過于詳細,還不如寫偽代碼。
五、不要留下注釋掉的代碼
相信我,其他人正常情況下是不敢刪除他們的。

格式
一、書寫上的格式
聰明的程序員會使用聰明的IDE,可能是自己的圈級不夠高,至少在我附近的人能把IDE用的6的真是少之又少,比如這里提到的智能替寫一些。
二、遵守一套團隊規(guī)則
人多就要有規(guī)矩。

對象與數(shù)據(jù)結(jié)構(gòu)
一、數(shù)據(jù)抽象
先看兩組代碼
二者最大的區(qū)別就是,上方直接操縱了代碼里的數(shù)據(jù)本體,而下邊則至少通過一次原子操作來做這些事情。我們不愿意暴露數(shù)據(jù)細節(jié),更愿意以抽象形態(tài)來表述數(shù)據(jù)。
二、得莫忒爾定律(最少知識原則)
本意為模塊不應(yīng)了解它所操作對象得內(nèi)部情形。及方法不應(yīng)該調(diào)用由任何函數(shù)返回的對象的方法。
三、使用數(shù)據(jù)傳送對象(DTO)
把數(shù)據(jù)放到類里進行傳輸。

類
一、單一權(quán)責(zé)原則
類或者模塊應(yīng)該有且只要一條加以修改得理由。這樣最終會造成一個結(jié)果,即一個類會被拆成非常小得部分,但是這才是一個好的系統(tǒng)應(yīng)該做到的,每一個小類封裝一個權(quán)責(zé),只有一個修改的原因,并與少數(shù)其他類一起協(xié)同達成期望的系統(tǒng)行為。
二、內(nèi)聚
一個類應(yīng)該只有少量得實體變量,類中得每個方法都應(yīng)該操作一個或者多個這種變量,如果一個類中的每個變量都被每個方法所使用,則該類具有最大得內(nèi)聚性。
系統(tǒng)
就像管理一個城市一樣,你一個Manager是沒辦法管理全部細節(jié)得,這就要求我們在整體系統(tǒng)之上,也做到一定的梳理,讓其變得非常整潔。
將構(gòu)造和使用分開
工廠模式
依賴注入(DI)
代碼是寫給人看的,不是寫給機器看的,只是順便計算機可以執(zhí)行而已。
——Harold Abelson