Initial commit

This commit is contained in:
Zhongwei Li
2025-11-29 18:03:43 +08:00
commit 2d7bed1e9d
8 changed files with 1725 additions and 0 deletions

415
commands/kb-green.md Normal file
View File

@@ -0,0 +1,415 @@
---
description: 讓測試通過Green 階段)。用最簡單、甚至是"錯誤"的方式快速讓測試變綠。
---
# TDD Green - 讓測試通過Green
用最簡單的方式讓測試通過。可以作弊、可以硬編碼、可以"錯誤"。
**【功能名】**{{feature_name}}
## Kent Beck 的 Green 階段理念
> "快速讓測試通過,用任何手段。"
> "乾淨的程式碼是目標,但先讓它能動。"
### 三種讓測試通過的策略
Kent Beck 在書中提出的三種策略:
#### 策略 1Fake It假實作
**最快速的方式:回傳常數**
```javascript
// 測試
test('5 * 2 = 10', () => {
expect(multiply(5, 2)).toBe(10);
});
// 假實作:直接回傳 10
function multiply(a, b) {
return 10;
}
```
**為什麼這樣做?**
- 快速得到綠燈
- 心理上的安全感
- 用下一個測試來逼出真正的實作
#### 策略 2Obvious Implementation明顯實作
**當實作很明顯時,直接寫出來**
```javascript
// 測試
test('加法運算', () => {
expect(add(2, 3)).toBe(5);
});
// 明顯實作:加法很簡單
function add(a, b) {
return a + b;
}
```
**何時使用?**
- 實作非常簡單
- 你很有信心
- 不需要三角測量
#### 策略 3Triangulation三角測量
**用多個測試來推導正確實作**
```javascript
// 第 1 個測試
test('1 + 1 = 2', () => {
expect(add(1, 1)).toBe(2);
});
// 假實作
function add(a, b) {
return 2;
}
// 第 2 個測試(三角測量)
test('2 + 3 = 5', () => {
expect(add(2, 3)).toBe(5);
});
// 被逼出真正的實作
function add(a, b) {
return a + b;
}
```
**何時使用?**
- 不確定正確的實作方式
- 想從多個角度驗證
- 設計還不清楚
## 實作步驟
### 1. 選擇策略
根據你的信心程度:
```
信心很低 → Fake It假實作
信心中等 → Triangulation三角測量
信心很高 → Obvious Implementation明顯實作
```
### 2. 寫最少的程式碼
**重點:最少**
```javascript
// 測試需要一個類別
test('Dollar 乘法', () => {
const five = new Dollar(5);
const product = five.times(2);
expect(product.amount).toBe(10);
});
// 最少的實作
class Dollar {
constructor(amount) {
this.amount = amount;
}
times(multiplier) {
return new Dollar(10); // 假實作!
}
}
```
### 3. 執行測試
```bash
npm test
```
**看到綠燈!** 🟢
### 4. 更新 journey.md
```markdown
#### 🟢 Green - 讓測試通過
策略:{Fake It / Obvious / Triangulation}
實作說明:
{簡述你做了什麼}
程式碼位置:{檔案路徑}
測試結果:✅ 通過
#### 🤔 反思
- 這個實作明顯是假的/硬編碼的嗎?
- 需要下一個測試來逼出真正的實作嗎?
- 有沒有重複的程式碼?
#### 📝 下一步
執行 /kb-refactor 重構
```
## Fake It 的威力
### 範例Money 的演進
**第 1 輪:完全假實作**
```javascript
test('5 * 2 = 10', () => {
const five = new Dollar(5);
expect(five.times(2).amount).toBe(10);
});
class Dollar {
constructor(amount) {
this.amount = amount;
}
times(multiplier) {
return new Dollar(10); // 硬編碼!
}
}
```
**第 2 輪:三角測量逼出真實作**
```javascript
test('5 * 3 = 15', () => {
const five = new Dollar(5);
expect(five.times(3).amount).toBe(15);
});
class Dollar {
times(multiplier) {
return new Dollar(this.amount * multiplier); // 真實作!
}
}
```
## 常見的"作弊"技巧
### 技巧 1回傳常數
```javascript
function getWelcomeMessage() {
return "Hello, World!"; // 先硬編碼
}
```
### 技巧 2複製測試資料
```javascript
// 測試
expect(processData(input)).toEqual({
status: 'success',
count: 5
});
// 實作:直接回傳期待值
function processData(input) {
return { status: 'success', count: 5 };
}
```
### 技巧 3最簡單的 if
```javascript
// 測試 1
test('even number', () => {
expect(classify(2)).toBe('even');
});
// 假實作
function classify(n) {
if (n === 2) return 'even';
}
// 測試 2 會逼出真實作
test('another even number', () => {
expect(classify(4)).toBe('even');
});
function classify(n) {
return n % 2 === 0 ? 'even' : 'odd';
}
```
## 實作的禁忌
Kent Beck 說明在 Green 階段應該避免的:
### ❌ 不要過度設計
```javascript
// ❌ 不要這樣(太複雜)
class Dollar {
constructor(amount, currency = 'USD') {
this.amount = amount;
this.currency = currency;
}
times(multiplier) {
// 處理多幣別、匯率轉換...
}
// 一堆還不需要的方法
add() {}
subtract() {}
convert() {}
}
// ✅ 要這樣(夠用就好)
class Dollar {
constructor(amount) {
this.amount = amount;
}
times(multiplier) {
return new Dollar(this.amount * multiplier);
}
}
```
### ❌ 不要一次實作多個測試
```javascript
// 目前只有一個測試需要 times()
// 不要順便實作 add(), subtract()
// 等有測試需要時再加
```
### ❌ 不要重構
```javascript
// ❌ Green 階段不要重構
// 先讓測試通過
// 重構留給下一步
// ✅ 先這樣
function calculate(x) {
return x * 2;
}
// 不要在這裡就改成
const MULTIPLIER = 2;
function calculate(x) {
return x * MULTIPLIER;
}
// 重構留給 /kb-refactor
```
## 心態:接受"醜陋"的程式碼
Kent Beck 強調的心態轉變:
```
階段 1讓它能動 (Make it work) ← 現在在這裡
階段 2讓它正確 (Make it right)
階段 3讓它快速 (Make it fast)
```
**Green 階段只追求"能動"**
- 硬編碼?沒關係
- 重複?沒關係
- 醜陋?沒關係
**下一步會改善**
## 範例完整流程
### 測試(失敗)
```javascript
test('購物車初始總價為 0', () => {
const cart = new ShoppingCart();
expect(cart.getTotal()).toBe(0);
});
```
### 實作策略選擇
**信心評估**:這個很簡單,用 Obvious Implementation
### 實作程式碼
```javascript
// src/shopping-cart.js
class ShoppingCart {
getTotal() {
return 0; // 最簡單的實作
}
}
module.exports = ShoppingCart;
```
### 執行測試
```bash
npm test
# ✅ 通過!
```
### 記錄到 journey.md
```markdown
#### 🟢 Green - 讓測試通過
策略Obvious Implementation
實作說明:
建立 ShoppingCart 類別getTotal() 回傳 0。
雖然是硬編碼,但足以通過目前的測試。
程式碼位置src/shopping-cart.js
測試結果:✅ 通過
#### 🤔 反思
- 實作很簡單,是硬編碼
- 下一個測試:加入商品後總價應該改變
- 目前沒有明顯重複
#### 📝 下一步
執行 /kb-refactor 檢查是否需要重構
```
## 速度的重要性
Kent Beck**Green 階段要快**
**目標**
- 幾秒鐘到幾分鐘
- 不要花太久時間
- 快速得到綠燈的心理回饋
**如果卡住**
- 寫更小的測試
- 用更假的實作
- 回退重來
## 下一步
測試通過了?執行:
```
/kb-refactor
```
檢查是否有重複,進行重構!
## 記住 Kent Beck 的話
> "讓測試通過的技巧是暫時降低對程式碼品質的標準。"
> "骯髒的程式碼是通往乾淨程式碼的墊腳石。"
> "當你看到綠燈時,那是重構的信號。"