軟體工程不僅僅是讓程式碼能夠運行,更重要的是保證其品質:可讀性、可維護性、以及潛在錯誤的預防。
如果單純依賴人工 Code Review 來檢查程式碼風格、未處理的錯誤等問題,效率低下且容易遺漏。
靜態分析(Static Analysis)工具 或稱 Linter,能在不實際運行程式碼的情況下對其進行掃描,自動找出潛在的問題。在 Go 生態中,golangci-lint
是這個領域的王者。
格式化工具 則確保程式碼風格的一致性,gofumpt
是一個比 gofmt
更嚴格的格式化工具,能幫助團隊維持統一的程式碼風格。
golangci-lint
的優勢golangci-lint
是一個 Go Linter 的聚合器,它將數十個社群中廣受好評的 Linter(如 go vet
, errcheck
, staticcheck
)整合到一個工具中,並提供了無與倫比的執行速度(透過平行化和快取)。它讓我們可以用一個設定檔,管理所有的 Linter 規則。
golangci-lint
:# binary will be $(go env GOPATH)/bin/golangci-lint
curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/HEAD/install.sh | sh -s -- -b $(go env GOPATH)/bin v2.5.0
golangci-lint --version
.golangci.yaml
在專案根目錄下建立 .golangci.yaml
,這個檔案用來定義你想啟用的 Linter 以及相關規則:
## 設定 golangci-lint 說明文件
## https://golangci-lint.run/usage/configuration/
version: "2"
run:
# 執行緒數,0 代表使用所有 CPU 核心
concurrency: 0
# 超時設定
timeout: 5m
# 在測試檔案中也執行 lint
tests: true
linters:
default: none
enable: # 啟用的 linters 列表
- govet # Go 官方的程式碼分析工具
- errcheck # 檢查未處理的 error
- staticcheck # 一套強大的靜態分析檢查
- unused # 檢查未使用的變數或函式
- ineffassign # 檢查無效的賦值
- unconvert # 檢查不必要的類型轉換
- nolintlint # 檢查 nolint 註解的使用
- bodyclose # 確保 HTTP 回應的 Body 被正確關閉
- cyclop # 檢查函式的圈複雜度
settings: # 各個 linter 的設定
cyclop:
max-complexity: 30 # 函式最大圈複雜度
package-average: 10 # 套件平均圈複雜度
errcheck:
check-type-assertions: true
check-blank: true
issues:
max-issues-per-linter: 10 # 每個 linter 最多顯示 10 個問題
max-same-issues: 5 # 同一個問題最多顯示 5 次
formatters:
enable:
- goimports # 使用 goimports 格式化輸出
- gofmt # 使用 gofmt 格式化輸出
這份設定檔啟用了多個常用的 Linter,並對一些 Linter 進行了基本設定。你可以根據團隊需求調整這些設定。
詳細的設定選項可以參考官方文件:Configuration。
在本地開發環境中,我們可以直接在命令列執行 golangci-lint
來檢查程式碼:
golangci-lint run
我們可以將它整合到 Makefile
中,方便團隊成員使用:
.PHONY: lint
lint: ## Run linter
@golangci-lint run ./...
我們可以將其設定在 VSCode 的工作區設定中,讓每次儲存檔案時自動執行 Lint:
{
"go.lintTool": "golangci-lint",
"go.lintOnSave": "file",
"go.lintFlags": [
"--config=./.golangci.yml"
]
}
這段設定告訴 VS Code 的 Go 擴充套件:
golangci-lint
作為 lint 工具。.golangci.yaml
設定檔。我們可以將其設定在 Git pre-commit hook 中,確保每次提交前都會進行檢查:
#!/bin/sh
golangci-lint run ./...
if [ $? -ne 0 ]; then
echo "Linting failed, please fix the issues before committing."
exit 1
fi
將這段腳本儲存為 .git/hooks/pre-commit
,並賦予執行權限:
chmod +x .git/hooks/pre-commit
這樣,每次嘗試提交程式碼時,Git 都會先執行 golangci-lint
,如果有任何問題,提交將被阻止,並提示開發者修正問題。
在 CI/CD 流程中,我們可以加入 golangci-lint
的檢查步驟,確保所有合併到主分支的程式碼都符合團隊的品質標準。
基礎上就是使用 golangci-lint 官方提供的 Docker Image 來執行 lint 檢查。
各家 CI/CD 平台的設定方式略有不同,就不一一展開說明。
gofumpt
的介紹與整合gofumpt
是一個比 gofmt
更嚴格的格式化工具,能幫助團隊維持統一的程式碼風格。它在 gofmt
的基礎上增加了一些額外的格式化規則,確保程式碼更加整潔和一致。
gofumpt
:go install mvdan.cc/gofumpt@latest
在本地開發環境中,我們可以直接在命令列執行 gofumpt
來格式化程式碼:
gofumpt -w .
我們可以將它整合到 Makefile
中,方便團隊成員使用:
.PHONY: fmt
fmt: ## Run gofumpt
@gofumpt -w .
我們可以將其設定在 VSCode 的工作區設定中,讓每次儲存檔案時自動執行格式化:
{
"go.useLanguageServer": true,
"gopls": {
"formatting.gofumpt": true
}
}
這段設定告訴 VS Code 的 Go 擴充套件:
gofumpt
作為格式化工具。我們可以將 gofumpt
整合到 golangci-lint
中,確保每次執行 lint 時也會進行格式化檢查。
在 .golangci.yaml
中加入 gofumpt
:
formatters:
enable:
- gofumpt # 使用 gofumpt 格式化輸出 // 新增這一行
這樣,每次執行 golangci-lint
時,也會檢查程式碼是否符合 gofumpt
的格式要求。
然而 golangci-lint
並不會自動修正格式問題,只會報告違規的地方。開發者仍需手動執行 gofumpt -w .
來修正格式。
但如果有整合在 VSCode 或 Makefile 中,這個步驟會變得非常簡單,或者是根本不需要特別去執行。
透過 golangci-lint
和 gofumpt
的整合,我們可以大幅提升團隊的程式碼品質和一致性。
這不僅減少了人工 Code Review 的負擔,還能及早發現潛在的問題,讓我們的專案更加健壯和易於維護。