代碼整潔之道

Any fool can write code that a computer can understand. Good programmers write code that humans can understand.


代碼整潔之道


普通的工程師堆砌代碼,優秀的工程師優雅代碼,卓越的工程師簡化代碼。如何寫出優雅整潔易懂的代碼是一門學問,也是軟件工程實踐裡重要的一環。前段時間通讀了三本經典書籍《代碼整潔之道 》、《編寫可讀代碼的藝術》、《重構:改善既有代碼的設計》,本文將重點從註釋、命名、方法、異常、單元測試等方面總結了一些代碼整潔最佳實踐,大部分是筆者總結於以上三本書中的精華,也有部分是筆者工程實踐的總結。篇幅有限,本文將總結性給出一些實踐建議,後續會有系列文章配合實踐代碼展開來講述。

註釋

  • 在文件/類級別使用全局註釋來解釋所有部分如何工作
  • 註釋應該聲明代碼的高層次意圖,而非明顯的細節
  • 公共api需要添加註釋,其它代碼謹慎使用註釋
  • 在註釋中用精心挑選的輸入輸出例子進行說明
  • 註釋一定要描述離它最近的代碼
  • 註釋一定要與代碼對應
  • 一定要給常量加註釋
  • 如果可能請儘量使用英文註釋
  • 團隊統一定義標記TODO 待處理的問題FIXME 已知有問題的代碼HACK 不得不採用的粗糙的解決方案
  • 典型的爛註釋不恰當的信息廢棄的註釋冗餘註釋糟糕的註釋註釋掉的代碼
  • 唯一真正好的註釋是你想辦法不去寫的註釋不要有循規式註釋,比如setter/getter註釋不要添加日誌式註釋,比如修改時間等信息(git可以做的事情)註釋一定是表達代碼之外的東西,代碼可以包含的內容,註釋中一定不要出現如果有必要註釋,請註釋意圖(why),而不要去註釋實現(how),大家都會看代碼適當添加警示註釋
  • 不要給不好的名字加註釋,一個好的名字比好的註釋更重要
  • 不要“柺杖註釋”,好代碼 > 壞代碼 + 好註釋
  • 不要註釋中增加html標籤,徒增閱讀難度
  • 不要在代碼中加入代碼的著作信息,git可以乾的事情不要交給代碼

命名

  • 儘可能使用標準命名方法,比如設計模式,通用學術名詞等
  • 命名要找更有表現力的詞使用更專業的詞,比如不用get而使用fetch或者download避免空泛的名字,像tmp使用具體的名字來細緻的描述事物給變量名帶上重要的細節,比如加上單位ms等為作用域大的名字採用更長的名字,作用域小的使用短名字變量類型為布爾值表達加上is,has,can,should這樣的詞會更明確
  • 變量名稱長短應該與其作用域對應
  • 別害怕長名稱,長而具有描述性的名稱比短而令人費解的名稱好
  • 函數名稱應該說明副作用,名稱應該表達函數,變量或類的一切信息,請不要掩蓋副作用,比如CreateAndReturnXXX

方法

  • 函數不應該有100行那麼長,20行封頂最好if else while等控制語句其中代碼塊應該只有一行,也就是一個函數調用語句函數的鎖進層次不應該多於兩層一個函數只做一件事,一個函數不應該能抽象出另外一個函數
  • 某個公共函數調用的私有函數緊隨其後
  • 最理想的參數是零參數,最長不要超過三個入參,儘量不要輸出參數如果函數傳入三個及以上參數最好將其抽象為類標識參數十分醜陋,向函數傳入布爾值用於區分不同業務的做法很醜陋,應該拆分為多個函數別傳入null值
  • 別返回null值,拋出異常或者返回特殊對象,儘量避免NPE

異常與錯誤

  • 抽離try catch包含的代碼塊,其中代碼塊抽象為一個函數
  • 拋出的每個異常,都應當提供足夠的環境說明,已便判斷錯誤的來源與處所
  • 不要將系統錯誤歸咎於偶然事件

併發

  • 分離併發相關代碼與其它代碼
  • 嚴格限制對可能被共享的數據的訪問
  • 避免使用一個共享對象的多個同步方法
  • 保持同步區域微小,儘可能少設計臨界區

單元測試

  • 使用最簡單的並且能夠完整運用代碼的測試輸入
  • 給測試函數取一個完整性的描述性名字,比如 Test _
  • 測試代碼與生產代碼一樣重要
  • 保證測試代碼整潔,一旦其整潔性被破壞,其價值會很快流失,沒有人願意維護雜亂的代碼,何況是測試代碼
  • 每個測試一個斷言,單個測試中斷言數量應該最小化也就是一個斷言
  • FIRST原則快速 Fast獨立 Independent 測試應該相互獨立可重複 Repeatable 測試應當在任何環境中重複通過自足驗證 Self-Validating 測試應該有布爾值輸出及時Timely最好的方式是TDD
  • 不要執著於追求太高的測試覆蓋率,事實上測試代碼前面90%通常比後面10%花的時間少
  • 不要怕單元測試的方法名字太長或者繁瑣,測試函數的名稱就像註釋

代碼結構

  • 代碼行長度控制在100-120個字符
  • 可能用大多數為200行,最長500行的單個文件構造出色的系統
  • 關係密切的代碼應該相互靠近變量聲明應該靠近其使用位置若某個函數調用了另外一個,應該把他們放在一起,而且調用者應該放在被調用者上面自上向下展示函數調用依賴順序
  • 應該把解釋條件意圖的函數抽離出來,儘可能將條件表達為肯定形式
  • 不要繼承常量,比如接口中定義常量,不要使用繼承欺騙編程語言的作用範圍規則
  • 模塊不應瞭解它所操作對象的內部情況
  • DTO(Data Transfer Objects)是一個只有公共變量沒有函數的類
  • 對象暴露行為,隱藏數據
  • 不要使用“尤達表示法” 如 if(null == obj),現代編譯器對if(obj = null)這樣的代碼會給出警告
  • 一般情況使用if else,簡單語句使用三目運算符
  • 通常來講提早返回可以減少嵌套並讓代碼整潔

設計

  • 類應該足夠短小類應該滿足單一權責原則(SRP),類和模塊只有一個修改理由類應該只有少量的實體變量類應該遵循依賴倒置原則 DIP(Dependency Inversion Principle),類應該依賴於抽象而不是依賴於具體細節類中的方法越少越好,函數知道的變量越少越好,類擁有的實體變量越少越好
  • 通過減少變量的數量和讓他們儘量“輕量級”來讓代碼更有可讀性減少變量縮小變量的作用域只寫一次的變量更好,如常量
  • 最好讀的代碼就是沒有代碼從項目中消除不必要的功能,不要過度設計從新考慮需求,解決版本最簡單的問題,只要能完成工作就行經常性地通讀標準庫的整個API,保持對他們的熟悉程度
  • 簡單設計運行所有測試不可重複表達了程序員的意圖儘可能減少類和方法的數量以上規則按重要程度排列
  • 無論是設計系統或者單獨模塊,別忘了使用大概可工作的最簡單方案
  • 整潔的代碼只提供一種而非多種做一件事的途徑,他只有儘量少的依賴。明確定義並提供儘量少的API
  • 減少重複代碼,提高表達力,提早構建,簡單抽象

小結

作為代碼整潔之道系列的第一篇,本文從註釋、命名、方法,單元測試,併發等視角簡單給出了一些最佳實踐,後續會從各個方面展開來介紹更多的實踐實例,讓我們一起左手代碼,右手詩。


分享到:


相關文章: