一致性(consistency)是降低系統複雜性、讓系統行為顯而易見的強大工具。
為什麼一致性有效#
- 相似的事用相似的方式做、不相似的事用不同方式做
- 認知槓桿(cognitive leverage):在一處學會某做法 → 看到別處立刻能套用該知識
- 不一致 → 開發者得對每個情境分別學習 → 多花時間
一致性也降低錯誤#
- 不一致時,兩個本質不同的情境外觀可能相似 → 讀者套用先前經驗 → 假設錯 → bug
- 一致時,「看起來像」就真的是 → 假設安全
- 結果:開發更快、錯誤更少
一致性的層次(範例)#
命名#
第 14 章已討論。同一個概念在所有地方都用同一個名字。
程式風格(Coding style)#
現代開發組織常用 style guide 限制編譯器規則之外的程式結構:
- 縮排
- 大括號位置
- 宣告順序
- 命名
- 註解
- 對被視為危險的語言特性的限制
讓程式碼更易讀,也減少特定錯誤。
介面(Interface)#
具有多種實作的介面也是一種一致性:學會其中一種實作後,其他實作也變得容易理解——因為你已經知道它必須提供哪些功能。
設計模式(Design patterns)#
設計模式是針對常見問題的公認解法(如 MVC)。能套用既有設計模式 → 實作快、出錯機率低、讀者更易懂。
不變量(Invariants)#
某變數或結構永遠成立的性質。例如:「儲存文字行的資料結構,每行都以換行字元結尾」。
不變量減少要考慮的特殊情況,讓推理程式碼行為更容易。
怎麼建立與維持一致性#
長時間多人專案中,一致性很難維持:
- 一組人不知另一組的慣例
- 新進成員不知道規則 → 無心違反 → 引入新慣例與舊慣例衝突
1. 文件化(Document)#
- 建一份文件列出最重要的整體慣例(例如 coding style)
- 放在開發者一定會看到的地方(如專案 Wiki)
- 鼓勵新人加入時讀、舊人定期回顧
- 直接從現成的 style guide 改起也是個合理起點
對於更局部的慣例(例如 invariants),在程式碼相對應的位置寫文件——不寫下來別人就不會遵守。
2. 強制(Enforce)#
即使有好文件,開發者也記不全所有慣例。
最好的辦法是寫工具自動檢查違反,commit 不通過就拒絕入庫。
真實案例:行尾字元#
某專案 Unix 用 LF、Windows 用 CRLF,跨系統編輯使檔案被「全行換行」改寫,造成 diff 混亂。
解法:
- 寫一個 commit hook 腳本檢查所有修改檔,含 CR 就拒絕
- 也可手動呼叫修復檔案
- 問題立刻消失,新進成員也藉此被快速訓練
Code Review#
Code review 也是強制慣例與訓練新人的好機會。
越是吹毛求疵的審查者,團隊越快學會慣例、程式碼越乾淨。
3. 入境隨俗(When in Rome)#
最重要的慣例:「When in Rome, do as the Romans do」——進新檔案先看周圍長相。
問問自己:
- public 變數與方法是否在 private 之前?
- 方法是否按字母排序?
- 命名用
firstServerName(camel case)還是first_server_name(snake case)?
只要看起來像個慣例就跟隨。做設計決策時也問:「專案其他地方是不是已經有相似決定?」找個現成例子並沿用。
4. 別動既有慣例#
抗拒「我有更好的想法」這種衝動。
「有更好點子」不是引入不一致的充分理由——一致性的價值幾乎總是大於「某做法比另一做法好」的價值。
引入新慣例前問自己:
- 你是否擁有當初定下舊慣例時不存在的、足以推翻它的新資訊?
- 新做法夠好到值得花時間更新所有舊地方嗎?
組織同意兩者皆「是」 → 動手;做完之後舊慣例不應再有任何痕跡。但仍有風險:其他開發者可能不知道新慣例,又把舊做法引回來。
整體而言,重新審視已建立的慣例很少是好的時間花用方式。
過度應用#
一致性不只是「相似的事相似做」,也包括「不相似的事用不同方式做」。
如果熱衷一致性過頭,把不相似的東西強塞進同一框架(例如把意思不同的東西命同名、把不適合的任務硬套到既有設計模式),反而製造複雜與混亂。
一致性帶來價值的前提是:「看起來像 X,就真的是 X」。
結語#
一致性是投資心態的展現:
- 要花一些額外工夫:決定慣例、寫自動檢查、找類似情境模仿、code review 中教育團隊
- 回報:程式碼更顯而易見;開發者更快、更準確地理解系統行為,工作更快、bug 更少