《程式設計守則》——簡單就是最好
- 懶人包
- 閱讀筆記
- 1 越簡單越好,但也不能太過簡單
- 2 bug 是會傳染的
- 3 取個好名字,本身就是最好的說明
- 4 先找出三個例子,才能改用通用的做法
- 5 最佳化的第一課——別去做最佳化
- 6 程式碼審查有三大好處
- 7 消除掉各種會出問題的狀況
- 8 沒在執行的程式碼,就是會出問題
- 9 寫出可以收合概念的程式碼
- 10 把複雜性局限在局部範圍內
- 11 有比之前好兩倍嗎?
- 12 大型團隊一定要有很強的約定慣例
- 13 揪出引發雪崩的那顆小石頭
- 14 程式碼有四種風格
- 15 拔草囉
- 16 要從結果往回推,別從程式碼往後推
- 17 有時大問題反而好解決
- 18 讓程式碼自己講故事
- 19 以平行方式進行改造
- 20 還是要用數學算一下
- 21 有時你就是得去做一些敲釘子的工作
- 結論:制定出你自己的規則
- 後記
懶人包
何謂好的程式碼?
- 一段程式碼用了最簡單的方式解決問題,它就是好的程式碼。「簡單」的意思是「它易於閱讀、易於理解」。要做到簡單,一段程式碼通常是簡短、符合團隊共識(格式與抽象層),以及擁有符合實際功能的註解。
- 不要太早開始搞通用模組,因為人沒辦法真正預測未來。
- 盡量殲滅程式碼中的 bug,避免後續寫好的程式碼需要依賴 bug 執行,那除蟲就會變成苦痛之路。導入 TDD 與程式碼審查制度有助於盡早排除 bug。
如果你需要更詳盡的守則說明,歡迎參考以下的閱讀筆記。
閱讀筆記
1 越簡單越好,但也不能太過簡單
任何問題的最佳解法,就是能滿足問題所有的要求,其中最簡單的那個做法。
本書對簡單的定義:
- 你花了多少時間寫這段程式碼?這段程式碼又有多長?都是越短越好
- 為了理解這段程式碼,讀者需要理解多少抽象概念?越少越好
- 解釋這段程式碼需要多久的時間?越短越好
- 程式碼本身好讀嗎?
你的問題已經夠簡單了嗎?還是你對問題做出額外的假設,讓你的程式碼不必要地變複雜?
🦊:「不要太過簡單」我會理解為「如果你已經明確知道有更好的演算法,那就不要偷懶,直接使用那個更好的演算法」。
程式碼最可怕的敵人是「複雜性(越來越難改動、越來越慢)」。而工程師能做的事情就是讓「複雜性荒謬到難以承受的那一天」越晚到來越好——所以在新增功能、修復問題時,都要盡可能避免添加複雜性,平時也要抽空消滅複雜性。
2 bug 是會傳染的
每個 bug 都會製造新的 bug,因為新的程式碼可能需要依賴這個 bug 才能正常運作。請盡早找出 bug 以避免它們繼續污染你的程式碼。
解決方式:
- 心懷 TDD 來開發,這樣你會寫出比較容易被測試(比較沒有狀態、比較「純」 aka 簡單)的程式碼
- 盡可能讓調用你寫的程式碼的人(可能是你同事、可能是未來的你)不會誤用你寫出來的程式碼,不要一廂情願地認為所有人都會正確呼叫你寫的程式碼,請檢查參數並拋錯
3 取個好名字,本身就是最好的說明
名稱本身就是一種「說明程式碼目的」的文件,請慎重地取名。工程師「讀」程式碼的時間遠多於「寫」,名稱要能讓人一看就知道這段程式碼的意圖。
- 不要過度簡化名稱
- 統一命名風格(駝峰、蛇形、動詞+名詞等等)——因為混用命名原則會造成認知負擔,你每一次看到一個新名稱,都要先消耗心智能量來判斷「它到底想做什麼」
- 讓名稱反應程式碼實際在做的事情(舉例:如果你不是在處理座標系統,那就避免使用 x/y 等名稱來命名變數)
- 讓所有人確實遵守命名規範
4 先找出三個例子,才能改用通用的做法
為什麼不要一開始就寫通用功能?因為你的預測很可能是錯的。手上只有一個案例時,根本就「不足以」預測出通用的解法。不要花太多時間去猜測你未來會遇到的需求,也不要花太多時間去寫你可能根本用不到的程式碼。
太早建立通用功能還有一個壞處——黏性太強:
- 一旦你建立了通用的作法,它就會變成一種樣板,而你在面對新進需求時,很可能就會設法擴張樣板,而不是重新進行評估。
- 一旦你建立了某種解決問題的抽象概念,你就很難再去考慮其他的替代方案了。
5 最佳化的第一課——別去做最佳化
在提升效率之前,先讓你的程式碼好懂、可靠。因為簡單的程式碼比較容易進行最佳化。
最佳化的 5 個步驟:
- 找出每條程式碼花費的時間
- 確認程式碼已經沒有任何 bug 了(效能問題不是因為 bug 而起的)
- 確實理解你要處理的資料樣態
- 確定你準備最佳化的目標真的會影響到效能
- 實際開始調整程式碼
想讓程式碼執行的更快,最重要的是少做一些事情,而不是用更快的速度去做同樣多的事情。
6 程式碼審查有三大好處
- 找出 bug
- 讓人更加理解程式碼(很遺憾,如果兩邊都是菜鳥工程師,那就不會有任何效果——沒有知識轉移、沒有足夠的背景知識找出 bug,甚至因為知識不足而做出有害的共識)
- 如果你知道有人會查看你的程式碼,每個人都會更努力寫出更好的程式碼(同儕壓力,但是是健康的形式)
- 會遵守格式和命名規則
- 比較不會偷懶、走捷徑
- 比較願意寫註解、把註解寫得更清楚
- 會刪掉用來測試的臨時程式碼
無論是在什麼情況下,程式審查都不應該去爭論專案的方向、團隊的約定慣例或理念。這些問題不該在只有兩個人的情況下被解決。
7 消除掉各種會出問題的狀況
永遠問自己:「我究竟讓這個功能或介面的使用者,有多麽難『用錯』它?」正確的答案是:「非常難。」
盡早檢查、盡早拋錯(強迫調用你寫的程式碼的人面對可能的錯誤情境)。
8 沒在執行的程式碼,就是會出問題
所以一旦確定程式碼不會被執行,就把它刪掉。
9 寫出可以收合概念的程式碼
不要挑戰人的短期記憶。
- 為變數和函式提供有意義的名稱
- 寫註解
- 合理分段程式碼
- 不要過度抽象化——做抽象化的目的永遠都是降低,而不是增加理解難度
- 配合團隊的常見抽象模式,不要老是發明新概念
10 把複雜性局限在局部範圍內
把複雜散落各處的缺點是會產生「二次複雜性(quadratic complexity)」的問題:每次添加新的條件,都要添加一段新的程式碼來檢查所有的條件。如果你無法避免增加複雜性,那至少把它們集中管理,讓未來的改動只會發生在一個地方。

假設你每次進行改動時,都要在系統各處東改西改,那就代表你的複雜性開始擴散了。
11 有比之前好兩倍嗎?
重構只是一種選項,而不是必然。「忽略」或「調整」也都是你可以執行的選項。
到底要不要重構?先問自己:重構後的程式碼有比重構之前好上兩倍嗎?沒有的話,還是漸進式地修改程式碼就好。
12 大型團隊一定要有很強的約定慣例
事情越複雜就越難成功,事情越簡單就越容易成功,簡單一定比較好。
程式碼書寫的風格不同,也會增加複雜性,所以請約定慣例。不同風格沒有好壞之分,壞的是混用風格。
如果團隊裡的所有人都使用相同的風格,大家就會寫出相同的程式碼,那使用彼此寫出來的程式碼也就不再是一件苦差事。
13 揪出引發雪崩的那顆小石頭
如何寫出比較容易除錯的程式碼:
- 讓程式碼中的「因」與「果」彼此接近
- 縮短「因果鏈」的長度
- 讓狀態越少越好,或是讓狀態能輕易地被重現
14 程式碼有四種風格
| 簡單的問題 | 困難的問題 | |
|---|---|---|
| 簡單的解法 | 可以預期 | 可以追求 |
| 複雜的解法 | 禁!止! | 可以接受 |
「你會不會用簡單的解法來解決簡單的問題?」這個問題正是區分普通工程師與優秀工程師的最佳標準。偉大的工程師在遇到看似困難的問題時,他們知道只要從正確的角度來思考,就有可能找出簡單的解法。
15 拔草囉
雜草指的是那些「與功能無關,很容易修正、但也容易被忽略的小瑕疵」,比如:
- 與實際功能並不相符的註解
- 不符合團隊風格規範的程式碼
在不影響功能的情況下,提升程式碼的可讀性和一致性。
如果放任雜草生長,那大家就會回去用最舒服的方式來寫程式碼,接著複雜性上升、除錯變難,最後專案變成一坨大便。定期除草會讓大家工作起來更輕鬆。
16 要從結果往回推,別從程式碼往後推
🦊:這章讀完的感想是⋯⋯不要永遠被手上既有的框架、函式限制解決問題的方式。在開始動手修改既有的程式碼來解決新問題前,先退一步看看「修改既有的程式碼」和「找一個新方法解決問題」哪一個做法比較好。類似 How to Build the Right Software (and Choose the Right Stack) 提出的概念。
17 有時大問題反而好解決
我們所有「通用解法就是更簡單的解法」這樣的例子,全都是「在視角上必須做出重大改變」的情況。通用解法往往代表一種完全不同的問題思考方式,而這種全新的視角,就促成了一個從根本上來看更簡單的解法。
18 讓程式碼自己講故事
只要寫出很容易閱讀的程式碼,就能讓其他事情進行得更順利,畢竟我們花在閱讀與除錯的時間,遠比最初花在寫程式的時間多得多。
- 確保變數、函式的名稱確實符合它們的功能
- 確保註解確實反應程式碼的意圖
- 每一段註解都要提供有額外幫助(程式碼本身無法傳遞)的資訊
19 以平行方式進行改造
🦊:簡單來說就是做標記加上雙版本,概念如下(舊模組稱為A,新模組稱為B):
- 在原本需要呼叫A的地方加上轉接器(adapter)
- 讓轉接器支援布林標記,以便之後可以從調用A改為調用B
- 透過切換轉接器的布林標記,漸進式地以B取代A,同時進行測試
- 全部改為使用B,並且過了一段時間確認一切安好後,移除轉接器,正式對接B
重點是:
- 在A換到B過程中如果遇到任何問題,要能很輕鬆地切回去
- 小改小動就不用這樣搞了,這種平行修改法通常是拿來對付大規模更新的情況
20 還是要用數學算一下
寫程式碼來執行自動化前,先實際算一下「寫程式碼要花的時間」跟「繼續手動作業要花的時間」,算完真的有差,再開始寫程式碼。
硬性限制可以簡化決策流程。
在真正寫出程式碼之前,先在數學計算上切換設計會容易很多。前算數學是為了確認設計是否無效。
可量化的限制與可衡量的解法,都是很好的線索——如果你同時看到這兩者,你就應該去進行數學計算,以協助你早點看出那種永遠行不通的解法。
以人工方式完成工作或許並不會真的那麼耗時,但如果它是一件持續要去做的麻煩事,而且自動化之後相對比較容易處理,那麼就算數學計算不那麼建議,它還是值得去做。
21 有時你就是得去做一些敲釘子的工作
不要偷懶。只看短期利益通常會讓你在事後後悔。
檔案太大確實會造成困擾,因為你沒有辦法單用瀏覽的方式尋找你需要的東西,你通常得透過文字搜索。
第一步是察覺自己會逃避哪些工作。第二步是評估你逃避的工作所帶來的長期利益。第三步是⋯⋯如果長遠來看確實是有益地工作,那就乖乖做吧。
結論:制定出你自己的規則
本書真正的價值:給你一些寫程式碼的建議,而你要跟自己的團隊討論你們應該建立哪些規則,然後大家要共同遵守規則,寫出所有人都看得開心、用得開心的程式碼。
後記
空洞騎士真好玩,九月開始坐牢就算了還坐出樂趣。


接下來想玩血源。