
大家好,我來了🙂。
我們團隊,維護著一個有5年歷史的史詩級中後台專案😖。在這座屎山裡,有一個叫handleOrderSubmit.js的檔案。
可以下載瞧一瞧 有多屎👉 handleOrderSubmit.js
它是一個長達500多行的React useEffect 鉤子函數(是的,你沒看錯,一個useEffect)。
它混合了訂單資料的本地校驗、價格計算、優惠券應用、API請求、全域狀態更新、以及錯誤彈窗處理... 所有的邏輯,都塞在一個函數裡,用if/else和try/catch層層嵌套。
沒人敢動它😖。
每次產品經理提一個小需求,比如在提交訂單時,增加一種新的優惠券類型,我們整個團隊的表情都像被雷劈了。因為我們知道,改這個函數,要麼加班一週,要麼就等著P0級事故。
上週,產品經理要求我們在這個函數裡,加入一個全新的風控邏輯。
我評估了一下,手動重構,至少需要一個資深工程師一週的時間,而且風險極大。
我受夠了。我決定,把這個燙手的任務,扔給我的實習生——AI(我用的是GPT-5 mini,窮😂)。
這篇文章,就是我人機協作,啃下這塊硬骨頭的完整回顧,大家繼續看。
我犯的第一個錯誤,是直接把500行程式碼貼給AI,然後說:幫我重構這段程式碼。
AI很聽話,它給我的,是一段看起來更整潔的程式碼——它把if/else換成了switch,提了幾個變數... 這不叫重構,這叫重新排版,毫無意義。
我很快意識到:AI是一個能力超強、但沒有靈魂的執行者。我,作為開發者,必須給它提供一個清晰的方案。
於是,我制定了一個五步重構法。
我的核心思想是:AI負責執行,我負責決策。 我要像一個指揮家一樣,一步一步地引導AI,把這500行的程式碼,拆解成高內聚、低耦合的模組。
我不能上來就讓AI改。我得先確認,它和我對這段程式碼的理解,在一個頻道上。
Prompt:
你是一個資深的React架構師。請分析下面這段500行的
useEffect程式碼。
- 告訴我它做了幾件主要的事情?(職責分析)
- 找出所有的副作用(比如API請求、
localStorage操作、全域狀態更新)。- 找出所有的純邏輯(比如資料校驗、價格計算)。
- 評價它的可維護性和可測試性。

GPT的回答,給了我一個驚喜。它清晰地列出了:
api.post(...), setLoading(true), showToast(...)...validateForm(...), calculateTotalPrice(...)...很好,AI看懂了!我們就可以開始了😁。
這是最關鍵的一步。我要把計算和動作分開。
Prompt:
非常好。現在,請你只針對純邏輯部分(表單校驗、價格計算)進行重構。
- 把這些邏輯,從原函數中提取出來,變成獨立的、可導出的純函數。
- 這些函數必須是純的:不能有任何副作用(不能調用
api或setLoading)。- 使用TypeScript,為這些新函數的入參和返回值,提供清晰的類型定義。

AI立刻唰唰唰地給了我幾個檔案:
validate.ts:
export function validateOrder(formData: OrderForm): string | null {
if (!formData.user) return '用戶信息不能為空';
if (formData.items.length === 0) return '商品不能為空';
// ... 10 more rules
return null;
}
calculator.ts:
export function calculateTotalPrice(items: Item[], coupon: Coupon): number {
let total = items.reduce((sum, item) => sum + item.price * item.quantity, 0);
if (coupon.type === 'PERCENT') {
total *= (1 - coupon.value / 100);
}
// ... 20 more rules
return total;
}
我怎麼知道AI提煉的邏輯,是對的還是錯的?
答案:讓它自己寫單元測試來證明。
Prompt:
你現在是一個QA工程師。請使用
Vitest,為你剛才提取的validateOrder和calculateTotalPrice這兩個函數,編寫全面的單元測試用例。
必須覆蓋所有邊界情況,包括正常、異常、和邊緣值。
AI再次給了我驚喜。它生成的測試用例,比我手寫的還要全:
// calculator.test.ts
import { describe, it, expect } from 'vitest';
import { calculateTotalPrice } from './calculator';
describe('calculateTotalPrice', () => {
it('should return 0 for empty cart', () => {
expect(calculateTotalPrice([], null)).toBe(0);
});
it('should apply percent coupon', () => {
const items = [{ price: 100, quantity: 1 }];
const coupon = { type: 'PERCENT', value: 10 };
expect(calculateTotalPrice(items, coupon)).toBe(90);
});
// ... 省略更多
});
我把這些測試用例跑了一遍,全部通過。我現在信心大增😁。
現在,純邏輯已經被分離並驗證了。原來的500行屎山,只剩下副作用和流程控制程式碼了。是時候重寫它了。
Prompt:
幹得漂亮。現在,我們來重構那個原始的
useEffect函數。
- 它現在唯一的職責是協調。
- 調用我們剛才創建的
validateOrder和calculateTotalPrice純函數。- 把所有的副作用(API請求、
setLoading、showToast)清晰地編排起來。- 使用
async/await,讓異步流程更清晰,用try/catch處理錯誤。
這次,AI給我的,是一個只有30行左右的、清晰的流程程式碼:
// 重構後的 useEffect
useEffect(() => {
const submitOrder = async () => {
setLoading(true);
try {
// 1. 協調:驗證 (純)
const errorMsg = validateOrder(formData);
if (errorMsg) {
showToast(errorMsg);
return;
}
// 2. 協調:計算 (純)
const totalPrice = calculateTotalPrice(formData.items, formData.coupon);
// 3. 協調:副作用(不純)
const result = await api.post('/order/submit', { ...formData, totalPrice });
// 4. 協調:響應(不純)
if (result.code === 200) {
showToast('訂單提交成功!');
router.push('/success');
} else {
showToast(result.message);
}
} catch (err) {
showToast(err.message);
} finally {
setLoading(false);
}
};
if (isSubmitting) { // 假設一個觸發條件
submitOrder();
setIsSubmitting(false);
}
}, [isSubmitting, formData /* ...其他依賴 */]);
別忘了,我重構的目的,是為了加風控這個新功能。
Prompt:
最一步。請在API請求之前,加入一個風控檢查的邏輯(調用
riskControl.check(...))。這是一個異步函數,如果檢查不通過,它會拋出一個錯誤。
AI在第2步和第3步之間,加了幾行程式碼,完美收工。
這次重構,我總共花了大概5個小時,而不是原計劃的一週。
總覺得 AI 不會淘汰會寫程式碼的工程師。
只會降維打擊那些只會堆砌程式碼的工程師。
那段500行的屎山,在過去,是我的噩夢;現在,有了AI的幫助,它變成了我的靶場。
這種感覺,真爽🙌。