2015年5月27日晚19:45左右,我們開發(fā)小組開了一個分享會砌左,會上靖哥哥做主要分享人脖咐,我負責記錄大家討論的精華部分,然后整理成文汇歹;本文包含了原書中的主要思想屁擅,也包含了我們小組的實戰(zhàn)總結(jié)。
可讀性基本定理
代碼的寫法應當使別人理解它的時間最小化产弹。
這也是這本書的目標派歌,簡單說,好的代碼應當易于理解痰哨。
如何使代碼易于理解呢胶果?可以從四個方面來改進:
一. 表面層次上改進:命名,注釋和審美
要多問自己幾遍:“這個名字會被別人解讀成其他的含義嗎斤斧?”要仔細審>視這個名字早抠。
提到命名,看似簡單撬讽,實則不易蕊连。名字是給人讀的悬垃,不是給機器讀的,所以不是說只要編譯器編譯通過就算完事了甘苍,還要看名字本身是否有助于別人理解它背后的意義尝蠕。這里的名字包括,變量名载庭,類名趟佃,方法名或者函數(shù)名。
最佳的命名是這樣的:名字本身不能比它的含義大昧捷,也不能比它的含義小,要剛好包含它的含義罐寨,如果無法剛好包含靡挥,通常說明這個名字的意義太大,可能需要考慮拆分職責鸯绿。
取名字往往需要仔細斟酌跋破,要選擇當前語境下最合適的詞,比如:一個方法是取get瓶蝴,還是fetch毒返,還是download呢?有時可能會實在找不出一個感覺很合適的詞舷手,職責劃分也沒啥問題,該怎么辦呢?這時就需要和團隊內(nèi)的同事一起討論鞍陨,只要大家達成共識就行蒿囤,即便大家選定的詞仍無法準確表達背后的含義,以后團隊內(nèi)其它同事在閱讀這個代碼的也能迅速理解歉眷,畢竟大家曾經(jīng)達成過共識牺六,會留下印象。
程序代碼的名字都是英文汗捡,我們中國人很多往往對英文的意思的細微差別難以分辨淑际,但取好名字最重要的目的是讓團隊內(nèi)的人看到的時候,能迅速理解扇住,而不是給外國人去評估的春缕,所以當你在寫代碼過程中,遇到起名字的困難時艘蹋,請團隊來討論真的是個好方法淡溯,雖然團隊的理解在外國人看來也不一定準確,但能讓團隊成員能比較容易的讀懂你的代碼簿训。還記得可讀性基本定理嗎咱娶?當新人加入的時候米间,對于哪些看起來不那么準確的名字,可以鼓勵新人在熟悉的代碼的時候膘侮,說出自己的看法屈糊,新人也和大家一起達成共識,這也應該是融入團隊文化的一部分琼了。
注釋的目的是盡量幫助讀者了解得和作者一樣多逻锐。
不過,不要為了注釋而注釋雕薪,當你準備加注釋的時候昧诱,先問一個問題:
“我可以通過優(yōu)化此處的代碼,來讓讀者更明白這段代碼的意思嗎所袁?比>如使用更合適的變量或者函數(shù)名盏档,能做到嗎?”
當你寫代碼的時候燥爷,需要留意如下應該寫注釋的情況:
- 加入有意義的評論蜈亩,或者提示,讓讀者更清楚代碼的背景前翎,意圖稚配,成效等。比如:
// 出乎意料的是港华,對于這些數(shù)據(jù)用二叉樹比哈希表快40%
再比如:
//TODO(dustin):處理除JPEG以外的圖像格式
- 加入全局觀的注釋道川,或者總結(jié)性的注釋
思考如下場景:有新人剛剛加入你的團隊,她坐在你旁邊立宜,而你需要讓她熟悉代碼庫愤惰。在你帶領(lǐng)她瀏覽代碼庫的時候,你可能會指著某些文件或者某些類說這樣的話:
“這段代碼把我們的業(yè)務邏輯和數(shù)據(jù)庫黏在一起了赘理。任何應用層代碼都不該直接使用它宦言。”
“這個類看上去很復雜商模,但它實際上只是個巧妙的緩存奠旺。它對系統(tǒng)中的其它部分沒有任何依賴∈┝鳎”
這樣的一分鐘的隨意對話之后响疚,你的新團隊成員就知道的比她自己閱讀源代碼更多了。
而這正是應該寫入注釋中的信息瞪醋。
- 克服“作者心理阻滯”
很多程序員不喜歡寫注釋忿晕,因為覺得會花很多時間。其實當你在寫代碼的時候银受,遇復雜問題時践盼,把你的所思所想要精要的話寫出來鸦采,就可以了,這些話往往正是讀者在閱讀的時候所需要的咕幻。
例如:
//小心:這段代碼不會處理列表中的重復(因為這很難做到)
有時自己的所思所想有點混亂渔伯,嘗試用精要的注釋來整理你的思路是個好辦法。
有時寫出言簡意賅的注釋也很困難肄程,也要像重構(gòu)代碼一樣重視它們锣吼,重視它們就是重視你的同事。
順便提一下代碼美化相關(guān)的蓝厌,代碼美化也能輔助讀者快速理解代碼玄叠。有三條原則:
使用一致的布局,讓讀者很快就習慣這種風格拓提。
讓相似的代碼看上去相似
把相關(guān)的代碼行分組读恃,形成代碼塊。
二. 簡化循環(huán)和邏輯
把條件崎苗、循環(huán)以及其他對控制流的改變做得越“自然"越好,運用一種方式使讀者不用停下來重讀你的代碼舀寓。
有幾種方法可以讓代碼的控制流更易讀胆数。
在寫一個比較時
> while (bytes_expected > bytes_received)
把改變的變量寫在左邊并且把更穩(wěn)定的變量寫在右邊更好一些
> while (bytes_received < bytes_expected)
你也可以重排if/else
的語句中的語句塊。通常來講互墓,先處理正確的/簡單的/有趣的情況必尼。有時這些準則會沖突,但是當不沖突時篡撵,應當遵守這些準則判莉。
盡量避免嵌套的代碼塊。應該把它們改成更加線性的代碼來避免深嵌套育谬。
通常來講提早返回可以減少嵌套并讓代碼整潔券盅。
要把超長的表達式拆分成更加容易理解的小塊。
減少不必要的變量膛檀。
減少每個變量的作用域锰镀,越小越好。
如果有些變量的值不會發(fā)生變化咖刃,最好明確指出泳炉。比如,加上const
,final
類似的修飾嚎杨。
三. 重新組織你的代碼
- 抽取出那些與程序主要目的“不相關(guān)的子問題”花鹅,單獨成為一個函數(shù)。
- 使每個函數(shù)只做一件事枫浙,每個變量只關(guān)心一個唯一的意義刨肃。
- 先用自然語言描述代碼古拴,然后用這個描述來幫助你找到更整潔的解決方案。(通常你這時的描述之景,都可以作為注釋)
這三條看似簡單斤富,實則需要訓練,通常只要在寫代碼的過程中反復思考锻狗,回想這些建議满力,就會有意想不到的收獲。好的的程序員往往一步三回頭轻纪,也就是每寫一部分代碼的時候油额,他都會回頭看看曾經(jīng)的設計思路是否仍舊適合,是否需要調(diào)整刻帚,當下的代碼邏輯是否足夠清晰潦嘶,是否需要重新整理,這些問題看似多崇众,但當思考的多了掂僵,并以成為習慣,這些思考過程往往會縮短成直覺反應顷歌,直覺會告訴你該怎么做锰蓬,你就會發(fā)現(xiàn)自己異常高效,因為寫出的代碼相當優(yōu)美眯漩,大大節(jié)省后期維護時間芹扭。
少寫代碼,別費神實現(xiàn)你不需要的功能
通常我的經(jīng)驗是赦抖,不要做過早設計和實現(xiàn)舱卡,讓你的設計最小化,只要你確信現(xiàn)在的設計能夠完全勝任現(xiàn)在的需求队萤,而且能在不重做的情況下滿足未來新增需求轮锥,比如未來改動少量代碼和新增一些代碼,就可以了要尔,沒必要現(xiàn)在就為未來編碼交胚,因為未來太不確定,代碼上做太多準備盈电,可能會造成很大的浪費蝴簇。
盡量保持代碼的小巧,不要冗余代碼匆帚;
刪除沒用的代碼熬词,即便將來50%的可能性會再有用,也不要手軟。
熟悉你周邊的庫互拾,不要重新發(fā)明輪子
站在今天對未來的預估歪今,總是存在很大差距,可以先把這些暫時沒用的代碼放在另外的代碼倉庫里颜矿,需要用的時候再拿出來寄猩,不要讓它成為你閱讀代碼和維護代碼的障礙。