重溫《編寫可讀性代碼的藝術》,記下的部分摘錄和總結,以便日後回顧、反思
摘錄&總結
宗旨
- 可讀性基本定理總是優先于其他條例或原則
- 盡管減少代碼行數是一個好目标,但把了解代碼所需的時間最小化是一個更好的目标
- 寫出新的團隊成員能了解代碼(命名同樣适用)
命名
- 選擇專業的詞,避免空泛或意義模糊的名字
- 用具體的名字代替抽象的名字
- 給名字帶上附加資訊(如機關 MB、KB)
- 為作用域更大的命名取一個更長(更詳細)的名字
- 采用一緻的命名規範,有目的的使用大小寫和下劃線
- 對不同實體使用不同格式就像文法高亮一樣,能幫你更容易的閱讀代碼
- google c++命名規範中,常量的格式是
而不是kConstantName
,目的是與宏區分開來,類成員變量使用下劃線結尾,如CONSTANT_NAME
,與普通局部變量區分開來offset_
- 命名應該符合使用者的期望
-
、get
、length
等命名的方法,使用者期望調用它們是沒有什麼代價的(不會耗費性能)size
-
- 變量和方法定義選擇一個有意義的順序,始終一緻的使用它
注釋
- 好名字比好注釋更加重要
- 幫助讀者能夠 更容易 了解代碼的是好注釋
- 不要為那些從代碼本身就能 快速 推斷的事實寫注釋
- 如果有注釋能夠比沒有注釋了解起來 快很多,那麼注釋是有可以的
-
name = '*'.join(line.split('*')[:2]) # 丢棄第二個'*'後面的所有東西
-
- 加入“導演評論”
-
# 出乎意料的是,對于這些資料用二叉樹比用哈希表快40%
-
# 哈希運算得代價比左/右比較大得多
- 防止讀者為了無謂的優化而浪費時間
-
# 作為整體可能丢掉幾個詞,這沒有什麼問題。要100%解決太難了
- 解釋了自己的解決方法雖然有瑕疵,但并不影響正常使用,并表示自己未能找到完美的方案,不鼓勵他人在此作無謂的優化
-
- 意料之中的提問,大部分人會産生疑惑的地方(為什麼這麼做,為什麼直接用簡單的方法)應該寫上注釋
- 公布可能的陷阱
- 連接配接失敗一段時間後逾時異常
- 性能問題,運作時間達到 O(num*depth), 嵌套很深的輸入需要小心
- 全局觀注釋
- 總結性注釋
- 這種注釋也是對函數(或一段代碼)所做的事情的總結,在讀者深入了解細節之前就能得到該代碼的主旨
控制流
- 把條件、循環以及其他對控制流的改變做得越自然越好(往往自然語言表述出來就是自然的,嘗試先用自然語言描述邏輯)
- 邏輯處理順序,有時這些傾向性會沖突,那麼你就需要自己判斷哪一種情況應該優先處理了,很多情況下這都會有很明确的選擇
- 先處理掉簡單的情況(例如先處理特殊情況,提前傳回,減少分支數量)
- 先處理有趣的或者可疑的情況
- 先處理正邏輯
- 三目運算符應該不會對可讀性造成負面影響的情況下使用
- 使用解釋變量,用它來表示一個子表達式,提高可讀性
- 使用德摩根定理
-
not (a or b or c) == (not a) and (not b) and (not c)
-
not (a and b and c) == (not a) or (not b) or (not c)
-
- 嘗試從“反方向”解決問題
變量
- 消除中間變量(對可讀性沒有影響的變量)
- 縮小變量作用域
- 隻寫一次的變量更好
組織代碼
- 建立大量通用代碼,把一般代碼和項目專有代碼分開
- 積極地發現并抽取出不相關的子邏輯
- 看看某個代碼塊,問問自己:這段代碼的高層次目标是什麼?
- 對每一行代碼,問一下:它是直接為目标工作的嗎?這段代碼的高層次目标是什麼?
- 如果足夠的行數在解決不相關的子問題,抽取代碼到獨立的函數中
- 簡化已有接口
- 把一個方法中的所有操作保持在同一個抽象層次上
- 一次隻做一件事
- 列出代碼所做的所有“任務”
- 盡量把這件任務拆分到不同的函數中,或者至少是代碼中不同段落中
- 最好讀的代碼就是沒有代碼
- 讓你的代碼庫越小、越輕量級越好
- 建立越多越好的“工具”代碼來減少重複代碼
- 減少無用代碼或沒有用的功能
- 讓你的項目保持分開的子項目狀态
測試
- 使測試易于閱讀和維護
- 讓錯誤資訊具有可讀性
- python中的unittest子產品的assertEqual方法比assert的錯誤資訊更具體
總結
- 寫代碼時,應該時常問下自己:新的團隊成員能否了解自己的代碼
- 所謂的工程學就是關于把大問題拆分成小問題,再把這些問題的解決方案放回一起
- 為代碼增加一個函數存在一個小的(卻有形的)可讀性代價(你需要暫時跳到另一個函數中去,你回來之後可能會忘了些什麼)
- 一段代碼抽出成一個函數的準則是:這樣做是否提高了可讀性,如果目前并不關注于這段代碼的細節,那麼是應該抽成一個函數的
- 一次隻做一件事,先列出方法要做的任務,盡量保持一個方法中的操作在同一個抽象層次上
- 先用自然語言描述邏輯