0.1 Go 的簡單哲學與認知負擔
0.1 Go 的簡單哲學與認知負擔
Go 的核心取捨是降低讀程式的人需要同時記住的事情。它不追求語法表現力最大化,而是追求團隊在多年後仍能快速判讀服務如何啟動、資料如何流動、錯誤如何處理。這些特性之所以重要,是因為它們直接支撐了 Go 在高併發服務、worker、長連線與事件處理場景中的可維護性。
本章目標
學完本章後,你將能夠:
- 說明 Go 為什麼偏好顯式控制流程
- 看懂入口程式中依賴組裝的意圖
- 區分「程式碼短」和「認知負擔低」
- 用 Go 的風格閱讀現有服務
為什麼這章在第零章
如果工作負載、架構與 runtime 條件已經顯示 Go 是合適選項,接下來就要理解 Go 為什麼會長成現在這種樣子。簡單、顯式、少魔法是讓高併發服務在多人維護時仍能被快速理解的工程策略。
【觀察】Go 程式的入口通常很直
一個簡化的通知程式,入口可能會做幾件明確的事:
1events := make(chan Event, 128)
2notifications := make(chan Notification, 128)
3
4repo := NewNotificationRepository()
5worker := NewWorker(repo, events, notifications)
6server := NewHTTPServer(repo, notifications)這段程式沒有依賴注入框架,也沒有隱式容器。所有元件的建立順序、依賴關係、資料流向都直接寫在入口。
這種寫法特別適合服務型應用:當系統需要處理很多並發請求、背景工作或外部事件時,入口越清楚,就越容易確認誰負責什麼、失敗時會停在哪裡。
【判讀】簡單是少猜幾件事
對維護者來說,入口程式的主要工作是回答三個問題:
- 哪些元件存在?
- 元件彼此怎麼連接?
- 程式關閉時誰負責停止?
Go 偏好把這些答案留在表面。當你看到 NewWorker(repo, events, notifications),你不需要先理解框架規則,就能知道 worker 依賴 repository,從事件 channel 讀資料,輸出通知到另一個 channel。抽象的責任是讓資料流更容易判讀;抽象若讓讀者需要猜測背後規則,就削弱了 Go 在長期維護上的主要價值。
【策略】閱讀 Go 程式先找資料流
讀 Go 應用時,可以用以下順序降低認知負擔:
| 順序 | 問題 | 對應檔案 |
|---|---|---|
| 1 | process 從哪裡開始? | 入口程式 |
| 2 | HTTP endpoint 在哪裡註冊? | route 註冊處 |
| 3 | 背景工作有哪些? | go ... 呼叫 |
| 4 | 資料用什麼型別傳遞? | model 定義 |
| 5 | 共享狀態由誰保護? | repository 或狀態元件 |
這個順序先建立系統地圖,再深入單一函式,避免一開始就陷入細節。
【執行】用入口程式畫出資料流
即時通知服務可以先整理成這張資料流:
1file / HTTP / timer ──> events ──> Worker ──> notifications
2 │
3 ▼
4 Repository
5 │
6 ▼
7 HTTP API這張圖比逐行閱讀更重要。它先回答「系統如何運作」,再讓你回到個別函式確認細節。