1. 作品集作為信任櫥窗
初學者的作品集常常長這樣:十個儲存庫,每個裡面都有 final_final2.go,而 README 裡驕傲地寫著 “My cool project”。在面試時,這對信任幾乎沒有幫助,因為看不到最重要的東西:你的程式碼如何運作、它有哪些 契約,以及它是否 值得信賴。作品集不是在比數量,而是在展示品質。
想像你的專案是一台小型裝置。使用者不需要知道裡面的齒輪是怎麼咬合的。使用者在意的是:它能不能開機、螢幕顯示什麼、出錯時會怎樣、按錯鍵會不會爆掉。在軟體裡,「螢幕」就是 CLI/HTTP 契約,而「不會爆掉」則是測試、清楚的錯誤與可預測性。
要讓作品集有「形狀」,最好記住三件事:展示 → 保證 → 可重現性。展示回答「它做什麼、為什麼要做」,保證回答「為什麼能信任它」,可重現性回答「要怎麼啟動並驗證它」。在好的專案裡,這些內容 2–3 分鐘內就看得出來,不需要進入考古模式。
學習型應用程式的展示用迷你骨架
先看一個假想的課程最終專案——任務管理器(就叫 tasker 吧),它有 CLI 和 HTTP API。在展示時,你幾乎總是會秀同一類東西:happy-path 與一到兩個 error-path,但重點是要透過契約來呈現。
下面是一小段「正確」的 CLI 進入點,因為行為集中且容易理解,所以非常適合放進作品集:
package main
import (
"os"
)
func main() {
os.Exit(run(os.Args[1:]))
}
再來是你有意識地管理 CLI 的「外部契約」的地方(引數 → 離開代碼):
package main
import (
"errors"
"fmt"
"os"
)
var ErrUsage = errors.New("usage")
func run(args []string) int {
if len(args) == 0 {
fmt.Fprintln(os.Stderr, "usage: tasker <command>")
return 2
}
return 0
}
這是一個很小的例子,但它顯示出成熟度:你不是把 os.Exit 到處散佈在程式裡,而是把外部契約集中在一個地方。
2. README 作為專案介面
README 不是一篇「我和 Go 一起度過暑假」的散文。它是一份說明文件,幫助使用者快速回答四個問題:專案做什麼、如何啟動、如何驗證品質、去哪裡看範例。如果 README 回答不了這些問題,那它就不是 README,而是一張裝飾用明信片。
作品集特別重視「理解速度」:審查者越快感受到「這個專案很整潔」的訊號,就越可能真的去讀程式碼。諷刺的是,好的 README 往往比漂亮的架構更重要,因為沒有讀者的架構,就像沒有觀眾的笑話:作者覺得好笑,其他人一片安靜。
一個很好的做法是把 README 寫成「quickstart + contract」的風格。下面是一段可作為參考的範例(這是文字,但結構比具體措辭更重要):
tasker — 最小任務管理器(CLI + HTTP)。
Quickstart:
go test ./...
go run ./cmd/tasker help
CLI contract:
stdout — 資料
stderr — 錯誤/usage
exit codes: 0 ok, 2 usage, 1 runtime
HTTP contract:
JSON, Content-Type: application/json
錯誤: { "error": { "code": "...", "message": "...", "fields": {...} } }
請注意:這裡沒有「我們使用了帶有量子 enum 的微服務架構」。這裡有的是你可以在一分鐘內動手驗證的內容。
Example 測試作為作品集的一部分
README 裡的普通範例很容易過時。Example 測試 可以編譯,而且能被 go test 驗證,所以它是「活的範例」。這是展示品質最被低估的方法之一:你不是用話術說服別人,而是直接展示一個可驗證的情境。
例如,你希望 ID 解析函式既讓人看得懂,也讓測試執行器看得懂:
package tasker
import (
"fmt"
"strconv"
)
func ExampleParseID() {
id, err := strconv.Atoi("42")
fmt.Println(id, err == nil) // 42 true
// Output: 42 true
}
在作品集中,這就像一個小小的保證:我不只是寫了程式碼,我還把行為固定下來,讓它不會「漂移」。
3. 程式碼審查作為一種能力
很多初學者把程式碼審查看成考試:「現在要來挑我毛病了」。實際上,程式碼審查是降低錯誤風險、提升溝通品質的一種方式。它是共同設計。有時候它真的讓人不舒服,但更常見的不舒服並不是審查本身,而是習慣不足:看不懂的 diff、混亂的變更、沒有測試、沒有說明「為什麼要改」。
好消息是:程式碼審查是一項可以訓練的技能。更好的消息是:即使你沒有團隊,也可以從今天開始做審查,因為有個很強的技巧——自我審查。你先替自己做一個 PR,走過品質檢查,然後再給別人看。這會大幅降低像「嗯,gofmt 本來也可以先跑一下吧?」這類意見的數量。
在作品集中,程式碼審查是間接可見的:從 commit 歷史、變更是否原子化、是否有測試、以及錯誤處理是否清楚,都能看出來。即使沒有人在 GitHub 上留言,專案也可能看起來像是「經過一位成熟工程師審過的」。
以 tasker 的變更為例,進行小型自我審查儀式
假設你新增了任務標題驗證。差的版本通常長這樣:函式「就地堆上去」、錯誤風格不一致、沒有測試、驗證邏輯散落在三層。
整潔的版本會從一個小函式開始,而且這個函式很容易測試:
package tasker
import "errors"
var ErrTitleEmpty = errors.New("title is empty")
func ValidateTitle(title string) error {
if title == "" {
return ErrTitleEmpty
}
return nil
}
是的,這是一個很簡單的函式。但正是這類東西,會塑造你對程式碼的「品味」:小、可讀、可測試的片段。
接著是一個小小的 table-driven 測試,用來固定契約:
package tasker
import "testing"
func TestValidateTitle(t *testing.T) {
if err := ValidateTitle(""); err == nil {
t.Fatalf("expected error")
}
if err := ValidateTitle("buy milk"); err != nil {
t.Fatalf("unexpected error: %v", err)
}
}
這樣的程式碼在審查時通常不太會被挑剔。不是因為它「完美」,而是因為它不需要別人猜。
把品質檢查變成習慣
重點是不要讓品質取決於心情(「今天我很棒,明天我很累」)。所以多數團隊會把品質做成固定儀式。你已經知道工具:格式化、測試、靜態分析。接下來不是「要跑哪些」,而是「怎麼把它變成習慣」。
這裡有個很簡單的想法:手動步驟越少,你真的做出來的機率就越高。即使是在單人專案中,也可以準備一條你每次推送前都會執行的命令。有時候會透過 Makefile,有時候是腳本,有時候是 IDE 的執行設定——不重要。重要的是,「檢查自己」應該像打開瀏覽器分心一樣容易。
4. 閱讀標準函式庫原始碼
閱讀標準函式庫原始碼聽起來像是只有穿黑斗篷的人才會做的事,通常是在編譯器不編譯的時候。其實這是一個非常實用的習慣。Go 的標準函式庫是一整本解法集:如何處理錯誤、如何圍繞介面設計 API、如何寫出能活上好幾年的程式碼,以及為什麼簡單有時候不是靠魔法,而是靠紀律。
閱讀 stdlib 時,不要抱著「我現在就要全部看懂」的心態,而是抱著「我現在只要懂一小塊,並從中偷一個好習慣」的心態。這就像健身房:你不會去一次就變成超級英雄。你會持續去,幾個月後你才會突然發現,自己的程式碼變得更穩定、更乾淨了。
還有一個好處:當你閱讀 stdlib 時,你會不再相信迷思。你會看到真實程式碼如何以 context 包裝錯誤、如何維持小介面、如何對輸入邊界投入大量注意力——然後「魔法思維」就會開始死亡。
如何找到某個套件的原始碼
在 Go 裡這件事相當直接:你有 GOROOT,標準函式庫就放在那裡。如果你使用 IDE,通常只要對 net/http 或 encoding/json 做「Go to definition」,就能跳到原始碼。如果你喜歡終端機(或 IDE 顯示了路徑),也可以從 GOROOT 來定位。
如果你想真正「感受」Go 不只是語言,還是一整套工具生態,那麼你應該知道 go 指令有很多模式,以及專案周邊的各種檔案。例如 workspaces(go.work)是一起管理多個模組的方法之一;它不是初學者每天都必須用到的東西,但它被文件化並且被工具支援,這本身就是「Go 文化」的一部分。
此外,還要記得某些指令是流程中的獨立步驟。例如 go generate 的確存在,但它不會「自動魔法般」加入建置流程:你需要明確執行它,而這對可重現性非常重要。即使你現在不用 go generate,理解這種哲學也有助於寫出沒有隱藏魔法的專案。
如果你是新手,stdlib 該先讀什麼
不需要從 runtime 開始。最好從你在課程中已經用過的套件開始:errors、fmt、io、bufio、net/http、encoding/json、context、sync。在那裡,你會看到熟悉的概念以「理想版本」呈現。
一個非常有用的閱讀技巧是:從介面走向實作。先看契約長什麼樣子(例如 io.Reader),再看誰實作它,最後看它周圍包了哪些 wrapper/decorator。這和我們的課程一樣:先看契約,再看實作,再看可測試性。
迷你練習:stdlib 風格的裝飾器
在閱讀 stdlib,尤其是 io 周邊的套件時,會有一種感覺:「他們把所有東西都包成某個實作介面的東西了。」這的確是真的:Go 非常喜歡小型 wrapper,它們不會「破壞」任何東西,而是新增行為。這是成長的絕佳訓練:你學會用組合而不是重寫來擴充系統。
讓我們在 tasker 裡做一個小步驟:為 io.Writer 加上一層 wrapper,用來計算我們寫了多少位元組。這很適合用在日誌、指標或測試,而這正是你在標準函式庫中會反覆看到的思維方式。
package tasker
import "io"
type CountingWriter struct {
W io.Writer
N int
}
func (cw *CountingWriter) Write(p []byte) (int, error) {
n, err := cw.W.Write(p)
cw.N += n
return n, err
}
現在你可以在任何有 writer 的地方使用它(stdout、檔案、緩衝區)。這非常「Go」:最少的魔法,最多的透明度。
例如,你想在 CLI 中計算你輸出了多少位元組給使用者:
package main
import (
"fmt"
"os"
"example.com/tasker"
)
func main() {
cw := &tasker.CountingWriter{W: os.Stdout}
fmt.Fprintln(cw, "hello") // hello
fmt.Println("bytes:", cw.N) // bytes: 6
}
沒錯,這個範例很玩具化。但它教了三件成熟的事:介面、組合與可觀測性。而在 stdlib 裡,這種小小的「積木」非常多——這正是閱讀它的原始碼如此能鍛鍊腦力的原因。
5. 成長節奏
幾乎所有成長計畫都會被同一件事打敗:人們給自己訂下「把所有東西都學完」的目標,然後一週後就開始討厭自己和 Go。為了不要重演這種經典黑色喜劇,最好接受一個簡單觀念:成長必須是小步的、規律的、可衡量的。這裡不是指 KPI 式的數字,而是指「我可以誠實地說我做了一步」。
一種很方便的形式是每週節奏,裡面有幾個重複活動:稍微改善一點專案(作品集)、稍微練習審查、稍微讀一點好程式碼。重點不是數量,而是穩定性。如果你每週只做 20 分鐘,但每週都做,那會比兩個月才一次的「週末馬拉松」更有用。
下面是一個很貼近現實的節奏範例,即使你是邊工作/邊讀書也能套用:
| 習慣 | 時間 | 什麼算「完成」 |
|---|---|---|
| 專案小幅改善 | 30–60 分鐘/週 | 一個 PR:測試、修 bug、小功能 |
| 自我審查 | 10–15 分鐘/PR | 跑完檢查、重新讀過 diff |
| 閱讀 stdlib | 20–30 分鐘/週 | 一個檔案/一個函式 + 筆記 |
| 文件 | 15 分鐘/週 | 改善 README 或新增 Example |
請注意:這裡沒有「學會 Kafka」這一項。不是因為 Kafka 不好,而是因為如果沒有節奏,你連 fmt.Printf 都學不好——最後只會剩下罪惡感,還有一個「之後再看」的課程分頁。
還有一個重要觀念:留意平台的變化。Go 會持續演進,工具會改變,新的預設值會出現。例如,在 Go 1.25 中,容器內 GOMAXPROCS 的行為有所改變:runtime 會預設考慮 CPU limits,以避免不愉快的 throttling 延遲。你不需要現在就「深入學容器」,但培養閱讀這類說明、理解平台是活的的習慣,會很有幫助。
6. 個人成長策略中的典型錯誤
錯誤 1:把作品集做成「數量導向」,而不是「信任導向」。
當你有很多儲存庫,但沒有任何一個具備清楚的 quickstart、測試與明確契約時,審查者很難相信你的程度。更有說服力的是一個第一次就能跑起來、錯誤穩定、測試完善,而且有清楚 README 的專案。
錯誤 2:把程式碼審查當成懲罰。
如果你把審查想成「判決」,你就會開始藏變更、把變更做得又小又沒意義,或者反過來一口氣塞進超大的 commit,「免得等一下又想改」。健康的模型不是這樣:審查是在共同降低風險。送出前先自我審查,是讓審查變得平靜又有用的最好方式。
錯誤 3:把 stdlib 當小說來讀(然後受苦)。
想一次看懂整個 net/http 或 encoding/json,很容易讓人失去動力。更有效的方法是小口小口讀:一個型別、一個函式、一個測試。重點是累積習慣與「專業品味」,而不是一次性的壯舉。
錯誤 4:把「我知道」和「我能展示」混為一談。
在面試與工作中,大家重視的不是你「大概懂」,而是你能不能快速重現:跑測試、展示 demo、解釋錯誤契約。所以作品集必須可展示:啟動命令、情境流程、預期結果。
錯誤 5:把品質改善留到「有空再說」。
如果品質沒有被內建進流程,它就不會自己出現。某個時候專案開始活起來、bug 累積、你把測試一拖再拖。更省成本的做法是:一個小儀式——格式化、測試、靜態分析,最後才 commit。
GO TO FULL VERSION