生活分享
Claude Code|接手缺測試舊專案:先留住行為再重構
用小步變更拆出可測試模組。舊程式重複很多,不代表可以一口氣改寫後再看結果。本篇先記錄待辦統計的既有行為,補上能保護空資料、混合狀態及同名項目的測試,再分三個小差異整理模組。每一步都能說明保留了什麼,以及出問題時如何回復。
閱讀時間約 6 分鐘

進階 · CLI / Desktop / VS Code / JetBrains
舊程式重複很多,不代表可以一口氣改寫後再看結果。本篇先記錄待辦統計的既有行為,補上能保護空資料、混合狀態及同名項目的測試,再分三個小差異整理模組。每一步都能說明保留了什麼,以及出問題時如何回復。
先讀逐步重構入門Claude Code|接手舊專案與逐步重構建立基準、小步重構並防止舊功能回歸。接手舊專案時,第一個目標是建立可信的基準,再做小步重構。本篇用待辦網站練習:先找啟動方式與測試,再抽出一個計算統計的純函式,確認原有行為沒有改變。你會學會把既有問題、新增問題與尚未驗證項目分開記錄。閱讀全文及紅綠除錯實作Claude Code|真正走完一次重現、失敗測試與修正定位跨資料層及介面層的待辦狀態錯誤。點了第一筆待辦,卻改到另一筆,這種問題不能只靠一句「請修好」驗證。本篇從瀏覽器重現開始,寫出修正前會失敗的行為測試,再讓 Claude 做最小修改。最後保留同一個測試由紅轉綠的紀錄,以及相鄰情境沒有退步的證據。閱讀全文。下載第 86 篇材料,開啟 starter。需要 Git 和 Node.js 22;閱讀約 20 分鐘,實作約 45 分鐘。
先區分已知行為與理想規格
閱讀完整文字說明
接手缺測試舊專案:先留住行為再重構,以流程和文件圖形呈現教學重點。
材料的 stats.js 使用多次迴圈計算 total、completed、active,回傳固定形狀的物件。程式可以運作,但重複遍歷讓邏輯分散。這次重構目標是保持有效待辦資料的輸出,整理成一個容易測試的函式,不新增過濾、登入或儲存功能。
舊程式可能對不合法資料有奇怪行為,例如把非布林 completed 當成真假值。先記錄這是觀察到的實作,不直接把它當成正式規格。課程資料契約使用布林值;若真實專案需要改驗證規則,應另立變更與驗收,避免與結構整理混在一起。
node --test tests/model.test.mjs tests/stats.test.mjs
git status --short
下載包附了可供對照的統計測試,讀者也應自己讀過每個斷言。若不使用 Git,至少保存原始檔副本;使用 Git 時,先在獨立練習目錄建立乾淨基準,再逐步提交。不要在含其他未完成工作的目錄直接用全檔案回復命令。
建立特性測試,先保留輸出
測試應包含空陣列、全部未完成、全部已完成、混合狀態與同名不同 id。檢查 total 等於項目數,completed 與 active 的分組符合輸入,原始資料不被修改。這些是可觀察行為,不需要斷言程式一定跑了幾次 for 迴圈。
import test from 'node:test';
import assert from 'node:assert/strict';
import {countTodos} from '../stats.js';
test('統計保留空資料與混合狀態的契約',()=>{
assert.deepEqual(countTodos([]),{total:0,completed:0,active:0});
const items=[{id:'a',title:'同名',completed:false},{id:'b',title:'同名',completed:true}];
const before=structuredClone(items);
assert.deepEqual(countTodos(items),{total:2,completed:1,active:1});
assert.deepEqual(items,before);
});
先對舊版執行,預期通過。這與上一篇先寫失敗測試修 bug 不同:目前要保留正常行為,所以先取得穩定基準。若這時失敗,先查測試假設是否符合目前需求,不要在尚未釐清時開始重構。
真正缺測試的專案可以先從使用者最常走的路徑開始,不必一次補齊所有細節。選擇能保護本次改動的案例,記錄未覆蓋範圍。測試基準是幫助定位,不是宣告整個舊系統沒有任何缺陷。
第一個小差異:固定模組邊界
確認統計只接受資料並回傳數字,不直接操作 DOM 或讀取 localStorage。材料已把舊統計放在 stats.js,真實專案若仍混在畫面事件中,第一步只移出函式並保留相同呼叫方式,先不順手改命名、輸入格式或計算規則。
請 Claude 說明要移動的內容與保留的介面,完成後跑同一測試。檢查 diff,確認資料讀取和畫面渲染沒有被一起改寫。保存第一個回復點,記錄它只改模組位置與引用,不包含新功能。
整理 stats.js 的模組邊界,保持 countTodos(items) 的輸入與回傳形狀。
先讀測試,不新增功能,也不更改有效資料的語義。
每完成一個可獨立檢查的小差異,先執行測試並說明結果。
模組抽離後若出現 import 路徑錯誤,先修引用,而不是把原檔全部貼回去並宣稱已解決。這個失敗可以清楚歸因於第一步;如果同時換掉全部算法,就很難知道是路徑還是計算導致問題。
第二個小差異:合併重複計算
在不變更介面的前提下,將多次遍歷整理成一個累計流程。你可以採 reduce,也可以使用單一迴圈;本篇不把較短程式碼當成唯一正確答案。選擇團隊容易閱讀且測試能保護的形式,並說明為何仍保留相同結果。
export function countTodos(items) {
return items.reduce((count,item)=>({
total:count.total+1,
completed:count.completed+(item.completed?1:0),
active:count.active+(item.completed?0:1)
}),{total:0,completed:0,active:0});
}
重跑統計與核心測試,確認空陣列回傳零而不是拋錯。這個細節由 reduce 的初始值提供,不能因為一般混合資料通過就忽略空值。參考實作沒有修改輸入資料,測試也應明確檢查這個契約。
不要未量測就宣稱效能大幅提高。本課資料很小,主要成果是計算邏輯集中、介面清楚。若要討論效能,另設固定資料量與量測方法,避免把程式看起來更短當成速度證據。
第三個小差異:整理呼叫與文件
確認 app.js 或其他呼叫者仍以完整待辦清單計算統計,而不是意外改成目前篩選後的清單。兩者都可能得到合理數字,卻有不同產品語義。先讀需求,再決定畫面應顯示哪一種,不在重構中默默改掉。
若本次課程沒有把統計接入 UI,明確記錄資料模組已整理、畫面整合未做。需要練習完整串接時,再讓 UI 匯入 countTodos 並顯示 total、completed、active,使用新增、切換、刪除三種操作驗證數字更新。不要把只跑資料測試寫成畫面已完成。
更新 CLAUDE.md 或交接文件中的模組位置及測試命令,移除已失效的舊路徑。文件變更應與實際檔案一致;不是每段舊說明都需要保留在常駐規則,歷史決定可放到 decisions.md。
故障練習與回復
故意在第二步移除 reduce 的初始值,對空陣列重跑測試。預期失敗,且能定位到計算改動。恢復第二步的正確內容,再確認第一步的模組邊界仍保留;不必撤銷所有已驗證的工作。
使用 Git 時先查目前差異與提交,確認要回復的是哪一個小變更。未提交內容與已提交內容使用的方式不同,不能把 reset 或 restore 當成無條件的清理命令。最簡單的練習方式是對照保存的三個提交,逐一檢查並保留需要的成果。
| 變更步驟 | 應保持不變 | 驗證 |
|---|---|---|
| 模組邊界 | 函式介面及輸出 | 相同特性測試 |
| 計算整理 | 空值、混合狀態、來源資料 | 核心與統計測試 |
| 呼叫與文件 | 產品顯示語義 | 引用檢查、必要時瀏覽器 |
把重構拆成可獨立回復的步驟
第一次提交只增加行為測試,確認原版本也能通過。第二次才移動或整理實作,保留相同測試。第三次視需要改善命名與重複內容。這些步驟都能各自審查,若某一步出現回歸,可以縮小到該步驟而不必拆解整包變更。
本課提供的統計函式已獨立成小模組,目的是讓你直接比較舊寫法和新寫法。接手自己的專案時,函式可能仍混在 UI 裡,先找出資料輸入和輸出,再決定是否拆檔。不能僅因為範例放在獨立檔案,就斷言所有專案都必須使用相同結構。
整理後確認空陣列、全部完成與部分完成仍得到相同統計。若新需求要求改變統計意義,將它獨立成行為變更,更新需求與測試。把新功能和保持行為的整理分開描述,審查者才能知道哪一個差異是刻意改變。
遇到效能疑慮先用代表性資料量測,不以程式行數少或迴圈少推定速度更快。這個小練習以可讀性和行為一致為判準,沒有提供正式環境的效能提升證據。
保存重構前的基準提交,讓讀者可以重新執行相同測試比較行為。若沒有基準,事後很難分辨變更是整理程式還是改變既有需求。
完成判準與小練習
交付既有行為清單、三個可說明的小差異、每步測試紀錄及一個實際做過的回復案例。已知缺陷與本次保持的正常契約分開,不用把所有舊行為都視為理想需求。若只完成資料模組,報告就寫資料模組,避免擴大完成範圍。
小練習是新增「統計只顯示目前篩選結果」的需求,先說明它為何屬於產品行為變更,再另外建立測試與提交。接著可請專責審查代理Claude Code|讓 Subagent 提出可核對的審查發現設計專責代理的範圍、工具及回報格式。讓專責代理審查程式,可以分開檢查資料邏輯與畫面,但兩份回報不會自動變成兩次獨立驗證。本篇建立唯讀的 data-reviewer 與 ui-reviewer,要求每項發現都有位置、條件與影響,再由主工作階段重現、去重並駁回沒有依據的意見。閱讀全文檢查這個變更,並由你自己核對每項發現的證據。
回 Claude Code 教學總目錄Claude Code 完整教學目錄:從入門到自動化依平台、程度與功能找到需要的教學,從 96 篇文章與共用練習專案逐步完成操作。這個教學中心把 Claude Code 分成 96 個可以獨立閱讀的小題目,從桌面、CLI、網頁與手機開始,再學 MD 規則、常用指令、Skills、MCP 與自動化。你可以依推薦路線循序學習,也可以直接搜尋正在遇到的功能、命令或檔名。目錄依目前公開狀態顯示可閱讀文章。閱讀全文
同主題延伸閱讀
生活分享
Claude Code|建立第一個 mod:在 Claude Code 行程內數工具呼叫
寫一個三檔案的 mod,用驗證器與測試確認它掛上的事件。文件把 mod 定義成多了入口檔的 plugin:入口檔叫 hooks module,Claude Code 在事件發生時呼叫裡面的函式,函式可以觀察、改寫或接手事件。
生活分享
Claude Code|Git Worktree 平行工作
隔離多個任務的檔案與分支。Git Worktree 讓同一儲存庫擁有多個工作目錄,各自使用分支與檔案。本篇會把待辦篩選與文件整理分開,確認兩個 session 不會直接改到彼此的檔案,再把其中一個成果整合回主分支。你也會知道何時可以安全清理工作目錄。
生活分享
Claude Code|比較流程品質、用量與執行時間
以同一資料集比較兩種工作方法。比較兩種 Claude 工作方法時,不能只挑成功那一次,也不能只看第一個答案有多快。本篇用固定案例、原始紀錄和一致判準,比較品質、重試、等待與人工整合時間,最後寫出有樣本數與限制的報告,而不是保證某個方法一定省錢。
引用本文的文章
最新旅遊情報攻略

情報
2026 韓國楓葉預測:雪嶽山 10 月 20 日、首爾近郊 10 月底、內藏山與漢拏山 11 月上旬
韓國山林廳 2026 年 9 月 22 日公布的楓紅高峰預測:雪嶽山 10 月 20 日,春川、國立樹木園到首爾植物園落在 10 月 28 日到 11 月 2 日,內藏山 11 月 4 日、漢拏山 11 月 6 日,整體比最近 5 年晚約 0.8 天。整理各地楓樹與銀杏的預測日、首爾出發怎麼排,以及出發前去哪裡看即時楓況。2026 年 10 月查證。
- 季節活動
- 自然
- 觀景

攻略胡志明市
胡志明市到頭頓一日遊:白藤碼頭搭高速船、船票與班次,下船就是胡梅纜車與耶穌基督像
人在胡志明市挪一天去頭頓看海:市中心的白藤高速船碼頭搭船,航程 120 分鐘到頭頓的胡梅碼頭,平日成人 320,000 越南盾、週末 350,000,回程末班平日 15:00。下船就是胡梅纜車站,同一條路上有白宮,小山頂上是耶穌基督像。平日一天只有兩班船,整天要從末班船倒推著排。
- 交通
- 行程範例
- 海灘

攻略沖繩
沖繩不開車攻略:單軌只到浦添,美麗海水族館要坐兩個多小時的巴士,回那霸的最後一班直達車 17:22 就開走
不租車的沖繩怎麼移動:那霸市區靠沖繩都市單軌電車(ゆいレール),那霸機場站到終點てだこ浦西 19 站、17 公里、37 分鐘,一日券 1,000 日圓;美麗海水族館有那霸機場直達的高速巴士,單程 2,000 日圓起、官方時刻表上 2 小時上下,下車後還要走 10 分鐘;古宇利島要在今帰仁村役場轉車,當天來回光坐車就六個半小時;回程的最後一班直達車 17:22 就從記念公園前開走(2026 年 9 月查證)。
- 交通
- 行程範例
- 預算