為什麼程式碼品質重要#
高品質程式碼能產出可靠、易維護且少 Bug 的軟體;低品質程式碼則會導致系統脆弱、難以修改、充斥問題。每位工程師在撰寫程式碼時做出的小決策,累積起來就決定了軟體的好壞。
| 面對的情境 | 高品質程式碼 | 低品質程式碼 |
|---|---|---|
| 既有需求 | 完全符合 | 不完全符合,存在未處理的邊界情況 |
| 需求變更 | 少量額外工作即可適應 | 需大幅重做和重構 |
| 發生錯誤 | 系統能正常還原或優雅降級 | 進入未定義狀態,資料可能受損 |
| 未預期的使用場景 | 系統仍可控 | 系統進入未定義狀態,資料可能受損 |
| 遭受攻擊 | 維持安全狀態,不受損害 | 進入未定義狀態,可能被入侵 |
| 最終軟體樣貌 | 可信賴、易維護、Bug 少 | 不可信賴、難以維護、Bug 眾多 |

Figure 1.1: High-quality code maximizes the chance that the software will be reliable, maintainable, and meet its requirements. Low-quality code tends to do the opposite.
程式碼如何變成軟體#
程式碼不會在工程師寫完的瞬間就變成正式運行的軟體,通常需要經過多道流程與檢查。以下是幾個關鍵術語:
| 術語 | 說明 |
|---|---|
| 程式碼庫(Codebase) | 由版本控制系統(如 Git)管理的程式碼倉庫 |
| 提交程式碼(Submitting code) | 將本地修改合併到主程式碼庫,也稱為 commit 或 merge pull request |
| 程式碼審查(Code review) | 由其他工程師審查變更,如同「校對」般幫助發現作者遺漏的問題 |
| 預提交檢查(Pre-submit checks) | 在提交前自動執行測試和編譯檢查,若失敗則阻擋提交 |
| 發布(Release) | 從程式碼庫的快照建構軟體,通過品質保證檢查後釋出 |
| 生產環境(Production) | 軟體被部署到伺服器或系統上正式運行的狀態 |
典型的軟體開發與部署流程如下:
- 工程師在本地副本進行修改
- 提交程式碼審查
- 審查者檢視並可能要求修改
- 雙方同意後,程式碼提交到主程式碼庫
- 定期從程式碼庫產出發布版本
- 測試失敗或編譯錯誤會阻擋提交或阻擋發布
flowchart TD
A[工程師在本地修改] --> B[提交程式碼審查]
B --> C{審查者檢視}
C -->|要求修改| A
C -->|通過| D[合併到主程式碼庫]
D --> E[產出發布版本]
E --> F{品質檢查}
F -->|失敗| E
F -->|通過| G[部署到生產環境]

Figure 1.2: A simplified diagram of a typical software development and deployment process.
高品質程式碼的四個目標#
能運作#
程式碼的首要目的是解決問題。「能運作」意味著程式碼應正確完成其預期功能且無 Bug。這也包含效能、安全性、隱私等非功能性需求。
能持續運作#
程式碼今天能運作,不代表明天也能。程式碼不是孤立存在的:
- 它依賴的其他程式碼會被修改和更新
- 新功能需求可能需要修改現有程式碼
- 問題本身會隨時間演變(消費者偏好、業務需求、技術條件都會改變)
重點: 確保程式碼持續運作是工程師面臨的最大挑戰之一,不應被視為事後補救的工作。
能適應變化的需求#
軟體開發往往持續數月乃至數十年,需求必然會改變。作者提出兩個極端情境的對比:
- 過度預測(Scenario A):試圖預測所有未來可能的需求變化並提前設計,導致開發速度極慢,而且預測通常是錯的
- 完全忽略(Scenario B):完全不考慮適應性,需求一變就得砍掉重練
技巧: 正確做法是介於兩者之間——採用通用的技術手段確保程式碼具有適應性,而不必精確預測未來會如何變化。
不重新發明輪子#
解決問題時,我們通常會將大問題拆解為多個子問題。許多子問題早已有人解決過,使用現有方案有四大好處:
| 好處 | 說明 |
|---|---|
| 節省時間與心力 | 不需從頭實作底層功能 |
| 降低 Bug 機率 | 已被廣泛測試和使用的程式碼更可靠 |
| 借助既有專業知識 | 維護者是該領域的專家,會持續更新 |
| 提高可理解性 | 使用標準方式做事,其他工程師一看就懂 |
補充: 這個原則是雙向的——如果我們寫了解決某子問題的程式碼,也應該把它結構化,讓其他工程師能輕鬆重用。
程式碼品質的六大支柱#
讓程式碼可讀#
如同一份糟糕的食譜——沒有標題、步驟混在一起、用 A/B/C 代稱器具、關鍵資訊擺錯位置——難以閱讀的程式碼會讓工程師花大量時間解讀,更可能在 code review 中遺漏 Bug,或在修改時引入新的錯誤。
避免意外#
想像你打電話訂披薩,但手機 app 的「貼心功能」在忙線時自動轉撥到另一間餐廳。你以為點了 margherita(瑪格麗特披薩),實際上卻收到了 margarita(瑪格麗特調酒)。

Figure 1.3: If you think you're talking to a pizza restaurant, when you're in fact talking to a Mexican restaurant, your order may still make sense, but you'll get a surprise when it's delivered.
其他工程師使用我們的程式碼時,會根據命名、資料型別和慣例建立心理模型。如果程式碼做了超出這個模型的事情,就會產生意外,而意外往往在很久之後才以詭異的方式浮現。
讓程式碼不易被誤用#
電視背面的插孔被設計成不同形狀,讓你不可能把電源線插進 HDMI 孔。

Figure 1.4: The sockets on the back of a TV are deliberately different shapes to make it hard to plug the wrong cables into the wrong holes.
程式碼也是如此——其他程式碼會「插入」各種輸入參數或前置狀態。如果錯誤的東西被插入,系統可能崩潰、資料庫損壞、重要資料遺失。透過設計讓程式碼難以(甚至不可能)被誤用,能大幅提升軟體的可靠性。
讓程式碼模組化#
模組化(Modularity)意味著系統由可獨立替換的小元件組成。以兩個玩具為例:
- 模組化的玩具(左):頭、手、腳可以獨立拆裝替換,元件間只有簡單的介面(一個凸榫對一個孔)
- 非模組化的玩具(右):所有部件縫在一起,無法獨立替換,介面極度複雜(20 多條線交織)

Figure 1.5: A modular toy can be easily reconfigured. A toy that has been stitched together is extremely hard to reconfigure.
模組化的程式碼更容易適應需求變更(修改一處不會牽動全局),也更容易理解和推理。
讓程式碼可重用與可泛化#
- 可重用性(Reusability):同一段程式碼能在不同場景下解決相同問題(如電鑽能鑽牆、鑽地板、鑽天花板)
- 可泛化性(Generalizability):程式碼能解決概念相似但細節不同的問題(如電鑽既能鑽孔也能鎖螺絲)
程式碼的建立與維護都需要時間和心力,而且寫越多就越可能引入 Bug。讓程式碼可重用和可泛化,能減少程式碼總量,同時提高可靠性。
讓程式碼可測試且正確測試#
測試是確保程式碼能運作且持續運作的關鍵防線,在兩個關鍵時間點發揮作用:
- 阻擋有問題的程式碼提交到程式碼庫
- 阻擋有問題的版本發布到生產環境

Figure 1.6: Tests are vital for minimizing the chance that bugs and broken functionality enter the codebase.
測試分為幾個層級:
| 測試層級 | 說明 |
|---|---|
| 單元測試(Unit tests) | 測試個別函式或類別,是工程師日常最常接觸的層級 |
| 整合測試(Integration tests) | 測試多個元件整合在一起時是否正常運作 |
| 端對端測試(E2E tests) | 測試從頭到尾的完整使用流程 |
注意: 「可測試性」和「測試」是兩個不同概念。即使你想寫測試,如果程式碼本身不具備可測試性(例如過度耦合),就無法有效測試。在寫程式碼的過程中,應持續問自己「這要怎麼測試?」
補充: 測試驅動開發(TDD)主張先寫測試再寫程式碼,是確保可測試性的一種有效實踐。
mindmap root((程式碼品質)) 四個目標 能運作 能持續運作 能適應變化 不重造輪子 六大支柱 可讀 無意外 不易誤用 模組化 可重用與可泛化 可測試
寫高品質程式碼會拖慢開發嗎?#
短期看來,寫高品質程式碼確實需要多花一些心思。但只要不是一次性的拋棄式工具,高品質程式碼在中長期幾乎總是能加速開發。
作者用「裝層板」來比喻:
- 正確做法:用電鑽和螺絲固定支架,花 30 分鐘。日後調整或重新裝潢都很容易
- 偷懶做法:用膠水黏上去,花 10 分鐘。但層板很快會連同牆面石膏一起掉落,修復要花數小時甚至數天
重點: 「欲速則不達」(Less haste, more speed)——不要把匆忙當成效率。走捷徑省下的時間,往往會在後續的修復、重構和除錯中加倍償還。
總結#
- 要產出好軟體,需要寫高品質的程式碼
- 程式碼在成為正式軟體前,通常需要通過數道檢查與測試關卡
- 高品質程式碼追求四個目標:能運作、持續運作、能適應變化、不重造輪子
- 實現品質的六大支柱:可讀、無意外、不易誤用、模組化、可重用、可測試
- 短期看似變慢,但中長期必然加速開發