# Vibe Coding 程式碼品質保障

> 如何確保 AI 生成的程式碼品質



你好，我是魚皮。

很多同學在用 AI 開發時，會有這樣的擔心：AI 生成的程式碼靠譜嗎？會不會有隱藏的 bug？

這個擔心是有道理的。AI 雖然能快速生成程式碼，但它不能保證程式碼的品質。作為開發者，你需要建立一套品質保障體系。

本文我就來分享一些實用的方法，幫你確保 AI 生成的程式碼品質。




## 一、什麼是好程式碼？

在講如何保障品質之前，我們先要明確什麼是好程式碼。




### 好程式碼的特徵

什麼樣的程式碼才算好程式碼？

這個問題看似簡單，但很多人說不清楚。其實，除了能運行之外，好程式碼最重要的是 **可讀性好**：程式碼清晰易懂、符合團隊開發規範，別人（包括未來的你）能快速理解。在此基礎上，還要 **可維護性強**，修改和擴展都很容易，不會牽一髮而動全身。

當然，這些都要建立在 **功能正確** 的前提下，程式碼能正確實現需求，沒有 Bug。同時，**性能要合理**，在可接受的時間內完成任務，不浪費資源。此外，程式碼還要 **安全可靠**，沒有安全漏洞、能處理異常情況。

![](https://pic.yupi.icu/1/goodcode%E5%A4%A7.jpeg)



### AI 生成程式碼的常見問題

那麼，AI 生成的程式碼通常會有哪些問題呢？

根據我的經驗，最常見的是 **過度複雜**，AI 為了實現功能，經常寫很多不必要的程式碼。另一個常見問題是 **缺少邊界處理**，AI 為了讓程式碼能快速運行，可能只考慮正常情況，忽略了空值、錯誤等特殊情況。

AI 生成的程式碼還經常出現 **重複程式碼** 的問題。特別是在前端開發中，如果你讓 AI 分別生成多個相似的頁面，它不會主動複用程式碼，而是為每個頁面生成獨立的程式碼。

舉個例子，假設你要做一個管理後台，有用戶列表頁、文章列表頁、評論列表頁。這三個頁面的佈局和功能都很相似：都是表格展示數據、都有搜索框、都有分頁。但如果你分 3 次讓 AI 生成，它會給你 3 套幾乎一樣的程式碼，只是數據字段不同。更好的做法是先讓 AI 生成一個通用的列表組件，然後用不同的配置來複用。這樣不僅程式碼量少，維護起來也容易。

有時候還會存在 **性能問題**，使用了低效的算法或數據結構。了解這些問題，你才能有針對性地檢查和改進。




### 建立品質標準

知道了什麼是好程式碼，接下來就要為你的項目建立明確的品質標準。

在程式碼規範方面，建議使用 ESLint 或 Prettier 統一程式碼風格，定義清晰的命名規則（比如變數用 camelCase 駝峰式寫法，常量用 UPPER_SNAKE_CASE 寫法），並規定好文件和文件夾的組織方式。

在功能標準上，要求所有功能都要有測試、要處理邊界情況、錯誤要有友好的提示。

性能方面，可以設定具體的指標，比如頁面加載時間不超過 3 秒，API 響應時間不超過 1 秒，數據量大時使用虛擬滾動等。

可以把這些標準寫在項目文檔裡，讓 AI 也知道。

💡 不過實際開發中還是要靈活，如果你只是單純開發個 Demo 類的小項目，幹就完了，不用考慮那麼多。




## 二、程式碼審查

程式碼審查（Code Review）是保障品質的第一道防線。



### 為什麼要審查 AI 程式碼？

有些同學覺得：AI 生成的程式碼能跑就行了，為什麼還要審查？

這個想法其實挺危險的。

首先，AI 不是完美的，它會犯錯，會生成有 Bug 的程式碼。更重要的是，AI 只知道技術，**不了解你的具體業務邏輯**，它生成的程式碼可能在技術上沒問題，但在業務上不合理。

另外，AI 可能只關注當前功能，不考慮未來的擴展性。今天能跑的程式碼，明天可能就成了技術債。而且，審查程式碼也是一個學習的機會，能幫你理解程式碼的工作原理，提升自己的技術水平。所以，審查 AI 程式碼是必不可少的，尤其是對於有程式設計基礎的同學。

![](https://pic.yupi.icu/1/whyreviewcode%E5%A4%A7.jpeg)




### 審查的重點

那麼，審查 AI 生成的程式碼時，應該重點關注哪些方面呢？




#### 1、功能正確性

最基本的要求是：程式碼能不能正確實現需求？

這聽起來簡單，但很容易被忽視。你需要運行程式碼，**測試所有功能**，嘗試各種輸入，包括正常的和異常的。

特別要注意邊界情況，比如空值、極大值、極小值等，這些往往是 Bug 的高發區。

舉個例子：

```typescript
// AI 生成的程式碼
function divide(a: number, b: number): number {
  return a / b;
}
```

想想看，這段程式碼有什麼問題呢？

答案是：沒有處理除數為 0 的情況。

```typescript
// 改進後：
function divide(a: number, b: number): number {
  if (b === 0) {
    throw new Error('除數不能為 0');
  }
  return a / b;
}
```



#### 2、程式碼可讀性

功能正確之後，接下來要看程式碼是否易讀。

記住，程式碼是給人看的，不只是給機器執行的。

檢查時要問自己幾個問題：

- 變數名是否清晰？
- 函數名是否表達了功能？
- 邏輯是否容易理解？
- 是否需要添加註釋？

如果你看程式碼時感到困惑，那別人也會困惑。

舉個例子：

```typescript
// 不好的命名
function f(x: number): number {
  return x * 2 + 1;
}

// 好的命名
function calculateDiscountedPrice(originalPrice: number): number {
  const discount = 0.2; // 8 折優惠
  return originalPrice * (1 - discount);
}
```



#### 3、錯誤處理

程式碼要能優雅地處理錯誤，不能一出錯就崩潰。

你要檢查 API 調用有沒有錯誤處理、用戶輸入有沒有驗證、異常情況有沒有友好的提示。很多 AI 生成的程式碼只考慮了正常流程，完全忽略了錯誤處理，這是很危險的。

舉個例子：

```typescript
// 不好的錯誤處理（根本沒做）
async function fetchUser(id: string) {
  const response = await fetch(`/api/users/${id}`);
  const user = await response.json();
  return user;
}

// 好的錯誤處理
async function fetchUser(id: string) {
  try {
    const response = await fetch(`/api/users/${id}`);
    
    if (!response.ok) {
      throw new Error(`獲取用戶失敗: ${response.statusText}`);
    }
    
    const user = await response.json();
    return { data: user, error: null };
  } catch (error) {
    console.error('獲取用戶出錯:', error);
    return { data: null, error: error.message };
  }
}
```



#### 4、性能問題

然後是性能問題。程式碼要高效，不能浪費資源。

可以看看有沒有不必要的循環、有沒有重複的計算、數據結構選擇是否合理。AI 有時候為了快速實現功能，會選擇最簡單但不是最高效的方案。

舉個例子：

```typescript
// 性能不好
function findUser(users: User[], id: string): User | undefined {
  // 每次都遍歷整個數組，O(n)
  return users.find(user => user.id === id);
}

// 性能更好
class UserManager {
  private userMap: Map<string, User>;
  
  constructor(users: User[]) {
    // 用 Map 存儲，查找是 O(1)
    this.userMap = new Map(users.map(u => [u.id, u]));
  }
  
  findUser(id: string): User | undefined {
    return this.userMap.get(id);
  }
}
```



#### 5、安全問題

對於商業項目來說，這點至關重要。程式碼要安全，不能有漏洞。

需要檢查有沒有 SQL 注入風險、有沒有 XSS 攻擊風險、敏感信息有沒有加密、API Key 有沒有暴露。AI 對安全的理解可能不夠深入，很容易留下安全隱患。

舉個 SQL 注入的例子。SQL 注入是指攻擊者通過在輸入中插入惡意的 SQL 程式碼，來執行非預期的數據庫操作。

比如下面這段程式碼是不安全的：

```typescript
// ❌ 不安全：直接拼接用戶輸入
const query = `SELECT * FROM users WHERE name = '${userName}'`;
```

假設用戶在登錄時輸入用戶名 `admin' OR '1'='1`，直接把這個輸入拼接到 SQL 語句裡，就會變成：

```sql
SELECT * FROM users WHERE name = 'admin' OR '1'='1'
```

這個查詢會返回所有用戶，因為 `'1'='1'` 永遠為真。攻擊者就能繞過驗證登錄任何賬戶。

正確的做法是使用參數化查詢：

```typescript
// ✅ 安全：使用參數化查詢
const query = 'SELECT * FROM users WHERE name = ?';
db.execute(query, [userName]);
```

參數化查詢會自動轉義特殊字符，防止 SQL 注入。

如果你對 Web 安全感興趣，可以利用魚皮 [免費的網絡安全自學網](https://github.com/liyupi/ceshiya) 來學習這些知識：

![](https://pic.yupi.icu/1/%E6%B5%8B%E8%AF%95%E9%B8%AD%E7%BD%91%E7%AB%99.png)



### 審查流程

可以按照下面的步驟，建立一個系統的審查流程：

1. 自己先看一遍：快速瀏覽程式碼，看有沒有明顯問題

2. 運行測試：測試所有功能，包括邊界情況

3. 逐行審查：仔細檢查每一行程式碼，思考是否有問題

4. 記錄問題：把發現的問題記下來

5. 要求 AI 改進：把問題反饋給 AI，讓它修復

6. 再次審查：確認修復後的程式碼沒有新問題

這個流程可能有點繁瑣，但能大大提高程式碼品質。

對於沒有程式設計基礎的朋友，如果自己看不懂程式碼，可以利用其他的 AI 大模型來幫忙審查。這是一個很實用的技巧：**用多個 AI 交叉驗證**。

比如用 Cursor（Claude）生成的程式碼，可以複製到 ChatGPT 或 Gemini，讓它們幫你審查一遍：

```markdown
請審查這段程式碼，找出潛在的問題，包括 bug、性能問題、安全隱患。
```

不同的 AI 有不同的視角和訓練數據，能互相補充，一個 AI 可能忽略的問題，另一個 AI 能發現。

我自己在做重要項目時，經常會讓 2 ~ 3 個不同的 AI 審查同一段程式碼，然後綜合它們的建議。這樣雖然多花了點時間，但能大大降低出錯的風險。特別是對於關鍵的業務邏輯、安全相關的程式碼、性能敏感的部分，多一層保障總是好的。



## 三、測試

測試是保障程式碼品質的關鍵手段。



### 為什麼要寫測試？

很多同學覺得寫測試浪費時間，但其實恰恰相反。測試能在開發階段就發現問題，而不是等到上線後用戶發現。有了測試，你可以放心地重構程式碼，不怕改壞。而且，測試程式碼本身就是很好的文檔，展示了如何使用你的函數或組件。

此外，雖然寫測試要花時間，但能省下更多調試時間。想想看，如果你每次改程式碼都要手動測試所有功能，那得花多少時間？有了自動化測試，運行一下就知道有沒有問題。

所以，寫測試是值得的。

![](https://pic.yupi.icu/1/testpk%E5%A4%A7.jpeg)



### 測試的類型

測試主要有 3 種類型。

- 單元測試：測試單個函數或組件，速度快，容易定位問題，覆蓋率要高。
- 集成測試：測試多個模塊的協作，確保模塊之間的接口正確，覆蓋主要流程。
- 端到端測試：模擬用戶的完整操作，測試整個系統，覆蓋關鍵場景。

對於 Vibe Coding 項目，我建議 **重點寫單元測試和集成測試**。端到端測試雖然也重要，但成本較高，可以只覆蓋最關鍵的場景。



### 讓 AI 幫你寫測試

如今絕大多數的測試程式碼已經不需要人工編寫了，你可以直接讓 AI 幫你生成測試程式碼。

````markdown
請為這個函數寫單元測試，覆蓋正常情況和邊界情況：
```typescript
function calculateTotal(items: CartItem[]): number {
  return items.reduce((sum, item) => sum + item.price * item.quantity, 0);
}
```
````

AI 會生成類似這樣的測試程式碼：

```typescript
import { describe, it, expect } from 'vitest';

describe('calculateTotal', () => {
  it('應該正確計算總價', () => {
    const items = [
      { price: 10, quantity: 2 },
      { price: 5, quantity: 3 }
    ];
    expect(calculateTotal(items)).toBe(35);
  });
  
  it('應該處理空數組', () => {
    expect(calculateTotal([])).toBe(0);
  });
  
  it('應該處理數量為 0 的情況', () => {
    const items = [{ price: 10, quantity: 0 }];
    expect(calculateTotal(items)).toBe(0);
  });
  
  it('應該處理小數', () => {
    const items = [{ price: 10.5, quantity: 2 }];
    expect(calculateTotal(items)).toBe(21);
  });
});
```

這段測試程式碼的作用是：用 `describe` 定義一個測試組（測試 calculateTotal 函數），然後用多個 `it` 定義具體的測試用例。每個測試用例都會調用函數並檢查結果是否符合預期。比如第一個測試檢查正常情況、第二個測試檢查空數組、第三個測試檢查數量為 0 的情況、第四個測試檢查小數。運行這些測試時，如果所有 `expect` 都通過，說明函數工作正常；如果有任何一個失敗，就說明程式碼有問題。

有了這些測試，你就能確保函數在各種情況下都能正常工作。



### 擴展知識 - 測試驅動開發（TDD）

你可以嘗試測試驅動開發（Test-Driven Development，簡稱 TDD）。這是一種 「先寫測試，再寫程式碼」 的開發方式。

聽起來很反直覺對吧？一般不都是先寫程式碼，再寫測試嗎？

但 TDD 的邏輯是：你先定義好函數應該如何工作（寫測試），然後讓 AI 根據測試來實現功能。這樣能確保程式碼從一開始就是符合需求的、可測試的。

具體流程是：

1. 先寫一個會失敗的測試（因為功能還沒實現）
2. 然後讓 AI 實現功能讓測試通過，運行測試確保所有測試都通過
3. 最後優化程式碼但保持測試通過

這樣一來，能避免寫出 「看起來能用但實際有問題」 的程式碼。




## 四、調試技巧進階

即使有了審查和測試，還是難免會遇到 Bug。這時候，你需要掌握調試技巧。



### 1、使用斷點調試

很多同學調試程式碼時只會用 `console.log`，也就是在程式碼裡加一行 `console.log(變數名)` 來打印變數的值，然後在瀏覽器控制台查看。

這個方法雖然簡單，但效率不高，而且調試完還要把這些 log 刪掉。

其實斷點調試要高效得多。在 VS Code 或 Cursor 中，你只需要在程式碼行號左邊點擊設置斷點，然後按 F5 開始調試。

![](https://pic.yupi.icu/1/image-20260105092822939.png)

程式碼會在斷點處暫停，這時你可以查看所有變數的值：

![](https://pic.yupi.icu/1/image-20260105092855154.png)

還可以單步執行程式碼，看看每一步發生了什麼。這比到處加 `console.log` 然後再刪掉要方便多了。



### 2、瀏覽器調試工具

前端開發時，瀏覽器的調試工具是你的好幫手。在瀏覽器中按 F12 就能打開開發者工具。

裡面有幾個常用的面板：

- Console（控制台）面板可以查看日誌和錯誤，執行 JavaScript 程式碼，查看變數值。
- Sources（源程式碼）面板可以設置斷點，單步執行，查看調用棧。
- Network（網絡）面板可以查看 API 請求，檢查請求和響應，分析加載時間。
- Performance（性能）面板可以分析性能瓶頸，查看渲染時間，找出慢的操作。

![](https://pic.yupi.icu/1/image-20260105093342746.png)

掌握這些工具，你的調試效率會大大提高。



### 3、二分法定位問題

如果你不確定問題在哪裡，可以試試二分法。

很好理解，直接把程式碼分成兩半，註釋掉其中一半，看問題是否還在。如果還在，說明問題在另一半；如果不在，說明問題在這一半。然後繼續把有問題的那一半再分成兩半，重複這個過程，直到找到問題。

這個方法雖然簡單，但很有效，特別是在處理大段程式碼時。



### 4、橡皮鴨調試法

這是一個看似玄學呆板，實則有一定科學原理的方法。

當你被 bug 困住時，試著向別人（或者一隻橡皮鴨）解釋你的程式碼：阿巴阿巴，這個函數應該做什麼…… 它先做了這個…… 然後做了那個…… 咦，這裡好像不對……

很神奇的是，在解釋的過程中，你往往就會發現問題。因為解釋的過程會強迫你重新理清思路，從不同的角度看問題。

哪個