一棚饵、整潔的代碼
- 整潔的代碼從不隱藏設(shè)計者的意圖,充滿了干凈利落的抽象和直截了當(dāng)?shù)目刂普Z句安拟。
- 讀寫的花費時間比例超過10:1。寫新代碼的時候宵喂,我們一直在閱讀舊代碼
二糠赦、命名
- 關(guān)鍵在于良好的描述技巧和共有的文化背景!
- 名副其實
- 避免誤導(dǎo)锅棕,不要使用非常相似的命名拙泽,不要使用小寫l和大寫O(容易和數(shù)字01搞混)
- 做有意義的區(qū)分(用數(shù)字區(qū)分通常沒有意義),例如裸燎,copy(source顾瞻,destination) > copy(a1, a2)。data德绿,info等等詞通常毫無意義
- 名詞要便于搜索荷荤,長名 > 短名
- 類名應(yīng)該是名詞短語退渗,方法名應(yīng)該是動詞短語
- 別抖機靈,一點也不幽默
- 每個概念對應(yīng)一個詞蕴纳,一以貫之会油,不要總變來變?nèi)ァetch, retrieve, get表達的都是一個含義
- 避免雙關(guān)
三古毛、函數(shù)
- 短蟹妗!更短欣恕体斩!函數(shù)的縮進層級應(yīng)該<=2
- 只做一件事,如果多余一件事颖低,就進行拆分
- 函數(shù)內(nèi)的語句要在同一個抽象層級上(自頂向下的coding絮吵,自頂向下的reading)
- 使用描述性的名稱,別害怕名字長
- 函數(shù)的參數(shù)要盡量少忱屑,0個最好蹬敲,1個也行,2個次之莺戒,3個及以上是災(zāi)難(不好記順序伴嗡,沒法測)。一定要盡可能的抽象出類
- 不要傳布爾參數(shù)从铲,一定可以拆出兩個函數(shù)來
- 可以把參數(shù)名放到函數(shù)名中來瘪校,比如assertEqual(expected, actual) -> assertExpectedEqualsActual(expected, actual)
- 區(qū)分開「指令型」和「詢問型」的函數(shù),不要一個函數(shù)兩種事情都做
- try-catch單獨封裝
四名段、注釋
- 「別給糟糕的代碼加注釋阱扬,重新寫吧」 —— Brian Kernighan and P.J. Plaugher
- 注釋的恰當(dāng)用法是彌補我們再用代碼表達意圖是遭遇的失敗
- 注釋存在的時間越久,就離其所描述的代碼越遠伸辟。原因在于程序員不能堅持維護注釋
- 好注釋包括:法律信息麻惶,提供信息,對意圖的解釋(不是實現(xiàn)信夫,是為什么這么實現(xiàn))窃蹋,對其他人的警示,todo(一定要寫好todo的功能静稻,以及由誰負(fù)責(zé)警没,何時完成),強調(diào)作用
- 壞注釋包括:喃喃自語振湾,多余的注釋惠奸,注釋掉的代碼(未來其他人不敢刪除),信息過多(沒人會看的)恰梢,署名(源代碼控制系統(tǒng)可以記錄作者)
五佛南、格式
- 垂直方向:緊密關(guān)聯(lián)的代碼應(yīng)該互相靠近(調(diào)用者應(yīng)該和被調(diào)用者相鄰,并且調(diào)用者在上嵌言,被調(diào)用者在下(符合人從上而下的閱讀習(xí)慣))嗅回,關(guān)系密切的概念也應(yīng)該互相靠近
六、對象和數(shù)據(jù)結(jié)構(gòu)
- 應(yīng)該盡量避免曝露數(shù)據(jù)細節(jié)摧茴,應(yīng)該以抽象的形態(tài)表述數(shù)據(jù)
- 過程式代碼(使用數(shù)據(jù)結(jié)構(gòu)的代碼)方便在不改動數(shù)據(jù)結(jié)構(gòu)的情況下增加函數(shù)绵载,面向?qū)ο蟮拇a方便在不改動現(xiàn)有函數(shù)的情況下增加新類
- 一切都是對象只是一個傳說
- 模塊不應(yīng)該了解它所操作的對象的內(nèi)部情形。類C的方法f只應(yīng)該調(diào)用(C的方法苛白,f創(chuàng)建的對象的方法娃豹,f的參數(shù)的方法,C的實體變量所持有的方法)购裙。一連串的調(diào)用應(yīng)該做切分懂版。
- 最精煉的數(shù)據(jù)結(jié)構(gòu),是一個只有公共變量躏率、沒有函數(shù)的類(Java)
七躯畴、錯誤處理
- 錯誤處理很重要,但如果它搞亂了代碼邏輯薇芝,就是錯誤的做法
- 拋出異常的時候蓬抄,應(yīng)該提供足夠的環(huán)境說明,以便判斷錯誤的來源夯到。應(yīng)該創(chuàng)建信息充分的錯誤信息嚷缭,和異常一起傳遞出去
- 定義異常類的時候,首要考慮它們應(yīng)該如何被捕獲
- 別返回null耍贾,應(yīng)該拋出異常阅爽,或者返回特例對象
- 盡可能避免傳遞null值
九、單元測試
- TDD三定律:
(1)在編寫不能通過的單元測試之前逼争,不可編寫生產(chǎn)代碼
(2)只可編寫剛好無法通過的單元測試优床,不能編譯也算是不通過
(3)只可編寫剛好通過當(dāng)前失敗測試的生產(chǎn)代碼 - 測試代碼和生產(chǎn)代碼一樣重要,應(yīng)該保持整潔
- 有了單元測試就不用再擔(dān)心對代碼的修改誓焦。是單元測試的代碼讓代碼可擴展胆敞、可維護、可復(fù)用
- 整潔的測試的要素:可讀性杂伟!可讀性的標(biāo)準(zhǔn):明確移层、簡潔、足夠的表達力
- 構(gòu)造-操作-檢驗:構(gòu)造測試數(shù)據(jù)赫粥,操作測試數(shù)據(jù)观话,檢查操作是否得到預(yù)期結(jié)果
- 每個測試函數(shù)只測試一個概念
- FIRST規(guī)則:fast(測試代碼運行速度應(yīng)該足夠快),independent(測試之間互相獨立)越平,repeatable(測試與測試環(huán)境無關(guān))频蛔,self-validating(測試輸出應(yīng)該是布爾值)灵迫,timely(先寫單元測試代碼,后寫生產(chǎn)代碼)
十晦溪、類
- 類中內(nèi)容的順序:變量瀑粥,函數(shù)。變量順序:公共靜態(tài)變量三圆,私有靜態(tài)變量狞换,私有實體變量。
- 類應(yīng)該短小舟肉,如果一個類無法精準(zhǔn)命名修噪,通常都意味著太長了。系統(tǒng)應(yīng)該由許多短小的類路媚,而不是少量巨大的類組成黄琼。
- 單一權(quán)責(zé)原則(SRP):類或者模塊應(yīng)該有且僅有一條加以修改的理由。
- 內(nèi)聚:類應(yīng)該只有少量實體變量磷籍,類中的每個方法都應(yīng)該操作一個或者多個這種變量适荣。
十一、系統(tǒng)
- 軟件系統(tǒng)應(yīng)將啟動過程和運行過程的邏輯分開院领。
- 分解main:將構(gòu)造與使用分開的方法之一弛矛,是將全部構(gòu)造過程搬遷到main中。
十三比然、并發(fā)
- 對象是過程的抽象丈氓,線程是調(diào)度的抽象
- 并發(fā)是一種解耦策略,它將what(目的)與when(時機)分解開
- 并發(fā)有時能夠改進性能强法,但是只在多個線程/處理器之間能分享大量等待時間的時候管用
- 并發(fā)算法的設(shè)計可能和單線程系統(tǒng)的設(shè)計極不相同
- 并發(fā)會在性能和編寫額外代碼上增加一些開銷
- 正確的并發(fā)是復(fù)雜的万俗,即便對于簡單的問題也是如此
- 并發(fā)缺陷并非總能復(fù)現(xiàn)
- 并發(fā)常常需要對設(shè)計策略進行根本性修改
- 數(shù)據(jù)封裝:嚴(yán)格限制對可能被共享的數(shù)據(jù)的訪問
- 生產(chǎn)者消費者模型、讀者作者模型饮怯、哲學(xué)家進餐模型
- 不要同時追蹤非線程缺陷和線程缺陷闰歪,確保代碼在線程之外可工作
- 在不同環(huán)境中,多線程代碼的行為可能不同蓖墅,盡量在所有可能部署的環(huán)境中測試库倘。
十四、其他
- 先寫可工作的臟代碼论矾,再在單元測試的輔助之下教翩,清理它
- clover工具可以檢查單元測試代碼的覆蓋率
- 應(yīng)該限制類、模塊中暴露的接口數(shù)量贪壳,類中的方法越少越好饱亿。
- 條件判斷中的條件應(yīng)加以封裝,用來清晰的表明該條件的內(nèi)容
- 用命名常量代替魔術(shù)數(shù)
- 時序耦合應(yīng)該暴露出來。如果語句a必須在語句b的后面執(zhí)行彪笼,那語句b的結(jié)果應(yīng)該作為語句a的輸入?yún)?shù)
- 封裝邊界條件钻注,應(yīng)該把所有涉及到邊界條件的代碼放到一起
- 避免傳遞瀏覽。每個模塊只應(yīng)該了解它的協(xié)作者杰扫,而非整個系統(tǒng)
- 測試邊界條件
- 錯誤傾向于扎堆出現(xiàn)队寇。如果某個函數(shù)出現(xiàn)錯誤,最好全面測試它