《程式設計守則》——簡單就是最好

懶人包

何謂好的程式碼?

  1. 一段程式碼用了最簡單的方式解決問題,它就是好的程式碼。「簡單」的意思是「它易於閱讀、易於理解」。要做到簡單,一段程式碼通常是簡短、符合團隊共識(格式與抽象層),以及擁有符合實際功能的註解。
  2. 不要太早開始搞通用模組,因為人沒辦法真正預測未來。
  3. 盡量殲滅程式碼中的 bug,避免後續寫好的程式碼需要依賴 bug 執行,那除蟲就會變成苦痛之路。導入 TDD 與程式碼審查制度有助於盡早排除 bug。

如果你需要更詳盡的守則說明,歡迎參考以下的閱讀筆記。

閱讀筆記

1 越簡單越好,但也不能太過簡單

任何問題的最佳解法,就是能滿足問題所有的要求,其中最簡單的那個做法

本書對簡單的定義:

  1. 你花了多少時間寫這段程式碼?這段程式碼又有多長?都是越短越好
  2. 為了理解這段程式碼,讀者需要理解多少抽象概念?越少越好
  3. 解釋這段程式碼需要多久的時間?越短越好
  4. 程式碼本身好讀嗎?

你的問題已經夠簡單了嗎?還是你對問題做出額外的假設,讓你的程式碼不必要地變複雜?

🦊:「不要太過簡單」我會理解為「如果你已經明確知道有更好的演算法,那就不要偷懶,直接使用那個更好的演算法」。

程式碼最可怕的敵人是「複雜性(越來越難改動、越來越慢)」。而工程師能做的事情就是讓「複雜性荒謬到難以承受的那一天」越晚到來越好——所以在新增功能、修復問題時,都要盡可能避免添加複雜性,平時也要抽空消滅複雜性

2 bug 是會傳染的

每個 bug 都會製造新的 bug,因為新的程式碼可能需要依賴這個 bug 才能正常運作。請盡早找出 bug 以避免它們繼續污染你的程式碼。

解決方式:

  1. 心懷 TDD 來開發,這樣你會寫出比較容易被測試(比較沒有狀態、比較「純」 aka 簡單)的程式碼
  2. 盡可能讓調用你寫的程式碼的人(可能是你同事、可能是未來的你)不會誤用你寫出來的程式碼,不要一廂情願地認為所有人都會正確呼叫你寫的程式碼,請檢查參數並拋錯

3 取個好名字,本身就是最好的說明

名稱本身就是一種「說明程式碼目的」的文件,請慎重地取名。工程師「讀」程式碼的時間遠多於「寫」,名稱要能讓人一看就知道這段程式碼的意圖。

  1. 不要過度簡化名稱
  2. 統一命名風格(駝峰、蛇形、動詞+名詞等等)——因為混用命名原則會造成認知負擔,你每一次看到一個新名稱,都要先消耗心智能量來判斷「它到底想做什麼」
  3. 讓名稱反應程式碼實際在做的事情(舉例:如果你不是在處理座標系統,那就避免使用 x/y 等名稱來命名變數)
  4. 讓所有人確實遵守命名規範

4 先找出三個例子,才能改用通用的做法

為什麼不要一開始就寫通用功能?因為你的預測很可能是錯的。手上只有一個案例時,根本就「不足以」預測出通用的解法。不要花太多時間去猜測你未來會遇到的需求,也不要花太多時間去寫你可能根本用不到的程式碼。

太早建立通用功能還有一個壞處——黏性太強

5 最佳化的第一課——別去做最佳化

在提升效率之前,先讓你的程式碼好懂、可靠。因為簡單的程式碼比較容易進行最佳化。

最佳化的 5 個步驟:

  1. 找出每條程式碼花費的時間
  2. 確認程式碼已經沒有任何 bug 了(效能問題不是因為 bug 而起的)
  3. 確實理解你要處理的資料樣態
  4. 確定你準備最佳化的目標真的會影響到效能
  5. 實際開始調整程式碼

想讓程式碼執行的更快,最重要的是少做一些事情,而不是用更快的速度去做同樣多的事情

6 程式碼審查有三大好處

  1. 找出 bug
  2. 讓人更加理解程式碼(很遺憾,如果兩邊都是菜鳥工程師,那就不會有任何效果——沒有知識轉移、沒有足夠的背景知識找出 bug,甚至因為知識不足而做出有害的共識)
  3. 如果你知道有人會查看你的程式碼,每個人都會更努力寫出更好的程式碼(同儕壓力,但是是健康的形式)
    1. 會遵守格式和命名規則
    2. 比較不會偷懶、走捷徑
    3. 比較願意寫註解、把註解寫得更清楚
    4. 會刪掉用來測試的臨時程式碼

無論是在什麼情況下,程式審查都不應該去爭論專案的方向、團隊的約定慣例或理念。這些問題不該在只有兩個人的情況下被解決。

7 消除掉各種會出問題的狀況

永遠問自己:「我究竟讓這個功能或介面的使用者,有多麽難『用錯』它?」正確的答案是:「非常難。」

盡早檢查、盡早拋錯(強迫調用你寫的程式碼的人面對可能的錯誤情境)。

8 沒在執行的程式碼,就是會出問題

所以一旦確定程式碼不會被執行,就把它刪掉。

9 寫出可以收合概念的程式碼

不要挑戰人的短期記憶。

  1. 為變數和函式提供有意義的名稱
  2. 寫註解
  3. 合理分段程式碼
  4. 不要過度抽象化——做抽象化的目的永遠都是降低,而不是增加理解難度
  5. 配合團隊的常見抽象模式,不要老是發明新概念

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):

  1. 在原本需要呼叫A的地方加上轉接器(adapter)
  2. 讓轉接器支援布林標記,以便之後可以從調用A改為調用B
  3. 透過切換轉接器的布林標記,漸進式地以B取代A,同時進行測試
  4. 全部改為使用B,並且過了一段時間確認一切安好後,移除轉接器,正式對接B

重點是:

  1. 在A換到B過程中如果遇到任何問題,要能很輕鬆地切回去
  2. 小改小動就不用這樣搞了,這種平行修改法通常是拿來對付大規模更新的情況

20 還是要用數學算一下

寫程式碼來執行自動化前,先實際算一下「寫程式碼要花的時間」跟「繼續手動作業要花的時間」,算完真的有差,再開始寫程式碼。

硬性限制可以簡化決策流程。

在真正寫出程式碼之前,先在數學計算上切換設計會容易很多。前算數學是為了確認設計是否無效。

可量化的限制與可衡量的解法,都是很好的線索——如果你同時看到這兩者,你就應該去進行數學計算,以協助你早點看出那種永遠行不通的解法。

以人工方式完成工作或許並不會真的那麼耗時,但如果它是一件持續要去做的麻煩事,而且自動化之後相對比較容易處理,那麼就算數學計算不那麼建議,它還是值得去做。

21 有時你就是得去做一些敲釘子的工作

不要偷懶。只看短期利益通常會讓你在事後後悔。

檔案太大確實會造成困擾,因為你沒有辦法單用瀏覽的方式尋找你需要的東西,你通常得透過文字搜索。

第一步是察覺自己會逃避哪些工作。第二步是評估你逃避的工作所帶來的長期利益。第三步是⋯⋯如果長遠來看確實是有益地工作,那就乖乖做吧。

結論:制定出你自己的規則

本書真正的價值:給你一些寫程式碼的建議,而你要跟自己的團隊討論你們應該建立哪些規則,然後大家要共同遵守規則,寫出所有人都看得開心、用得開心的程式碼

後記

空洞騎士真好玩,九月開始坐牢就算了還坐出樂趣。

除了當鐵匠也可以當模型師啊

白王你好白王再見

接下來想玩血源。