可維護性
程式碼被閱讀的次數遠多於被撰寫的次數。可維護性是區分一個三年歷史的程式碼庫是令人愉悅的還是像個焦油坑的關鍵。為下一位開發者最佳化,他可能六個月後的你就是他。
規則
- 一個功能,一個地方。 依功能進行封裝(參閱 backend/core/SKILL.md)。單一變更應觸及相鄰的檔案,而非散落在各層。
- 只在模組邊界使用介面。 在功能內部,使用具體類別即可。介面的存在是為了讓呼叫方能跨越邊界依賴合約,而非為了裝飾每一個類別。
- 刪除,不要註解掉。 死程式碼與永久的
// TODO註解會腐爛。Git 會記住;IDE 不需要。 - 偏好小型純函數。 更容易測試、推論與組合。副作用應置於系統邊緣,而非散落其中。
- 測試涵蓋行為,而非實作。 重寫內部實作不應破壞測試。若測試失敗,代表測試與錯誤的東西耦合了。
- 公開 API 需有版本管理。 破壞性變更應透過新版本或功能旗標,絕不能默默重新命名。
- 依賴注入勝過靜態單例。 靜態方法難以測試且隱藏耦合。將依賴傳入;在測試中模擬它們。
- 鎖定並定期更新依賴。 提交鎖定檔;透過 Renovate/Dependabot 自動開 PR。落後兩年意味著一次未規劃的兩週遷移。
- 文件說明「為什麼」,而非「做什麼」。 程式碼顯示做了什麼;註解解釋商業規則、歷史限制、非顯而易見的權衡。
- 在 CI 中進行 lint、格式與型別檢查。 非建議性,而是阻擋性。人類應討論設計,而非空格。
- 保持建置綠色且快速。 不穩定或緩慢的測試會被忽略,一旦被忽略,就無法保護任何東西。
危險訊號
- 單一檔案超過約 500 行,或一個類別有超過約 10 個公開方法——通常代表某個功能想逃脫。
- 共享的「utils」套件,無人認領的工具函數在其中慢慢死去。
- 為了讓測試通過而模擬受測物件。
- 「不要碰那個模組,已經沒人懂它了。」
- CI 建置時間以十分鐘為單位。