上週三下午,我接手了一個讓我倒吸一口涼氣的代碼庫。同事離職前留下的這個JavaScript文件有1200多行,函數長得能滾動三屏,變量名像是用隨機字符生成的。產品經理説需要加個簡單功能——根據用户類型顯示不同的訂單狀態。我看了兩小時,愣是沒搞清楚該在哪改。

這就是那種典型的“爛代碼”:能跑,但沒人敢動。

初探代碼沼澤
文件名叫 orderProcessing.js,打開後的第一印象是這樣的:

function proc(o) {

let a = [];

for (let i = 0; i < o.length; i++) {

if (o[i].s === 'pd') {

if (o[i].amt > 100) {

if (o[i].uType === 'vip') {

// ... 

}

}

}

}

// 後面還有800行類似代碼

}


變量名全是單字母,邏輯嵌套深得能挖到地心,重複代碼隨處可見。更糟糕的是,業務邏輯和數據處理、UI更新全攪在一起。

第一步:用Cursor理解這團亂麻
我沒有直接開始重寫,而是先讓Cursor幫我理解代碼在做什麼。

技巧一:讓AI解釋代碼塊我選中了一個150行的函數,按下Cmd+I(Mac)調出Chat界面,問:“這個函數到底在做什麼?用簡單的話解釋。”

Cursor花了點時間分析,然後説:“這個函數似乎在做三件事:1)過濾出待處理訂單,2)計算折扣,3)格式化顯示數據。但都混在一起了。”

這正是問題所在——一個函數做太多事情。

技巧二:識別代碼模式我又問:“找出這個文件中最常見的代碼壞味道。”

Cursor列出了:

魔法數字(到處出現的0.1、100等)

重複的條件判斷邏輯

過長的函數(超過100行的有8個)

混合的抽象層次(業務邏輯直接操作DOM)

有了這個分析,我知道該從哪裏下手了。實戰重構:從最臭的代碼開始

階段一:提取魔法數字

原代碼中到處都是這樣的片段:if (order.amount > 100) {

discount = order.amount * 0.2;

} else if (order.amount > 50) {

discount = order.amount * 0.1;

}

我選中這類代碼,讓Cursor重構: “將這些魔法數字提取為有意義的常量”Cursor生成:
const DISCOUNT_THRESHOLD_PREMIUM = 100;

const DISCOUNT_THRESHOLD_STANDARD = 50;

const PREMIUM_DISCOUNT_RATE = 0.2;

const STANDARD_DISCOUNT_RATE = 0.1;if (order.amount > DISCOUNT_THRESHOLD_PREMIUM) {

discount = order.amount * PREMIUM_DISCOUNT_RATE;

} else if (order.amount > DISCOUNT_THRESHOLD_STANDARD) {

discount = order.amount * STANDARD_DISCOUNT_RATE;

}


階段二:拆解巨無霸函數
最大的那個函數有300行。我決定分步驟重構。

首先,識別可提取的部分我問Cursor:“這個函數中哪些部分可以獨立成單獨的函數?”

Cursor指出了幾個明顯可以抽離的邏輯:

價格計算邏輯(第45-90行)
狀態判斷邏輯(第120-180行)
數據格式化邏輯(第200-280行)
然後,讓Cursor幫我提取我選中價格計算部分(45-90行),輸入: “將這部分提取為一個獨立函數,專注於價格計算,考慮所有邊界情況”

Cursor不僅提取了函數,還給了個好名字:

function calculateOrderPrice(order, userType) {

// 清晰的邏輯,包含註釋説明

const basePrice = order.amount;

const discount = calculateDiscount(basePrice, userType);

const tax = calculateTax(basePrice - discount, order.state);

return basePrice - discount + tax;

}

神奇的是,它還發現了一個原代碼中的bug:某個特定情況下税被計算了兩次。階段三:處理條件嵌套地獄

原代碼中的條件嵌套讓人頭暈:if (user.type === 'vip') {

if (order.status === 'pending') {

if (order.amount > 100) {

if (order.paymentMethod === 'credit_card') {

// 實際邏輯

}

}

}

}


我讓Cursor用策略模式重構: “使用策略模式重構這個多層條件判斷,讓不同用户類型的處理邏輯分離”

結果出乎意料地好:

const userHandlers = {

vip: new VipOrderHandler(),

standard: new StandardOrderHandler(),

guest: new GuestOrderHandler()

};function processOrder(order, user) {

const handler = userHandlers[user.type] || userHandlers.guest;

return handler.handle(order);

}


遇到問題:Cursor不是總對
在重構一個複雜的數據轉換函數時,Cursor給出了一個有問題的建議。它試圖合併兩個相似的循環,但沒注意到它們有細微的副作用差異。

教訓:任何時候都要運行測試。我在重構前已經準備了幾個關鍵測試用例:

// 簡單的快照測試

test('重構前後結果一致', () => {

const originalResult = oldProcessOrders(testData);

const refactoredResult = newProcessOrders(testData);

expect(refactoredResult).toEqual(originalResult);

});


當Cursor的重構導致測試失敗時,我沒有直接接受,而是問: “為什麼這個重構會導致測試失敗?原邏輯中的微妙區別是什麼?”

Cursor重新分析後承認:“抱歉,我忽略了第一個循環會修改原數組,而第二個循環依賴這個修改。”

重構後的成果
經過兩天的重構(原本估計要一週),代碼有了明顯改善:

之前:

1個文件,1200行
函數平均長度:85行
最深嵌套:8層
重複代碼塊:約30處
之後:

6個文件,平均150行
函數平均長度:22行
最深嵌套:3層
重複代碼:基本消除
更重要的是,新加功能變得簡單。產品經理要的“根據用户類型顯示不同訂單狀態”功能,現在只需要:

// 以前:需要在多個地方修改條件判斷

// 現在:

import { getStatusDisplay } from './orderStatus';function displayOrderStatus(order, user) {

return getStatusDisplay(order, user.type);

}


學到的重構技巧
先理解,再動手用Cursor解釋代碼比自己摸索快得多。但永遠要結合自己的業務理解。

小步前進,頻繁測試每次重構不超過一個函數,立即運行測試。Cursor的“重構並解釋”功能很好用。

用好Cursor的代碼分析像“找出重複模式”、“識別壞味道”這類指令,能幫你發現肉眼忽略的問題。

不要完全依賴AICursor有時會過度設計。簡單的重複代碼提取它做得很好,但涉及複雜設計模式時,需要人工判斷是否合適。

命名是重構的關鍵Cursor能建議更好的變量名,但最終命名要符合團隊習慣。我經常這樣問:“給這個函數起個更清晰的名字,它負責驗證訂單並計算價格。”

最後的思考
重構爛代碼就像整理一個雜亂的倉庫。Cursor不是那個替你幹所有活的機器人,而是給你提供了一個好用的手推車、一些收納箱,還有一位隨時能問的倉儲專家。

最大的收穫不是把代碼變漂亮了,而是找回了修改代碼的勇氣。原來那種“改一行可能崩全局”的恐懼消失了,因為現在有了一個能快速理解代碼結構、指出潛在問題的助手。