一致性(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. 別動既有慣例#

抗拒「我有更好的想法」這種衝動。

有更好點子不是引入不一致的充分理由——一致性的價值幾乎總是大於「某做法比另一做法好」的價值。

引入新慣例前問自己:

  1. 你是否擁有當初定下舊慣例時不存在的、足以推翻它的新資訊?
  2. 新做法夠好到值得花時間更新所有舊地方嗎?

組織同意兩者皆「是」 → 動手;做完之後舊慣例不應再有任何痕跡。但仍有風險:其他開發者可能不知道新慣例,又把舊做法引回來。

整體而言,重新審視已建立的慣例很少是好的時間花用方式

過度應用#

一致性不只是「相似的事相似做」,也包括「不相似的事用不同方式做」。

如果熱衷一致性過頭,把不相似的東西強塞進同一框架(例如把意思不同的東西命同名、把不適合的任務硬套到既有設計模式),反而製造複雜與混亂

一致性帶來價值的前提是:「看起來像 X,就真的是 X」。

結語#

一致性是投資心態的展現:

  • 要花一些額外工夫:決定慣例、寫自動檢查、找類似情境模仿、code review 中教育團隊
  • 回報:程式碼更顯而易見;開發者更快、更準確地理解系統行為,工作更快、bug 更少