iT邦幫忙

2026 iThome 鐵人賽

DAY 28
0

模組六|工程文化與收斂(Day 27–30)

遷移完成之後,API 層累積了一批「可能沒人用」的函式。

大家都知道它們在那裡。也大概知道哪幾支應該可以刪。但沒有人刪。

不是因為懶,是因為 Day 4 講過的那個問題:你沒辦法證明沒人用。

而這件事的解法,我認為是這個系列裡最值得抄的一段工程實踐:把「刪除」當成一個需要工具支撐的問題,而不是需要勇氣的問題

六個腳本

團隊為 API 層寫了一組腳本:

腳本 做什麼
分析使用狀況 掃出每一支 API 被哪些檔案引用
找出可安全刪除的 本篇重點
執行刪除 分批移除
重構單一 API 檔 依規範重排
重組模組 調整檔案劃分
冒煙測試 驗證改完之後結構仍然正確

六個腳本裡,第二個是整組的核心。因為「找得出來」比「刪得掉」難得多。

「安全」的定義

那支腳本的輸出標題,一字不差寫著:

=== Safe to delete (unused + no permission binding) ===

兩個條件:沒有被引用,而且沒有綁定權限。

第一個很直觀。第二個才是這組腳本裡最聰明的地方。

為什麼要檢查「有沒有綁權限」

我這一面看得清清楚楚沒有東西壓著,但那塊積木的另一頭還頂著上層

Day 18 講過:這個系統的權限碼就是 API 路徑字串。

所以一支 API 的路徑,可能同時出現在兩個地方:

  1. 前端程式碼裡(被呼叫)
  2. 後台的權限設定裡(被拿來判斷某個角色能不能做某件事)

而第二種完全不會出現在前端的搜尋結果裡。

想像一下這個災難:

你搜尋了整個前端專案,確認某支 API 沒有任何一行程式碼在呼叫它。
於是你刪掉它。

但那支 API 的路徑,是後台某個角色權限的一個項目。

刪掉之後,權限設定畫面上那一列變成空白,或者更糟,權限判斷開始回傳未定義。

這條檢查的價值不在技術,在於有人意識到「引用」不只發生在程式碼裡。

「沒人用」這件事,要看的不只是你的搜尋範圍,是「這個東西可能被誰引用」的完整清單。

而這份清單通常不在程式碼裡,在你對系統的理解裡,所以它必須被寫進腳本,否則下一個人不會知道要檢查這一項。

搜尋要涵蓋「字串形式的引用」

分析腳本用了兩種比對方式:

new RegExp(`\\b${name}\\b`)       // 一般的引用
new RegExp(`['"]${name}['"]`)     // 被寫成字串的引用

第二條在防什麼?動態呼叫。

如果某處寫的是 apiMap['getOrderList'] 而不是 getOrderList(...),只用一般的識別字比對是抓得到的(因為字串裡也有那個名字),但如果組法更動態一點就會漏。

這正是 Day 4 我提出的那個疑問:「如果有人寫成 this['baseUrl'] 呢」。當時我沒有答案,這裡他們給了一個:把字串形式也列進比對。

不完美(真正動態拼接的名稱還是抓不到),但它把最常見的那一種涵蓋了。

冒煙測試:把文件規範變成可執行的檢查

我把那張貼在牆上沒人看的規則折成一個擋塊,裝到滑道口上

這是我最想講的一段,因為它把 Day 15 的一個遺憾補上了。

Day 15 我說過:

命名規範寫在文件裡擋不住人,要能自動檢查才擋得住。

而那份 235 行的 API 對照表,訂了很多規範:每個模組內要依「查詢 → 修改 → 新增 → 刪除」排序、同類別內按字母序、檔案索引要跟實際檔案對得上。

這些規範後來被寫成了檢查項。

那支冒煙測試腳本驗的東西包括:

  • 檔案存在,而且跟模組索引對得上
  • 路徑常數跟匯出的函式互相對齊
  • 程式碼裡的 Api.XXX 引用真的存在
  • 路徑字串非空、沒有多餘空白
  • 模組內的排序符合規範
  • 索引文件的標題,跟程式碼裡的分段一致
  • 禁止使用別名

第五、六項就是把文件裡的排序規範,變成會噴錯的東西。

這個轉變的意義很大:

文件是「希望大家這樣做」,檢查是「不這樣做就過不了」。

而且它讓那份 235 行的對照表不會說謊:Day 15 我擔心的「如果有人加了 API 沒更新文件,這份文件就開始說謊」,這支腳本正好防的是這件事。

刪除要分批、要可回溯

有了「找得出來」的能力之後,剩下的是執行紀律。我們的做法:

一、一次刪一個模組。 不要一口氣清空。因為如果出事,你要能快速判斷是哪一批造成的。

二、獨立的改動,訊息寫清楚刪了什麼。 這樣還原的時候只要退一步。

三、刪除的東西要留下記錄。 這是 Day 15 講過的:改名的東西還找得到,刪掉的東西沒有痕跡。所以那份對照表裡有一區專門記「這些 API 被移除了」。

四、刪完跑一次冒煙測試。 確認結構仍然完整。

一個順帶的收穫

跑分析腳本的過程中,會撈出一些原本不是目標的東西:

  • 同一支 API 有兩個名字(不同時期各自包了一層)
  • 兩個不同名字的函式,打的是同一個路徑
  • 某個模組的 API 數量異常多,代表它該被拆了

這些都不是「沒人用」,但都是問題。

這是量化工具常見的副作用:你為了回答 A 問題而收集資料,結果順便看到了 B。 Day 2 那個「最長 = 最常改」的交叉比對也是這樣來的。

代價

一、六個腳本本身也是要維護的程式碼。 如果 API 檔案的寫法慣例改了,這些腳本就要跟著改。它們現在是專案的一部分,不是一次性的工具。

二、「安全」的定義是專案特有的,不能照抄。 我們的第二條件是「沒有綁權限」,那是因為這個系統的權限碼剛好是 API 路徑。你的專案可能是別的東西:可能是排程設定、可能是外部系統的呼叫、可能是某份 Excel 巨集。

所以真正該抄的不是那兩個條件,是「先列出這個東西可能被誰引用」這個動作。

三、自動化會讓人過度信任。 腳本說「安全」,不代表真的安全,它只代表通過了我們想到的那幾項檢查。Day 14 講的第三個條件(問業務、注意一年只跑一次的功能)沒有辦法被腳本涵蓋。

而工具的存在,反而會讓人跳過那一步。

帶走什麼

  1. 刪除是工程問題,不是勇氣問題。 沒有工具支撐的刪除,靠的是膽子,而膽子不可重複、也無法交接。
  2. 定義「安全」的時候,先列出「這個東西可能被誰引用」的完整清單。 程式碼引用通常只是其中一種。
  3. 搜尋要涵蓋字串形式的引用。 這是最常見、也最容易漏的一種。
  4. 文件裡的規範要變成會噴錯的檢查,否則它只是願望。 而且這樣文件才不會說謊。
  5. 工具說「安全」不等於安全,它只代表通過了你想得到的檢查。最後那一步人工確認不能省。

明天 Day 29 是倒數第二篇,講一個貫穿整個系列的問題:什麼時候該把兩個東西合併成共用的?

我會給一個我們實際走過的兩階段流程:先刻意寫兩份,隔了幾個月,確認它們真的一樣,才合併。


上一篇
Day 27|Day 3 那三行被註解掉的程式碼,沒有人知道為什麼
下一篇
Day 29|我們刻意先寫了兩份,隔了幾個月才合併
系列文
一個活了六年的 Vue 2 後台,升級到 Vue 3 的那兩年30
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言