在我們的程式碼庫中,通常有幾個面向需要達成並持續監控:功能正確性(是否如預期運作)、架構適配性(是否足夠快速、安全且易用),以及可維護性。我在此將可維護性定義為:讓日後變更程式碼庫變得簡單且風險低 —— 也就是所謂的「內部品質」。因此,我不只希望今天能快速進行變更,也希望未來依然如此。而且我不想擔心每次進行變更(或讓 AI 進行變更)時,都會引入錯誤或降低適配性。我通常會在 AI 產生的程式碼庫中,發現可維護性出現裂痕的第一個跡象:即使是微小的調整,也需要變更越來越多的檔案;或者,變更開始破壞原本正常運作的功能。

內部品質問題對 AI 代理的影響,與對人類開發者的影響相似。在混亂的程式碼庫中,代理可能會在錯誤的地方尋找既有實作、因為沒有注意到重複而產生不一致,或是被迫載入超過任務所需的上下文。

在本文中,我將描述我對各種感測器的實驗,這些感測器能幫助我們與 AI 反思程式碼庫的可維護性,以及我從中學到的經驗。

應用程式

我正在開發一個供社群管理者使用的內部分析儀表板,該儀表板會從多個 API 讀取聊天空間活動、參與度和人口統計資料,並在網頁前端呈現這些資料。

Overview showing the application frontend, backend, and 4 external APIs - Google Chat, Google People, Employee API, Gemini API

圖 1: 範例應用程式:網頁 UI、服務層,以及外部 API。

技術堆疊為 TypeScript、NextJS 與 React。後端會讀取並串接來自 API 的資料。這個應用程式已經存在一段時間,但為了這些實驗,我使用 AI 從頭重新建置它。

目前幾乎沒有任何關於程式碼品質與可維護性的指南(例如 Markdown 檔案)提供給 AI,我想要觀察它在僅依賴感測器回饋的情況下,表現會如何。

所有感測器概覽

Overview of sensors: During coding session, after integration in the pipeline, repeatedly, and runtime feedback in production

圖 2: 感測器可運行的時機:初始開發階段、管線中、定期執行,以及生產環境的執行階段回饋。

以下是我在導入生產環境的過程中,所設置的感測器概覽。

開發階段

與代理同時持續運行的感測器,用以提供快速回饋。

  • 型別檢查器(運算式)
  • ESLint(運算式)
  • Semgrep,內部 AppSec 團隊指定的 SAST 工具(運算式)
  • dependency-cruiser,執行結構規則以檢查內部模組相依關係(運算式)
  • 測試套件結果(包含測試涵蓋率)(運算式 —— 雖然測試套件是由 AI 產生,因此屬於推論式)
  • 增量變異測試(運算式)
  • GitLeaks 作為 pre-commit hook 的一部分執行,我將其視為感測器,因為當代理嘗試提交時,它會提供回饋(運算式)

整合後 - 管線

相同的運算式感測器會在 CI 中再次執行。開發階段的感測器能在開發過程中提供早期回饋,而 CI 管線則會在乾淨的基礎設施與整合後確認結果。

定期執行

以較慢的頻率運行的感測器,用以偵測隨時間累積的偏移,而非即時發生的錯誤。

  • 安全性檢視,提示來自我們內部應用程式的 AppSec 檢查清單(推論式)
  • 資料處理檢視,提示描述「使用者名稱絕對不應傳送至網頁前端」等內容(推論式)
  • 相依性新鮮度報告,會先執行腳本取得函式庫相依性的年齡與活動度,然後由 AI 產生包含升級、棄用等建議的報告(運算式與推論式)
  • 模組化與耦合度檢視(運算式與推論式)

有了這些背景,讓我們深入探討第一類感測器。

基礎環境與模型

在整個應用程式建置過程中,我混合使用了 Cursor、Claude Code 與 OpenCode(依使用頻率排序)。預設模型通常是 Claude Sonnet,部分規劃與分析任務使用 Claude Opus,而實作任務則經常使用 Cursor 的 composer-2 模型。

靜態程式碼分析:基本程式碼檢查

我將從使用 ESLint 於此應用程式的經驗開始分享。像 ESLint 這類基本的程式碼檢查工具,主要針對單一檔案與函式的可維護性風險。

針對 AI 常見缺點的規則

根據我的經驗,靜態程式碼分析最容易捕捉的 AI 失敗模式包括

  • 函式的最大參數數量
  • 檔案長度
  • 函式長度
  • 循環複雜度

然而,這些規則在 ESLint 的預設預設集(preset)中甚至並未啟用,我必須先自行設定其上限。希望靜態分析工具未來能演進,提供更適合與 AI 搭配使用的預設集。經過一些研究發現,有些人已經開始發布針對已知代理失敗模式的 ESLint 插件規則集,例如 Factory 推出的這個插件,其中包含要求測試檔案或結構化記錄等規則。

自我修正的引導

感測器的目的是提供代理回饋,讓它能自我修正。理想上,我們希望在自我修正時提供額外上下文 —— 這是一種良性的提示注入。為此,我建立了一個自訂的 ESLint 格式化程式來覆寫部分預設訊息 —— 當然,這也是在 AI 的協助下完成的。

以下是針對 no-explicit-any 警告的引導範例。

We want things to be typed to make it easier to avoid errors, especially for key concepts.
But we also want to avoid cluttering our codebase with unnecessary types. Make a judgment
call about this. If you choose to not introduce a type, suppress it with:
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- (give reason why)`,

管理警告 —— 現在更可行?

靜態程式碼分析已經存在很長一段時間,然而即使團隊已經設置好,卻往往無法持續使用。其中一個原因是管理負擔。有效使用這類分析需要團隊維持「乾淨的環境」,否則指標就會變成雜訊。特別是像 no-explicit-any 這樣的警告,因為你並不總是想要修復它 —— 這取決於情境。而逐一抑制這些警告一直以來都感覺很繁瑣,而且會在程式碼中產生雜訊。

有了程式碼代理,我們現在可能有機會建立乾淨的基準。在上述引導文字中,代理被要求做出判斷,並允許在程式碼中抑制警告。這讓抑制動作變得可管理、可見且可檢視。

對於閾值,例如最大行數或允許的最大循環複雜度,我會在 lint 訊息中告訴代理,如果它認為某個特定情況下重構是不必要或不可能的,可以略微提高閾值。這並不會永久抑制該閾值,只是提高它,因此如果未來情況變得更糟,規則仍會再次觸發。這樣既保留了約束,又避免了「抑制或遵守」的二元選擇。

觀察結果

  • 查看 AI 建立的例外(抑制警告、提高閾值)是我進行程式碼檢視的好起點。
  • AI 經常決定提高循環複雜度閾值,但當我進一步提示時,它會提出良好的重構建議。這是唯一會這樣做的類別,而我後來發現我沒有為此設置自我修正引導,因此沒有明確指示「提高閾值應該是絕對例外」。這顯示自訂的 lint 訊息確實會產生相當大的影響。
  • 有時我希望在程式碼的不同部分對規則採取不同的處理方式。以 no-console 為例,它會在代理使用 console.log 時發出警告。在後端,我希望它改用 logger 元件;在前端,我可能完全不希望使用直接記錄,或者至少需要使用不同的記錄元件。這再次展示了自我修正引導的力量,以及 AI 如何協助進行語義判斷與分析警告的管理。
  • 我觀察了規則之間的權衡範例。我目前看到的唯一例子是由 max-linesmax-lines-per-function 規則產生的。我發現 AI 因為這些感測器回饋而進行了相當多有用的重構,將程式碼拆解成更小的函式與元件。然而,在 React 前端,我注意到一個令人擔憂的趨勢:因為要透過越來越小的元件鏈傳遞數值,導致元件擁有越來越多的屬性。我目前還沒有足夠的觀察,來判斷 AI 在這類權衡上能做出多一致的決策。

主要收穫

總體而言,我對靜態分析能涵蓋的範圍感到相當驚訝。我必須多次提醒自己,為什麼它在過去一直被低度使用,以及現在有什麼改變:成本效益平衡。成本降低是因為使用 AI 建立自訂腳本與規則變得便宜許多。而效益也提升了:分析結果能幫助我快速掌握許多衛生因素,這些因素即使是我自己撰寫程式碼時也不會經常發生,因此可以先排除常見的 AI 錯誤。

然而,我不禁懷疑這是否也會導致錯誤的安全感與品質的幻覺。畢竟,lint 工具過去較少被使用的另一個原因是它們有其限制,我們一直謹慎地避免將它們視為簡化的品質指標。靜態分析無法捕捉許多更具語義層面的品質問題,AI 是否能與這些工具有效合作來填補這個缺口,還有待觀察。此外,每次啟用新的規則集時,我都會在程式碼中發現新的所謂問題。這些問題總是混雜著不相關與真正重要的項目。因此我擔心代理會面臨回饋過載,導致它陷入過度工程化的重構循環。

靜態程式碼分析:相依性規則

基本程式碼檢查主要聚焦於檔案或函式內部的品質與複雜度。接下來,我開始探索能針對跨越檔案與模組邊界的可維護性問題提供回饋的感測器。這類分析工具在歷史上甚至比基本程式碼檢查更少被使用。

為了了解這類感測器在幫助我們與 AI 維持良好模組化的潛力,我探索了三件事:

  • 相依性規則(確定式)
  • 耦合度分析(確定式與推論式)
  • 模組化檢視(推論式)

讓我們從相依性規則開始。我與代理合作,為我的應用程式設計了一個分層模組結構,大約在實作到一半時進行。我請它協助我撰寫 dependency-cruiser 規則來強制執行這些層級。

sensors-structure-chativity.png

圖 3: 分層模組結構與相依性規則

例如,其中一條規則強制規定 clients 資料夾中的程式碼不得匯入 services 資料夾中的任何內容:

{
  name: “clients-no-services”,
  comment:
    “API clients must not depend on the orchestration layer above them. “ + LAYERS,
  severity: “error”,
  from: { path: “^server/clients/”, pathNot: “/__tests__/” },
  to: { path: “^server/services/” },
},

與 ESLint 訊息相同,我也擴充了錯誤訊息,讓它成為自我修正的引導,重新說明整個分層概念:

ERROR  clients-no-services
  API clients must not depend on the orchestration layer above them. 
  [Layers: routes -> services -> clients + domain; Services orchestrate: fetch data via clients, compute via domain -- no I/O, no SDKs, no knowledge of data fetching.]

觀察結果

  • 如果沒有 AI,我無法這麼快速地設置這些規則。該工具的配置語法有很高的入門門檻,而 AI 幾乎完全吸收了這個成本。
  • 代理在規則引入後違反了幾次,然後根據 dependency-cruiser 的回饋進行自我修正,因此它確實有助於維持我的資料夾概念。
  • 我還使用相同的方法,在前端引入了 React hooks 應如何結構的慣例。
  • 我必須想辦法捕捉 AI 在此結構之外建立新資料夾的情況,方法是建立一條規則,要求每個新檔案都必須位於預先定義的資料夾結構中。

主要收穫

當我引入這些規則時,程式碼按資料夾結構化的方式已經變得有些隨意。我可以看到這些規則如何幫助代理清理現況,然後繼續強制執行這些層級。因此,我發現這是描述 Markdown 指南中程式碼結構的相當有用的替代方案。然而,這類工具僅限於可透過 import、檔案名稱與資料夾結構表達的內容。

靜態程式碼分析:耦合度資料

接下來,我實驗了從程式碼庫中提取典型的耦合度指標,也就是每個檔案的輸入與輸出 import 與呼叫數量。

我沒有使用任何現有工具,而是請程式碼代理撰寫一個應用程式,透過 TypeScript 編譯器產生這些指標,讓我能在實驗中保有最大的彈性。我讓它加入兩個介面:一個網頁介面,包含各種視覺化圖表供我自己使用;以及一個 CLI,能將這些指標提供給程式碼代理。

sensors-coupling-dashboards.png

圖 4: 耦合度指標:供人類使用的視覺化圖表,以及供代理使用的 CLI。

供人類使用

這些視覺化圖表大多是既有的概念,例如相依性結構矩陣(DSM)。我發現它們很難解讀,雖然它們是 vibe coded 且確實可以改進,但我認為這更多與資料的本質有關。這是相當詳細的資料,需要大量上下文與經驗才能解讀,並對應到更高層級的良好實務。因此,我覺得這類工具在檢視由 AI 變更的程式碼庫時,仍然無法有效降低人類的認知負擔。

供 AI 使用

我給代理存取這個自訂 CLI(coupling-analyser)的權限,並要求它根據資料建立報告,包含改善關鍵問題的建議。

以下是該提示的部分內容 —— 我主要重現這段文字,是為了說明我實際上並沒有給它太多關於何謂良好或不良模組化的引導,我主要是委託模型自行判斷:

Produce a markdown report on modularity and coupling quality for the target TypeScript codebase, grounded in actual CLI output from npx coupling-analyser, not guesswork from static browsing alone.

Gather evidence (run the CLI)

Execute the CLI and capture stdout. Use the report subcommands—combine as useful for the question: …

Write the markdown report

Use clear headings. Prefer concrete module IDs / paths and numbers quoted or paraphrased from CLI output.

Suggested sections:

  1. Context — What was analyzed

  2. Executive summary — 2–5 bullets: overall modularity posture, top 1–3 systemic issues.

  3. Findings from the tool — Summarize hotspots, top risks, notable cycles or mutual dependencies, and behavioural highlights as reported by the CLI.

  4. Interpretation (modularity lens) — Tie metrics to software design: cohesion vs. spread of change, stability vs. dependency direction, fan-in/fan-out intuition, cycle impact.

  5. Deep dives for each high and critical issue

  • What it is — Module(s), role in the system, dependency neighbours (from CLI + minimal code peek if needed).
  • Responsibilities today …
  • Why it hurts …
  • Design options (2+ where reasonable) …
  • Why the new design is better — Fewer cycles, clearer dependency direction, smaller surfaces, test seams, align with likely change vectors.
  • Future change risk — How each option reduces regression risk and makes safe evolution cheaper (concrete scenarios: “adding X”, “swapping Y”, “shipping Z independently”).

這個由 LLM 引導的分析,實際上指向了與我透過視覺化圖表發現相同的耦合熱點,只是格式更容易消化。而且要求 LLM 將其分析建立在確定式工具的結果上,讓我更有信心,也可能比代理自行掃描整個程式碼庫來尋找耦合問題更省時省 token。

觀察結果

LLM 根據這些資料找到的結果相當平淡(我使用的是 Claude Opus 4.7):

  • 它指出其中一個最大的問題是一個初始化所有必要元件的 factory,但我引入這個 factory 的目的是讓它扮演輕量級的相依性注入框架。
  • 另一個問題是前端與後端之間共享的 zod schema,被 LLM 稱為「god module」。然而,這是一種常見的模式,用來建立前端與後端之間的明確合約,而且當前端與後端一起演進,甚至位於同一個 repo(如我的情況)時,這並不是什麼大問題。
  • 當合法的模式被視為高耦合樞紐時,未來分析中必須有辦法抑制這些,否則會產生更多雜訊。
  • 有一個比較有趣的發現:domain 資料夾中的 index.ts 檔案不加區分地暴露了 ./domain 中的所有檔案,並被許多地方匯入。雖然這也是一種建立層級明確合約的常見模式,但它確實有利有弊,至少值得調查它是否適合這個程式碼庫。

主要收穫

上述例子顯示,即使比基本程式碼檢查更甚,並沒有明確的定義,而是取決於是否適當。而什麼樣的耦合是適當的,取決於許多上下文,而不僅僅是程式碼庫的原始呼叫與 import 圖形。因此,根據這個小型實驗,我認為這類耦合資料單獨對 AI 來說並不實用。

我能想像這個資料更實用的用途,是在程式碼檢視的風險分類階段。當我檢視 AI 做出的程式碼變更時,知道被變更檔案的影響範圍似乎很有用,這樣我就能在例如變更具有 10 個以上呼叫者的檔案時,給予更多關注。或者,AI 檢視代理可以使用這些資料來決定要花費 token 的優先順序。

靜態程式碼分析:AI 模組化檢視

耦合度資料實驗結果平淡的原因可能有幾個:

  • 我的分析提示不夠具體
  • 耦合度資料對 AI 來說不實用
  • 耦合度資料太淺顯,缺乏完整程式碼的上下文

因此,我最後採取完全推論式的方法,使用 Vlad Khononov 的「Modularity Skills」 來分析程式碼庫設計並找出模組化問題。這個方法非常有效!它提供了許多有趣的重構建議,這些建議明顯能降低未來變更的風險。我第二次執行這些 skills,並讓它們存取我的耦合度分析 CLI。AI 主要在資料中找到確認,但沒有額外發現。相反地,它指出了許多 CLI 遺漏的項目。值得注意的是,第二次分析(沒有第一次的上下文)發現了第一次分析沒有發現的另一個問題。這提醒我們,當事情重要時,通常值得多次執行基於 LLM 的分析,以獲得更完整的圖像。

觀察結果

以下是結果的一些重點(使用的模型是 Claude Opus 4.7,與耦合度分析相同):

  • 重複的路由程式碼 —— 我的三個後端端點各自有自己的路由檔案,而每個路由實作幾乎都相同。因此,當我想對後端 API 的一般原則進行變更時(例如引入 request ID,或變更錯誤處理或記錄方式),我就必須在多個檔案中進行。我才剛引入第三個端點,所以我認為還沒有進行抽象是合理的。但根據我的經驗,AI 代理通常不會在重複第三或第四次程式碼時,主動進行重構,它們很樂意複製貼上。
  • 呼叫後端的不一致性 —— 或者說,這是另一種語義重複的形式。應用程式中有 3 個頁面需要使用相同的參數集(選定的聊天空間,以及要分析的日期範圍)呼叫後端。其中兩個頁面使用相同的 hook 與一般方法來執行此操作,但當 AI 引入第三個頁面時,它偏離了這個方法,並以自己的方式重新實作了類似的行為。這可能導致錯誤處理的不一致,或者當後端 API 原則變更時,又需要變更多個檔案。
  • 核心引數的低效處理 —— 如前所述,應用程式中的所有頁面都會將聊天空間 ID 與日期範圍傳遞給後端。我已經注意到,當我變更使用者指定日期範圍的方式時,AI 必須為此變更修改大量檔案 —— 超過 40 個!所以我已經意識到這裡有問題,而分析確認了這一點:「問題:請求參數在每一層級重複」。建議是引入一個物件來封裝所有這些參數。AI 實際上已經以某種方式這樣做了 —— 但從未完全遵循該物件的使用,因此變成了一團不一致的混亂。
  • 職責位置錯誤 —— 檢視發現一些驗證程式碼位於我們的 factory 中,而該 factory 應該只負責連接我們的模組。它在使用者未驗證時實作了回退到模擬資料的機制。這種意外的位置會造成新增路由時可能遺漏的風險。
  • 對可接受的高 import 數量「樞紐」的更好解讀 —— 還記得我之前的耦合度分析發現的「god classes」嗎?模組化 skills 也注意到了這些,但在這兩個案例中,它都很好地指出它們在這個應用程式的上下文中是有目的的。我假設這要麼是因為這些 skills 的提示很好,要麼是因為這個分析實際上讀取了程式碼中的內容,而我要求另一個分析只依賴耦合度資料。

主要收穫

  • dependency-cruiser 這樣的相依性解析器可以作為有效的即時感測器,來強制執行一些基本的資料夾結構與相依性方向,但它們的能力有限。
  • AI 模組化檢視是「垃圾收集」的很好範例,而且在給予強大的提示時表現相當不錯。將其建立在實際的耦合度資料上似乎沒有太大差異。如果能找到方法將此應用於 commit 中的變更檔案,以便更早進入管線,會很好,但我目前還沒有探索這一點。
  • 我在建置大部分程式碼庫後才執行模組化檢視 —— 而且它有一些相當令人擔憂且非常合理的發現,這些發現會增加未來的風險。這顯示如果沒有人類檢視與耦合度專業知識,而且沒有這些額外的 AI 檢視,代理絕對會累積 無意的技術債務

總體而言,程式碼庫設計與模組化似乎是一個運算式感測器無法提供太多幫助的領域,需要 AI 來加入語義解讀並考量權衡。

測試套件作為回歸感測器

測試有許多目的 —— 它們幫助我們思考並推動設計、記錄應用程式期望的行為(它們是最終的規格!),以及幫助我們偵測回歸,也就是告訴我們變更是否破壞了既有的功能。有效的回歸測試在程式碼庫的可維護性中扮演重要角色,它們讓變更變得更安全。因此,在可維護性感測器的背景下,本節討論的是測試套件作為回歸感測器的角色。

當既有的測試失敗時,我們必須問自己一個問題:「我是意外破壞了某些東西,所以需要變更我的實作?還是我是有意變更行為,所以測試必須改變以適應這個新規格?」失敗的測試給了 AI 機會去問這個問題。話雖如此,它不一定總是做出正確的決定!但好的測試套件能降低 AI 破壞期望既有行為的機率。

在我的聊天分析應用程式中,我讓代理隨時間撰寫所有測試,除了手動測試與關注測試涵蓋率之外,沒有太多監督。我想要一個完整的 AI 產生的測試套件,以便事後分析其回歸有效性。

讓 AI 在沒有檢視的情況下產生測試,有兩個主要風險:

  • 涵蓋率不是測試有效性的充分指標
  • 測試可能正在測試錯誤的行為 —— 這比檢查測試有效性困難得多,這是另一個話題。本文僅關注測試有效性,也就是假設我們的程式碼實作了期望的行為,我們是否有能捕捉破壞程式碼的測試。

我們的工具箱中有什麼?

  • 涵蓋率($) —— 追蹤哪些部分的程式碼被測試執行,顯示哪些部分的程式碼對測試是可見或不可見。
  • 屬性導向測試($) —— 透過從定義的屬性而非手動製作範例產生許多輸入組合,來找出遺漏的邏輯測試案例。
  • 模糊測試($$) —— 透過對系統丟出意外或格式錯誤的輸入,來找出輸入韌性遺漏的測試案例。
  • 變異測試($$) —— 透過引入小的程式碼變異並檢查測試套件是否能捕捉它們,來找出遺漏的斷言。

在我的應用程式中,我使用了涵蓋率與變異測試,因為屬性導向測試與模糊測試不太適合我的使用情境。

變異測試

以下是我程式碼庫中的一個小範例,用來說明變異測試如何幫助我們找出斷言中的缺口。代理在分析變異測試結果期間為我建立了這張圖表:

Mutation testing analysis diagram for mappers and related                        code

圖 5: 程式碼庫中的變異測試範例。

mappers.ts 檔案回報了 100% 的陳述式涵蓋率與 75% 的分支涵蓋率 —— 但結果發現它沒有單元測試,而 Stryker(我使用的變異測試工具)回報了 13 個存活者(也就是在 Stryker 的 13 個程式碼變異後,測試套件仍然是綠色的)。這種情況下的涵蓋率很高,是因為程式碼庫有一個大型的驗收測試最終呼叫了這些函式 —— 涵蓋率告訴我們某一行被執行了,但沒有告訴我們它的影響被驗證了。如果這個小小的 mappers 輔助函式 dvpToSchema 在未來被變更,它可能會破壞 UI 中資料圖表的顯示。

觀察結果

  • AI 在分析變異熱點並制定優先順序計劃來提高測試品質方面非常有幫助。
  • Stryker 會將結果寫入一個巨大的 JSON 檔案。為了幫助分析並避免意外塞滿上下文視窗,我產生了一個自訂腳本來幫助代理有效查詢 Stryker 的結果。這只是 AI 幫助我幫助 AI 的眾多範例之一。
"""Query a Stryker mutation-testing JSON report from the command line.

Usage:
python query_stryker.py <report.json>; <command> [options]  

Commands:
   summary Overall status totals, mutation scores, thresholds.
   files Per-file breakdown, default sorted by mutation score asc.
   hotspots Lines with the most survivors / no-coverage mutants.
   tests Test effectiveness: weak, unused, or top-killer tests.

Examples

# 1. Overall health — mutation score, status breakdown, threshold pass/fail
python ./query_stryker.py reports/mutation/mutation.json summary

# 2. Worst files first, with an action hint (strengthen assertions vs add tests)
python ./query_stryker.py reports/mutation/mutation.json files --top 10 -v

# 3. Same, but only for files you've changed in git (auto-detects the repo)
python ./query_stryker.py reports/mutation/mutation.json files --changed -v

# 4. Zoom into one file: every (line, actionable counts, sample mutators)
python ./query_stryker.py reports/mutation/mutation.json hotspots --file server/services/ai-summaries.ts --top 30

"""

主要收穫

目前似乎有一個趨勢是朝向更多端到端風格的驗收測試。如開頭所述,AI 在產生測試方面已經變得非常擅長,因此讓開發者直接讓 AI 產生大量測試而無需太多檢視已經變得很常見。特別是檢視單元測試可能非常繁瑣。我不是說完全不看它們是好事 —— 但我承認現實是認為人類檢視所有測試是可持續的,這是不切實際的,而且認為人們真的會這樣做也是不切實際的。因此,當我們尋找 AI 輔助開發未來的適當測試金字塔/冰淇淋甜筒/鬆餅形狀時,像 approved scenarios 這樣的技術正變得流行。如上所示,驗收測試會增加涵蓋率,但通常斷言不多,這給了我們測試有效性的錯誤安全感 —— 變異測試幫助我們監控這個缺口。

變異測試當然有一個實務限制:它相當耗費資源。在我的設置中,我沒有持續運行它(不像我的一些其他感測器),而是手動觸發增量執行。

結論與開放性問題

運算式感測器 在檔案與函式層級給我最深刻的印象。跨檔案的問題如模組化與耦合度則是另一回事,原始資料本身非常嘈雜,如果沒有 LLM 的語義解讀(也就是推論式感測器),就不太有用。但我對使用良好提示能獲得的輸出與建議印象深刻,也對以不同方式呈現這些資訊以適應不同經驗水平的潛力印象深刻。

在我的實驗中我沒有看到,但我懷疑可能會成為更多問題的是感測器之間的衝突max-linesmax-lines-per-function 規則顯示出一些緊張跡象,將函式重構得越來越小,反而將複雜度推入元件屬性鏈中。更多類似的權衡可能潛藏其中,隨著時間推移觀察它是否以及如何成為問題,會很有趣。

在這個應用程式中,我完全沒有使用指南,目的是更純粹地觀察感測器的效果。我很好奇指南與感測器的平衡將如何演進。一旦我們對一組感測器感到有信心,我們可以刪除哪些指南?感測器是否讓使用較弱的模型變得更現實?我們如何讓指南與感測器保持一致,以及我們是否能找到某種方式將它們綁定在一起,讓它們更容易維護?

在回歸測試領域,我的眼睛真的被打開了,了解到當我們決定將大部分測試交給 AI 時,變異測試變得多麼關鍵…… 我想再次強調,關於測試正確性的另一場對話還有待進行!

雖然其中一些感測器確實增加了我對結果品質的信任,但它們並不是讓人類完全退出迴路的魔法解決方案。但我確實體驗到,無論是運算式還是推論式感測器作為我的夥伴,都改善了我的檢視體驗與信任水平。