可靠性的代價是對極致簡潔的追求。 — C.A.R. Hoare,圖靈獎演講
軟體系統天生動態而不穩。本章談 SRE 為什麼要花力氣維持簡潔——並把簡潔視為可靠性的前提。
穩定 vs. 敏捷#
SRE 的工作可以總結為一句話:讓系統的敏捷度與穩定性保持平衡。
少數情況可以為了敏捷犧牲穩定——例如做「探索性編碼(exploratory coding)」:刻意給程式碼一個保存期限,允許試錯,因此測試與發佈門檻可放寬。
但對絕大多數生產系統,要求是平衡。SRE 經驗顯示:可靠的流程其實會提升開發敏捷度——
- 快速、可靠的上線讓變更後果可見
- bug 出現後更快被定位與修復
- 開發者因此能把注意力放在真正的功能與效能上
無趣是美德#
Robert Muth(Google 工程師):「不像偵探小說,原始碼沒有刺激、懸疑與謎題反而是好事。」生產環境的驚喜是 SRE 的敵人。
本質複雜度 vs. 偶發複雜度#
引用 Fred Brooks「No Silver Bullet」:
- 本質複雜度(essential complexity):問題本身內含、無法移除
- 偶發複雜度(accidental complexity):因實作選擇引入,可工程改善
例:寫 web server 要處理「快速回應」是本質複雜度;用 Java 寫導致需處理 GC 影響則是偶發複雜度。
SRE 應該:
- 在偶發複雜度被引入系統時抵抗
- 接手系統時持續清除既有的複雜度
我不要刪我的程式碼!#
工程師對自己寫的程式有感情,因此大規模清理時常會聽到:
- 「以後可能會用到」
- 「先註解掉就好」
- 「用 flag gating 不要刪」
這些都是糟糕的建議:
- 版控系統本來就能回溯,不需要保留註解碼
- 大量註解掉的程式碼會在源碼演進過程中變成干擾
- 永遠關閉的 flag 後面的死程式碼是定時炸彈(Knight Capital 的災難就是經典案例)
「負程式碼行數」這個指標#
對於 24/7 服務而言,每多一行新程式碼就多一份債。
較小的專案更易理解、易測試、缺陷更少。最令人滿足的程式設計之一是一次刪除上千行不再被需要的程式碼。
實踐:
- 嚴審程式碼是否真的服務業務目標
- 例行清理 dead code
- 在所有測試層級內建 bloat 偵測
最小化 API#
完美並不是已經無法再加,而是已經無法再減。 — Antoine de Saint Exupéry
API 是「簡潔」的清楚展現:
- 提供愈少方法與參數,愈容易讓使用者理解
- 我們愈能把心力投入在這些少數方法的品質上
- 小而清晰的 API 通常代表「問題已被充分理解」
模組化#
物件導向程式設計的法則同樣適用於分散式系統:
- Binary 之間、binary 與設定之間的鬆耦合同時促進敏捷與穩定
- 子系統的 bug 可以獨立修復、獨立推上線
- 對 API 做版本管理:使用者可繼續用舊版、安全地評估升級
- 系統釋出節奏可分歧,不必每次都全量推送
- 避免「util / misc」之類的雜湊垃圾桶——好的分散式系統由目的清晰的協作者組成
- 資料格式也要模組化:Google 的 protocol buffers 的核心設計目標就是向前向後相容
發佈的簡潔性#
一次只動少數變更會比一次推 100 個變更好——可以類比為機器學習的梯度下降:每一步都評估改善或退化。
大批變更同時上線,事後追責耗費極大;小批次反而能讓團隊更快推進、更有信心。
結語#
軟體簡潔是可靠性的前提。把每個步驟想得更簡單,並非懶惰,而是把「我們究竟想完成什麼、怎麼做最容易」釐清。
對一個功能說「No」並非限制創新——而是讓環境保持乾淨,讓焦點留在真正的工程與創新上。