🎯 什麼情境該想到我

當你看到「永遠不會被執行、或已經沒有任何地方在使用」的程式碼——被註解掉的舊實作、再也沒人呼叫的函式、不可能成立的條件分支——它們只會增加閱讀時的負擔。

⚙️ 怎麼用(步驟 / 公式)

意圖:把死掉的程式碼刪掉。留著它不會帶來價值,只會讓讀者以為「這還有用」而多花心力理解。有版本控制在,需要時隨時能找回來。

小步安全進行:

  1. 確認這段程式碼真的沒有被使用(用工具搜尋呼叫端、靜態分析找不可達碼)。
  2. 若它曾對外公開(是 API),先確認外部確實沒有依賴。
  3. 直接刪除,不要用註解「暫時封存」——那只是另一種雜訊。
  4. 執行測試,確認沒有東西壞掉。

★ Go 的優勢:編譯器幫你抓掉一部分

func f() {
    x := 1          // ★ declared and not used —— 編譯錯誤,不是警告
    return
    fmt.Println()   // ★ missing return / unreachable code(vet 的 unreachable 會報)
}
import "os"         // ★ "os" imported and not used —— 編譯錯誤

★ Go 把「未使用的區域變數與 import」定為編譯錯誤,這是它相對多數語言最大的優勢:
這一類死碼在 Go 裡根本活不下來。

⚠️ 但編譯器抓不到這四種

抓不到怎麼找
未使用的匯出函式/型別/方法staticcheck 的 U1000(unused),或 deadcode(golang.org/x/tools/cmd/deadcode)
未使用的 struct 欄位staticcheck 的 unused;但被反射/JSON tag 用到的會誤判
★ 永遠為假的分支沒有工具能通用地抓。靠 coverage 報告:go test -coverprofile 後看 0% 的行
★ 整包沒人 import 的 packagedeadcode 或 go mod why;grep -rn '"module/path/pkg"'
# ★ 找死碼最實用的一招:用 coverage 反推
go test ./... -coverprofile=c.out && go tool cover -html=c.out
# 紅色(0 次執行)的分支,有些是缺測試,有些是真的死碼 —— 要人來判斷

★★ 刪之前必須確認的五件事(Go 版)

  1. grep 字串引用:反射、encoding/json tag、RPC/HTTP 路由註冊表、DI 容器
    —— 這些靠字串找函式和欄位,編譯器完全不保護你。
    grep -rn '"HandleLegacyWebhook"' .      # ★ 函式名當字串用的地方
  2. init() 的副作用:import _ "pkg" 只為了跑它的 init()(driver 註冊是典型)。
    刪掉那行 import 會讓程式編譯成功、執行期才找不到 driver。
  3. build tag://go:build linux 的檔案在 macOS 上「看起來」沒人用。
    用 GOOS=linux go build ./... 逐個平台確認。
  4. go:generate 產生的碼:刪了會在下次 generate 時回來。要改的是產生器。
  5. 匯出的 API 不是你的:別的 module 可能在用。先掛 // Deprecated: 一個版本再刪。

★ 為什麼不是「註解掉」或「留著以備萬一」

★ 版本控制就是你的「以備萬一」。 註解掉的碼有三個具體傷害:
① 搜尋時會命中,浪費讀者時間;② 不會被編譯器與重構工具檢查,很快就爛掉、再也編不過;
③ 讀者無法判斷它是「暫時關掉」還是「被遺忘」——於是沒人敢動它。

唯一的例外:用 feature flag 關掉、但確定要在近期重新開啟的碼。
那要有明確的移除期限和一張 ticket,否則就是死碼披上偽裝。

和相鄰概念的界線

差別
冗員元素那是「存在但不值得存在」的抽象層;死碼是「完全沒人呼叫」
誇誇其談通用性為了假想需求準備的擴充點——通常也是死碼,但要連設計一起拿掉

🧪 我實際套用的紀錄

  • (待填)

⚠️ 注意 / 什麼時候不適用

  • 「可能之後會用到」不是保留的理由——版本控制就是你的還原機制,別靠註解保存。

  • 對外公開的介面要先確認沒有隱形依賴(反射、動態呼叫、外部呼叫端)再刪。

  • 不確定是否真的無用時,先加日誌/監控觀察一段時間,再決定刪除。

  • ★ 反射、JSON tag、路由註冊表、DI 容器用字串找程式碼,編譯器不保護你。 刪之前 grep 那個名字。

  • ★ import _ "pkg" 是為了 init() 副作用(DB driver、image 格式、pprof handler)。看起來沒用,刪了執行期才爆。

  • build tag 下的檔案在你的平台上「看起來」沒人用。逐個 GOOS 確認。

  • 匯出的 API 要先 Deprecated 一個版本,不能直接刪。

  • 不要註解掉,要真的刪。註解掉的碼不被編譯器檢查,很快就爛到無法復原——反而不如 git history。

  • 一次刪一批、一個 commit 只刪死碼。混在功能改動裡,review 的人會直接放過。

  • 測試碼裡的死碼也要刪:沒被任何 test 呼叫的 helper、永遠不會跑到的 t.Skip 分支。

🔗 相關工具