- Published on
Book - 易讀程式之美學-提升程式碼可讀性的簡單法則 (The Art of Readable Code)
昨天有分享了 高效程序員的 45 個習慣 (Practices of an Agile Developer:Working in the Real World) 這本書,今天來分享另外一本書
易讀程式之美學-提升程式碼可讀性的簡單法則 (The Art of Readable Code)
這本書,我覺得比 無瑕的程式碼 (Clean Code) 來的輕薄容易看,可以看成是一本前導書
文章內容,是在之前公司內,我舉辦的讀書會,我整理的一些內容,基本上都是我要特別點出來跟大家分享的重點。
第一章 程式碼應該易於理解
- 可讀性基本原則
- 應該將讀者理解所需的時間降到最短 -> 呈現「意圖」
- 1 個月後的自己有沒有辦法看的懂
- 短的程式碼一定是最好的嗎 ?
第一部份 表層改善
第二章 富含資訊的名稱
- 名稱可視為簡短的註解
- 命名好的話,還需要註解嗎 ?
- 非英語系國家
- domain 而來
01 選擇詞彙
- 根據上下文 fetch 可能會比 get 好
- 基本上 java 是不加 get 的
- size -> 什麼的 size ?
02 避免 tmp 與 result 通用名稱
- data / result
- tmp ? 什麼 tmp ?
- xxxtmp
- 有意義的使用 for 的 i
- 視情況而定
03 優先使用具體名稱而非抽象名稱
- server can start -> can listen on port
04 在名稱中加入額外資訊
- 把單位加到變數上
- file size -> size_mb
- delay -> delay second
- 加入其它重要屬性
- html_utf8
- plaintext_password
- 匈牙利命名 ?
- 類型加在最前面
05 名稱該有多長
- 剛剛好就好
- 讓 ide 協助你完成
- 縮寫不要縮的讓它媽媽都不認的
06 利用名稱格式加入更多意義
- 不同語言的規定不同
第三章 不被誤解的名稱
- 英文的 right ?
- 英文的單子很多不同的時候有正/反的意思
- think aloud 放聲思考法
- 是在進行某種認知任務時,該人士會公開地表達出他們正在想什麼,以便其他人可以聽到他們的思考過程
- filter => 無法判斷是 選取 select 還是 排除 exclude
邊界的極值 min, max
- 每個人對於 limit 的定義不同,包不包含邊界值
封閉區間 first, last
- 起始點 ~ 包含終點
半開放區間 begin, end
- 起始點 ~ 不包含終點
bool 名稱
- is, has, can, should
符合使用者的預期
- get
- 以 c# 的 prop get 為例
- 是否應該在裡面存取 db
- size
- 以 c# 的 count 為例
- api 的熟悉
評估多個可用名稱
- 先選出名稱再來討論
第四章 美學
- 排版,固定的模式
- 類似的程式碼有相似外觀
- 程式碼變成段落
調整斷行讓程式更加一致與簡潔
- 類似的程式碼,排版應該要類似
用方法消除混亂
- 測試重構
- 消除重複
- 呈現意圖
適當使用列對齊
- 個人不建議
選擇有意義的順序並堅守到底
- 對應 html input
- 重要性
- 字母
上下 (前面) 要一致就好
將宣告組織成區塊
- interface 同樣功能的 method 放在同一個區塊
- 可以看到一些 code smell
- 拆分
- 可以看到一些 code smell
區分程式碼「段落」
- 區分不同的段落
- 寫文章一樣的感覺
- 先寫註解在寫程式
個人風格與一致性
一致的風格比正確的風格更為重要
第五章 認識註解
- 註解的目的,是協助使用者了解作者的思想
- 重點在於記錄 why
不該註解的部份
- 一看就知道的事情就不用註解
- 不要為了註解而註解
- 不要註解不好的名稱 - 直接修正名稱
- 好程式 > 壞程式 + 好註解
記錄自己的想法
- 記錄 why
- 註解程式碼 bug
- todo 的意義
- 常數的註解
- 視情況而定要不要加
- 永遠固定的值,基本上不用
- 視情況而定要不要加
為讀者設想
- 想像程式碼在外人眼中的樣子
- 預期可能出現的問題
- 可能是反模式,為什麼不修改可以表達 ?
- 註明可能出現的陷阱
- 與其說是陷阱,不如說是限制 - 例如寄信附檔不可超過多大
- 全局註解
- 向團隊的新成員,介紹程式的來龍去脈 - 我覺得是文件,而不是註解
- 摘要註解
- 跟前面說的很類似,先註解再寫程式
避免寫作抗拒
- 步驟
- 寫下當時心中的想法
- 讀出註解,看看是否需要修正
- 改善
第六章 讓註解精確與簡潔
避免模稜兩可的代名詞
- 它是誰 ?
使用具代表性的輸入 / 輸出範列
- 註解加上範列
- 測試 ?
函數參數名稱的註解
- ide 有提供的功能
- c# 的具名參數
使用訊息密集的詞彙
- 大家都知道的 ?
- 工程師 - 知識的詛咒
- domain 通用語言
- 工程師通用語言 - design pattern
第二部份 簡化迴圈與邏輯
- 第一個部份在表層,重點在於「表現意圖」(可讀性)
第七章 提高控制流程可讀性
01 條件式中的條件順序
- if 的右邊大多都是固定的值
- 尤達表示法 ?
- 有人習慣會把 null 寫在左邊
02 if/else 區塊順序
- 先正向再反向
- 把程式碼拆出括號外
03 ?: 三元運算式
- 視情況使用
- 最多不要超過兩層的三元運算式
04 避免 do/while 迴圈
- do/while 因為不好閱讀,應該要改成 while
- 個人覺得可以不用就不用,避免無窮迴圈
05 儘早由函數中返回
- early return
- 衛語句 (guard clause)
- 防禦性程式設計 (defensive programming)
06 惡名昭彰的 goto
- 可以用,但不要用
07 減少巢狀結構
- 就拆掉括號
- early return 是最基本的方式
- return 變 continue 也是一招
- 使用 linq
08 能否理解執行流程
- 不要用 exception 控制流程
第八章 分解巨大表示式
01 解釋性變數
- 使用「變數」達到比原本更有意義
- 雖然會造成 temp variable
02 摘要變數
- 跟解釋有點像
- 是不是會違反 feature envy ?
03 利用笛摩根定律
- 利用 ide 的提示
- 之前提過的正向表示
04 誤用捷徑邏輯
- 簡短不一定是好的
- 可以拆開 if 內的判斷式
- us falsely value
06 分解巨大的敘述
- jQuery 常用的重構手法
- 消除重複
07 另一個有創意的簡化手法
- 跟上一個有點像,重點是怎麼找到重複
第九章 變數與可讀性
01 消除變數
- temporary variable
- 中間結果 variable 有時還是需要的
- 可以利用程式碼的特性 yield return
02 縮限變數的範圍
- 全域變數
- js 就比較麻煩,新版本多加了宣告的方式 let , const
- python 也是
- 可以是區域就設定成區域
- 神奇 field
- 離使用的地方愈近愈好
- 副作業比較小
03 偏好單次寫入的變數
- const
- readonly static
第三部份 重新組織程式碼
- 第二部份是針對某個區域,第三部份是針對大範圍
第十章 抽離不相關子問題
- 程式主流程的目的為何
- 是不是有解決主要目的不相關的子問題
- 將子問題抽成獨立的 method/ function
01 說明範例
- 子問題
- 可以提供單一完整功能,不在乎其它人怎麼使用它
02 純工具程式碼
- 希望語言本身可以提供的函數
- static helper ~
03 其它通用程式碼
- 非 02 的工具程式碼 ?
04 建立大量通用程式碼
- 拉出去變成 lib/ package
05 專案專屬功能
- 是不是跟 domain 無關的 helper ?
06 簡化既有介面
- 永遠不需要屈就於不夠理想的介面
- 在原本的 method 上面多包一層
- 比較方便使用
- ToJoinString()
07 依需求重塑介面
- glue 膠合程式碼
- 程式碼與程式本身邏輯無關 -> 05 的意思
08 過猶不及
- method 拆分過小
- 等有人用的時候再拆就好
第十一章 一次一項工作
- 程式碼重組
- 函數應該只作一件事
- SRP
- 這裡主要是針對函數,並沒有拆 class
01 工作可以很小
- 原本
- 投票轉數字 + 更新
- 之後
- 投票轉數字
- 更新
02 從物件抽取數值
- || js 的特性
- TDD 也是在簡化操作
結語
- 列出執行的工作
- 工作可以抽離為函數 / 類別
- 真正困難 - 列出所有函數執行的小工作
第十二章 將想法轉化為程式碼
- 怎麼好的跟別人解釋
01 清楚描述邏輯
- 先口語說邏輯 -> 有點類似之前說的寫註解
- 不看程式碼說要做的事情
02 認識函數庫能提供的協助
- 重點在於對程式本身提供的 api / sdk 要熟悉
- 之前有說過的 join string 的例子
03 應用在較大的問題
- 如果原本已經有程式碼
- 如何重構
- 如果是新功能
- 如何規劃設計
04 結語
第十三章 撰寫較少的程式碼
01 不開發那些功能 - 不會需要
- 80 / 20 法則
- 那些是真正核心的功能
02 詢問與分解需求
- 了解功能背後的 why
- 重點在於解決問題,而不是功能
03 維持程式碼小而美
- 重用程式碼
- 移除沒有使用的程式碼
- 拆專案 ?
04 熟悉使用的函式庫
- 跟前一章的「02 認識函數庫能提供的協助」一樣意思
05 範例
- 重點在於善用工具
- 役物而不役於物
第四部份 精選主題
第十四章 測試與可讀性
01 讓測試易讀與維護
- 測試程式,也是程式,也是需要重構和維護
03 讓測試更易讀
- 隱藏不重要的細節,突顯重要的細節
- 「第十二章 將想法轉化為程式碼」
- 讓測試程式跟說話一樣
- input / output 一行有點跨張了點
04 讓錯誤訊息易讀
- 測試應該可以反應錯誤的情境
- self valid
05 選擇良好的測試輸入資料
- 優先使用簡單,明確但可以達到測試效果的輸入值
- 永遠都有測試不完的輸入值
- 應該要以情境來挑選
- 最後才是處理例外情況
- QA
- Boundary Value
- decision table
06 測試函數的命名
- 以情境來命名
- 適度加上 summary
07 那些測試有何問題 ?
- 回過頭來看 02 的測試範例
08 測試友善的開發
- 會想怎麼寫比較好測試
- 先寫測試在寫程式
09 過度應用本原則
- 不是為了測試過度改程式碼
- 測試含蓋率的意義
- 測試影響了產品開發
- 重點是功能完成,不是測試完成
10 結語
- 讓修改和加入新的測試變的更加容易
圖片來源:網路。若分享內容有侵害您的圖片版權,請來信告知,我們會及時加上版權信息,若是您反對使用,本著對版權人尊重的原則,會儘速移除相關內容。