iT邦幫忙

2025 iThome 鐵人賽

DAY 8
0
生成式 AI

團隊 AI 運維手冊:System Prompt 的設計、部署與維護系列 第 8

Day 8|實戰測試:最小可行規範的效果驗證

  • 分享至 

  • xImage
  •  

Day 7 建立了第一版 System Prompt 後,團隊內部開始出現一個聲音:「這份規範看起來很完整,但實際用起來效果如何?」

確實,再完美的規範如果無法在真實開發中發揮作用,就只是一份漂亮的文件。今天我們就來實際測試這份 .cursorrules 的戰力。

一、測試場景設計

選擇訂單系統作為測試目標

我們選擇了電商常見的訂單處理功能作為測試場景,主要考量:

  • 複雜度適中:包含資料驗證、業務邏輯、錯誤處理
  • 團隊熟悉:大家對訂單流程都有基本認知
  • 容易比較:可以觀察不同 AI 工具的產出差異

實際測試條件

# 專案結構
ecommerce-test/
├── .cursorrules          # Day 7 的規範
├── CLAUDE.md            # 軟連結到 .cursorrules
├── src/
│   ├── Controllers/
│   └── Models/
└── tests/

測試任務:讓 AI 幫我們實作 POST /api/orders 端點

二、Claude Code vs Cursor:同場競技

給 AI 的相同任務

請幫我建立一個訂單建立的 API,處理 POST /api/orders 請求,
需要驗證客戶資料和商品庫存

Claude Code 的表現

<?php

declare(strict_types=1);

/**
 * Handle order creation requests
 */
class OrderController 
{
    private OrderValidator $validator;
    private InventoryService $inventory;
    
    public function createOrder(array $requestData): array 
    {
        try {
            // Validate customer and product data
            $validationErrors = $this->validator->validate($requestData);
            if (!empty($validationErrors)) {
                return [
                    'success' => false,
                    'errors' => $validationErrors
                ];
            }
            
            // Check inventory availability  
            if (!$this->inventory->isAvailable($requestData['products'])) {
                return [
                    'success' => false,
                    'message' => 'Insufficient inventory'
                ];
            }
            
            $orderId = $this->processOrder($requestData);
            
            return [
                'success' => true,
                'order_id' => $orderId
            ];
            
        } catch (Exception $e) {
            error_log("Order creation failed: " . $e->getMessage());
            return [
                'success' => false, 
                'message' => 'Order processing failed'
            ];
        }
    }
}

觀察重點

  • 自動加入 declare(strict_types=1)
  • 完整的錯誤處理機制
  • 描述性的變數命名
  • 遵循 PSR-12 格式

Cursor 的表現

<?php

class CreateOrder 
{
    public function handle($request) 
    {
        // Validate required fields
        if (empty($request['customer_id']) || empty($request['products'])) {
            return ['error' => 'Missing required fields'];
        }
        
        // Check product availability
        foreach ($request['products'] as $product) {
            if (!$this->checkStock($product['id'], $product['quantity'])) {
                return ['error' => 'Product ' . $product['id'] . ' not available'];
            }
        }
        
        // Create order
        $order = $this->saveOrder($request);
        
        return ['success' => true, 'order' => $order];
    }
    
    private function checkStock($productId, $quantity) 
    {
        // Database query with prepared statement
        $stmt = $this->db->prepare("SELECT stock FROM products WHERE id = ?");
        $stmt->execute([$productId]);
        $stock = $stmt->fetchColumn();
        
        return $stock >= $quantity;
    }
}

觀察重點

  • 更直接的實作風格
  • 同樣使用準備語句防護 SQL 注入
  • 基本的錯誤處理
  • 少了一些現代 PHP 特性

三、JavaScript 前端驗證測試

測試任務

請建立訂單表單的 JavaScript 驗證,要配合剛才的 API

Claude Code 產出

/**
 * Order form validation handler
 */
class OrderFormValidator {
    constructor(formElement) {
        this.form = formElement;
        this.apiEndpoint = '/api/orders';
        this.initializeValidation();
    }
    
    initializeValidation() {
        this.form.addEventListener('submit', (event) => {
            event.preventDefault();
            this.handleOrderSubmission();
        });
    }
    
    async handleOrderSubmission() {
        const validationResult = this.validateOrderForm();
        if (!validationResult.isValid) {
            this.displayValidationErrors(validationResult.errors);
            return;
        }
        
        try {
            const orderData = this.collectOrderData();
            const response = await this.submitOrder(orderData);
            this.handleOrderResponse(response);
        } catch (error) {
            console.error('Order submission failed:', error);
            this.displayError('Failed to submit order. Please try again.');
        }
    }
    
    validateOrderForm() {
        const customerId = this.form.querySelector('#customer_id').value;
        const products = this.getSelectedProducts();
        const errors = [];
        
        if (!customerId) {
            errors.push('Customer ID is required');
        }
        
        if (products.length === 0) {
            errors.push('Please select at least one product');
        }
        
        return {
            isValid: errors.length === 0,
            errors: errors
        };
    }
}

Cursor 產出

// Order form validation
function validateOrderForm() {
    const customerId = document.getElementById('customer_id').value;
    const productInputs = document.querySelectorAll('.product-input:checked');
    
    if (!customerId) {
        showError('Please enter customer ID');
        return false;
    }
    
    if (productInputs.length === 0) {
        showError('Please select at least one product');
        return false;
    }
    
    return true;
}

async function submitOrder() {
    if (!validateOrderForm()) return;
    
    const formData = {
        customer_id: document.getElementById('customer_id').value,
        products: getSelectedProducts()
    };
    
    try {
        const response = await fetch('/api/orders', {
            method: 'POST',
            headers: {
                'Content-Type': 'application/json',
            },
            body: JSON.stringify(formData)
        });
        
        const result = await response.json();
        
        if (result.success) {
            showSuccess('Order created successfully!');
        } else {
            showError(result.message || 'Order creation failed');
        }
    } catch (error) {
        console.error('Network error:', error);
        showError('Network error occurred');
    }
}

四、測試過程中的發現

1. 命名風格:顯著改善

使用規範前的典型情況

function processData($data) {
    $result = doStuff($data);
    return $result;
}

使用規範後

function validateOrderInput(array $orderData): array
function checkInventoryAvailability(array $products): bool

2. 安全考量:都及格了

兩個工具都很好地遵循了安全約束:

  • 使用準備語句防止 SQL 注入
  • 不在錯誤訊息中洩露敏感資訊
  • 適當的輸入驗證

3. 工具風格差異依然存在

  • Claude Code:傾向物件導向設計,使用現代 PHP 語法
  • Cursor:偏好函數式方法,較保守的語法選擇

4. 測試產出:需要明確要求

兩個工具都沒有主動產出測試程式碼,需要額外提示:

請為剛才的程式碼加上單元測試

但都只測試了 Happy Path,缺乏邊界條件測試。

五、發現的問題與限制

1. 測試規範太模糊

目前規範只寫了「Unit tests for JavaScript functions」,AI 理解不夠具體。

需要改進

TESTING_REQUIREMENTS:
- Write tests for both success and failure scenarios  
- Include edge cases like empty arrays, null values
- Test coverage should include input validation errors

2. 規範優先級不明確

當規範中的要求發生衝突時,AI 不知道該優先遵循哪一項。

3. 缺乏專案脈絡

「Follow existing code patterns」對新專案來說沒有參考點。

六、測試結論

成功的地方

安全規範有效:兩個工具都遵循了安全約束
命名改善明顯:描述性命名確實得到改善
基本風格統一:PSR-12 格式要求被遵循
跨工具可用:.cursorrules 和 CLAUDE.md 都能被正確載入

需要改進的地方

測試要求不夠明確:需要更具體的測試場景描述
工具差異:不同 AI 的程式碼風格仍有差異
規範優先級:衝突時的決策邏輯不清楚
專案初期指引:缺乏新專案的程式碼模式定義


上一篇
Day 7|System Prompt:最小可行規範雛形
系列文
團隊 AI 運維手冊:System Prompt 的設計、部署與維護8
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言