Skip to content

4.4 进阶技巧和最佳实践

🎯 本章目标

本章将深入探讨 Spec-kit 的高级应用场景:

  • ✅ 宪法框架的深度应用
  • ✅ 契约优先开发(Contract-First Development)
  • ✅ 多技术栈并行探索
  • ✅ 团队协作模式
  • ✅ CI/CD 集成
  • ✅ 调试与故障排查

🏛️ 宪法框架深度应用

什么是宪法框架?

宪法(Constitution) 是项目的"不可协商原则",确保所有开发决策符合核心价值观。

markdown
宪法的作用:
✅ 统一团队标准(避免"各自为政")
✅ 自动化质量门控(AI 自动验证)
✅ 防止技术债务(复杂度证明机制)
✅ 加速决策(明确边界)

经典宪法条款示例

Article I: 简洁优先(Simplicity First)

markdown
# Article I: Simplicity First

**原则**: 所有功能必须使用 ≤3 个外部依赖

**理由**:
- 减少维护负担
- 降低安全风险
- 提升长期可维护性

**验证方法**:
```bash
# 检查 Python 项目
cat requirements.txt | grep -v '^#' | grep -v '^$' | wc -l
# 结果必须 ≤ 3

# 检查 Node.js 项目
jq '.dependencies | length' package.json
# 结果必须 ≤ 3

违规处理:

  • 必须在 plan.md 中证明复杂度合理性
  • 提供简化方案的评估
  • 记录为什么简单方案不可行

示例: ✅ 合规: FastAPI (1 dep) ✅ 合规: FastAPI + SQLAlchemy + pytest (3 deps) ❌ 违规: FastAPI + SQLAlchemy + pytest + Redis + Celery (5 deps)


#### Article II: 测试驱动开发(TDD)

```markdown
# Article II: Test-Driven Development

**原则**: 所有代码必须先写测试再写实现

**理由**:
- 确保可测试性
- 防止回归
- 文档化行为

**验证方法**:
```bash
# Git 提交历史必须显示测试先于实现
git log --oneline --grep="test" --grep="implement" --all

# 正确顺序:
# abc123 Add failing test for user registration
# def456 Implement user registration to pass test

# 错误顺序:
# abc123 Implement user registration
# def456 Add tests for user registration ❌

强制执行:

  • Pre-commit hook 检查测试覆盖率
  • CI 管道要求测试先于实现的提交顺序
  • Code review 必须验证 TDD 流程

示例:

python
# Step 1: 先写测试(会失败)
def test_user_registration():
    response = client.post("/api/users", json={
        "email": "test@example.com",
        "password": "SecurePass123"
    })
    assert response.status_code == 201
    assert "user_id" in response.json()

# Step 2: 实现功能(让测试通过)
@app.post("/api/users", status_code=201)
def register_user(user: UserCreate):
    # Implementation
    return {"user_id": 42}

#### Article III: 契约优先(Contract-First)

```markdown
# Article III: Contract-First API Development

**原则**: 所有 API 必须先定义 OpenAPI 规范再实现

**理由**:
- 前后端并行开发
- 自动生成文档
- 契约测试保证一致性

**验证方法**:
```bash
# 检查 contracts/ 目录必须在实现之前创建
git log --diff-filter=A --find-renames --pretty=format:"%H %s" -- "specs/*/contracts/*.yaml"

# 验证实现符合契约
openapi-spec-validator specs/001-feature/contracts/api.yaml

工作流:

  1. 产品经理 + 后端 + 前端共同定义 OpenAPI 契约
  2. 前端基于契约创建 Mock 服务器
  3. 后端基于契约实现 API
  4. 集成时零惊喜(契约保证一致性)

工具链:

bash
# 从 OpenAPI 生成 TypeScript 类型
npx openapi-typescript specs/001-feature/contracts/api.yaml -o types/api.ts

# 从 OpenAPI 生成 Python Pydantic models
datamodel-code-generator --input api.yaml --output schemas.py

# 创建 Mock 服务器(前端开发用)
npx @stoplight/prism-cli mock specs/001-feature/contracts/api.yaml

#### Article IV: 性能预算(Performance Budget)

```markdown
# Article IV: Performance Budget

**原则**: 所有功能必须满足性能预算

**预算标准**:
| 指标 | 目标 | 测量方法 |
|------|------|----------|
| API 响应时间 | < 200ms (P95) | Load testing |
| 页面加载时间 | < 2s (FCP) | Lighthouse |
| 数据库查询 | < 50ms | Query profiling |
| Bundle 大小 | < 200KB (gzipped) | webpack-bundle-analyzer |

**验证方法**:
```bash
# API 性能测试
ab -n 1000 -c 10 http://localhost:8000/api/endpoint

# 前端性能测试
lighthouse https://example.com --only-categories=performance --chrome-flags="--headless"

# 数据库查询分析
EXPLAIN ANALYZE SELECT * FROM users WHERE email = 'test@example.com';

超预算处理:

  • 必须在 plan.md 中证明为什么需要超预算
  • 提供优化方案和时间表
  • 记录性能 trade-off

示例:

markdown
## Performance Budget Justification

| Feature | Budget | Actual | Status | Justification |
|---------|--------|--------|--------|--------------|
| User Login | 200ms | 180ms | ✅ Pass | - |
| Photo Upload | 200ms | 350ms | ❌ Fail | Large file processing required |

### Photo Upload 性能证明:
- 简化方案: 客户端压缩(rejected - 移动端 CPU 限制)
- 当前方案: 服务端压缩 + 异步处理
- 优化计划:
  1. 引入 CDN(预计减少 100ms)
  2. 使用 WebAssembly 压缩(预计减少 50ms)
  3. 目标: 降至 200ms 以内(2 周内完成)

### 宪法的演进

**版本管理:**
```markdown
# Project Constitution

**Version**: 2.1.0
**Ratified**: 2025-01-01
**Last Amended**: 2025-01-15

## Version History
- v2.1.0 (2025-01-15): Added Article V (Security Standards)
- v2.0.0 (2025-01-10): BREAKING - Changed Article I dependency limit from 5 to 3
- v1.1.0 (2025-01-05): Added Article IV (Performance Budget)
- v1.0.0 (2025-01-01): Initial constitution

## Amendment Process
1. Proposal: 任何团队成员可以提出修正案
2. Discussion: 团队讨论 (minimum 3 days)
3. Vote: 需要 2/3 多数同意
4. Update: 更新 constitution.md,增加版本号
5. Migrate: 所有活跃 feature 必须验证新宪法合规性

宪法升级工作流:

bash
# 1. 备份当前宪法
cp .specify/memory/constitution.md .specify/memory/constitution.v1.0.0.md

# 2. 更新宪法
# 编辑 .specify/memory/constitution.md

# 3. 验证所有活跃 feature 符合新宪法
for feature in specs/*/; do
  echo "Validating $feature"
  /speckit.analyze --constitution-version=2.0.0 --feature=$feature
done

# 4. 提交变更
git add .specify/memory/constitution.md
git commit -m "Constitution v2.0.0: Reduce dependency limit to 3

BREAKING CHANGE: Article I now requires ≤3 dependencies (was 5)

All active features validated against new constitution.
Features requiring adjustment: 003-analytics (pending refactor)"

📜 契约优先开发(Contract-First Development)

核心理念

传统方式:

后端实现 API → 前端对接 → 发现不一致 → 返工

契约优先方式:

定义 OpenAPI 契约 → 前后端并行开发 → 集成零惊喜

完整工作流示例

Step 1: 定义 OpenAPI 契约(团队协作)

参与角色: 产品经理、后端开发、前端开发、QA

yaml
# specs/001-user-management/contracts/api.yaml
openapi: 3.0.0
info:
  title: User Management API
  version: 1.0.0

components:
  schemas:
    User:
      type: object
      required: [id, email, name]
      properties:
        id:
          type: integer
          example: 42
        email:
          type: string
          format: email
          example: user@example.com
        name:
          type: string
          minLength: 1
          maxLength: 100
          example: John Doe
        created_at:
          type: string
          format: date-time
          example: "2025-01-15T10:30:00Z"

paths:
  /api/users:
    get:
      summary: List users
      operationId: listUsers
      parameters:
        - name: page
          in: query
          schema:
            type: integer
            default: 1
        - name: per_page
          in: query
          schema:
            type: integer
            default: 20
            maximum: 100
      responses:
        '200':
          description: User list
          content:
            application/json:
              schema:
                type: object
                properties:
                  users:
                    type: array
                    items:
                      $ref: '#/components/schemas/User'
                  total:
                    type: integer
                  page:
                    type: integer
                  per_page:
                    type: integer

    post:
      summary: Create user
      operationId: createUser
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [email, name, password]
              properties:
                email:
                  type: string
                  format: email
                name:
                  type: string
                  minLength: 1
                password:
                  type: string
                  format: password
                  minLength: 8
      responses:
        '201':
          description: User created
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/User'
        '400':
          description: Validation error
        '409':
          description: Email already exists

Step 2: 验证契约合法性

bash
# 安装验证工具
npm install -g @apidevtools/swagger-cli

# 验证 OpenAPI 规范
swagger-cli validate specs/001-user-management/contracts/api.yaml

# 输出:
# specs/001-user-management/contracts/api.yaml is valid ✅

Step 3: 前端并行开发(使用 Mock 服务器)

bash
# 启动 Mock 服务器(自动基于 OpenAPI 生成)
npx @stoplight/prism-cli mock specs/001-user-management/contracts/api.yaml

# 输出:
# [Prism] Server is running on http://127.0.0.1:4010

前端代码(立即开始开发):

typescript
// frontend/src/api/users.ts
import axios from 'axios';

// 使用 Mock 服务器
const API_BASE = process.env.NODE_ENV === 'development'
  ? 'http://127.0.0.1:4010'  // Mock server
  : 'https://api.production.com';  // Real API

interface User {
  id: number;
  email: string;
  name: string;
  created_at: string;
}

interface UserListResponse {
  users: User[];
  total: number;
  page: number;
  per_page: number;
}

export async function listUsers(page = 1, perPage = 20): Promise<UserListResponse> {
  const response = await axios.get(`${API_BASE}/api/users`, {
    params: { page, per_page: perPage }
  });
  return response.data;
}

export async function createUser(email: string, name: string, password: string): Promise<User> {
  const response = await axios.post(`${API_BASE}/api/users`, {
    email,
    name,
    password
  });
  return response.data;
}

// 前端可以立即开发 UI,无需等待后端!

Step 4: 后端并行开发(基于契约实现)

python
# backend/src/schemas.py
# 从 OpenAPI 自动生成 Pydantic models
from pydantic import BaseModel, EmailStr, Field
from datetime import datetime

class UserResponse(BaseModel):
    id: int
    email: EmailStr
    name: str = Field(..., min_length=1, max_length=100)
    created_at: datetime

class UserCreate(BaseModel):
    email: EmailStr
    name: str = Field(..., min_length=1, max_length=100)
    password: str = Field(..., min_length=8)

class UserListResponse(BaseModel):
    users: list[UserResponse]
    total: int
    page: int
    per_page: int
python
# backend/src/api/users.py
from fastapi import APIRouter, HTTPException, Query
from src.schemas import UserResponse, UserCreate, UserListResponse
from src.models import User
from src.database import get_db

router = APIRouter(prefix="/api", tags=["Users"])

@router.get("/users", response_model=UserListResponse)
async def list_users(
    page: int = Query(1, ge=1),
    per_page: int = Query(20, ge=1, le=100),
    db=Depends(get_db)
):
    """
    List users with pagination.

    Implements: GET /api/users from OpenAPI contract
    """
    offset = (page - 1) * per_page
    users = db.query(User).offset(offset).limit(per_page).all()
    total = db.query(User).count()

    return UserListResponse(
        users=users,
        total=total,
        page=page,
        per_page=per_page
    )

@router.post("/users", response_model=UserResponse, status_code=201)
async def create_user(user_data: UserCreate, db=Depends(get_db)):
    """
    Create a new user.

    Implements: POST /api/users from OpenAPI contract
    """
    # Check email uniqueness
    existing = db.query(User).filter(User.email == user_data.email).first()
    if existing:
        raise HTTPException(status_code=409, detail="Email already exists")

    # Hash password
    hashed_password = hash_password(user_data.password)

    # Create user
    user = User(
        email=user_data.email,
        name=user_data.name,
        password_hash=hashed_password
    )
    db.add(user)
    db.commit()
    db.refresh(user)

    return user

Step 5: 契约测试(验证实现符合契约)

python
# backend/tests/test_contract_compliance.py
import pytest
from fastapi.testclient import TestClient
from openapi_core import create_spec
from openapi_core.validation.request import openapi_request_validator
from openapi_core.validation.response import openapi_response_validator

@pytest.fixture
def openapi_spec():
    with open('specs/001-user-management/contracts/api.yaml') as f:
        return create_spec(yaml.safe_load(f))

def test_list_users_contract(client: TestClient, openapi_spec):
    """验证 GET /api/users 实现符合契约"""
    response = client.get("/api/users?page=1&per_page=10")

    # 验证响应结构符合 OpenAPI schema
    validator = openapi_response_validator(openapi_spec)
    result = validator.validate(response)

    assert result.errors == []  # 无验证错误
    assert response.status_code == 200

    data = response.json()
    assert "users" in data
    assert "total" in data
    assert isinstance(data["users"], list)

def test_create_user_contract(client: TestClient, openapi_spec):
    """验证 POST /api/users 实现符合契约"""
    response = client.post("/api/users", json={
        "email": "test@example.com",
        "name": "Test User",
        "password": "SecurePass123"
    })

    # 验证响应符合契约
    validator = openapi_response_validator(openapi_spec)
    result = validator.validate(response)

    assert result.errors == []
    assert response.status_code == 201

    data = response.json()
    assert "id" in data
    assert data["email"] == "test@example.com"

Step 6: 集成(前后端对接)

typescript
// 前端切换到真实 API
const API_BASE = 'https://api.production.com';  // 从 Mock 切换到真实

// 由于都遵循同一个 OpenAPI 契约,集成时零惊喜!

契约优先的价值:

节省时间:前后端并行开发,节省 40-60% 时间
减少 bug:契约保证一致性,集成 bug 减少 80%
自动文档:OpenAPI 自动生成文档,永远最新
类型安全:自动生成类型定义,编译时发现错误

🌲 多技术栈并行探索

使用场景

创业团队不确定最佳技术栈时,可以从同一份规格生成多个实现,对比后选择最优方案。

完整案例:仪表盘项目

Step 1: 编写技术无关的规格

bash
/speckit.specify 用户仪表盘,显示任务统计、最近活动、快速操作

生成 specs/001-dashboard/spec.md(技术无关):

markdown
## User Scenarios

### P1: 任务统计概览
- Given 用户登录系统
- When 访问仪表盘
- Then 显示:
  - 待办任务数量
  - 已完成任务数量
  - 今日新增任务
  - 本周完成率趋势图

### P2: 最近活动流
- Given 用户有操作记录
- When 滚动仪表盘
- Then 显示最近 10 条活动(创建、完成、删除任务)
- And 每条活动显示:图标、描述、时间戳

## Success Criteria
- SC-001: 仪表盘加载 < 1 second
- SC-002: 支持 1000+ 任务无性能下降
- SC-003: 实时更新(WebSocket)

Step 2: 生成 3 个并行技术方案

方案 A: React + Node.js + MongoDB

bash
/speckit.plan React 18 + TypeScript + Node.js Express + MongoDB + Socket.io

关键技术决策(plan-react-node.md):

markdown
## Technical Context
- Frontend: React 18 + TypeScript + Vite
- Backend: Node.js 20 + Express 4
- Database: MongoDB 6
- Real-time: Socket.io
- State: Zustand

## 优势
✅ 全栈 JavaScript(学习曲线低)
✅ MongoDB 灵活 schema(适合快速迭代)
✅ Socket.io 开箱即用

## 劣势
❌ MongoDB 无事务(复杂查询弱)
❌ Node.js 单线程(CPU 密集型差)

方案 B: Vue + Python + PostgreSQL

bash
/speckit.plan Vue 3 + TypeScript + Python FastAPI + PostgreSQL + Server-Sent Events

关键技术决策(plan-vue-python.md):

markdown
## Technical Context
- Frontend: Vue 3 + TypeScript + Vite
- Backend: Python 3.11 + FastAPI
- Database: PostgreSQL 15
- Real-time: Server-Sent Events (SSE)
- State: Pinia

## 优势
✅ PostgreSQL 强大查询能力
✅ FastAPI 高性能(Starlette + Pydantic)
✅ Python 生态丰富(数据分析)

## 劣势
❌ SSE 单向通信(需要 polling 补充)
❌ Python 部署复杂度高

方案 C: Svelte + Go + SQLite

bash
/speckit.plan Svelte + Go + SQLite + WebSocket

关键技术决策(plan-svelte-go.md):

markdown
## Technical Context
- Frontend: Svelte 4 + TypeScript
- Backend: Go 1.21 + Gin
- Database: SQLite 3
- Real-time: Gorilla WebSocket
- Deployment: Single binary

## 优势
✅ 极致性能(Go + Svelte 编译优化)
✅ 部署简单(单个可执行文件)
✅ SQLite 零配置(嵌入式数据库)

## 劣势
❌ SQLite 并发写限制(多用户场景弱)
❌ Go 生态较小(库不如 Python/Node丰富)

Step 3: 并行实现(3 个开发者)

bash
# 开发者 A
cd implementations/react-node
/speckit.tasks --plan=../../specs/001-dashboard/plan-react-node.md
/speckit.implement

# 开发者 B
cd implementations/vue-python
/speckit.tasks --plan=../../specs/001-dashboard/plan-vue-python.md
/speckit.implement

# 开发者 C
cd implementations/svelte-go
/speckit.tasks --plan=../../specs/001-dashboard/plan-svelte-go.md
/speckit.implement

Step 4: 基准测试对比

性能测试脚本:

bash
#!/bin/bash
# benchmark.sh

echo "=== 性能基准测试 ==="

# 测试 1: 冷启动时间
echo "冷启动时间:"
for impl in react-node vue-python svelte-go; do
  cd implementations/$impl
  time curl -s http://localhost:3000/api/dashboard > /dev/null
  cd ../..
done

# 测试 2: 吞吐量 (1000 requests)
echo "吞吐量测试:"
ab -n 1000 -c 10 http://localhost:3000/api/dashboard

# 测试 3: 内存使用
echo "内存使用:"
ps aux | grep "node\|python\|go-app"

# 测试 4: Bundle 大小
echo "前端 Bundle 大小:"
du -sh implementations/*/dist

测试结果:

┌─────────────┬──────────┬─────────┬────────┬──────────┐
│ 实现方案     │ 冷启动   │ 吞吐量  │ 内存   │ Bundle   │
├─────────────┼──────────┼─────────┼────────┼──────────┤
│ React+Node  │ 850ms    │ 450 RPS │ 180MB  │ 245KB    │
│ Vue+Python  │ 320ms    │ 1200RPS │ 95MB   │ 180KB    │
│ Svelte+Go   │ 120ms    │ 2500RPS │ 25MB   │ 85KB     │
└─────────────┴──────────┴─────────┴────────┴──────────┘

结论:Svelte + Go 在所有指标上领先

Step 5: 开发体验对比

开发者反馈:

markdown
| 维度 | React+Node | Vue+Python | Svelte+Go |
|------|-----------|-----------|----------|
| 学习曲线 | ⭐⭐⭐⭐ | ⭐⭐⭐ | ⭐⭐ |
| 开发速度 | ⭐⭐⭐ | ⭐⭐⭐⭐ | ⭐⭐⭐ |
| 调试体验 | ⭐⭐⭐⭐ | ⭐⭐⭐⭐ | ⭐⭐⭐ |
| 生态丰富度 | ⭐⭐⭐⭐⭐ | ⭐⭐⭐⭐ | ⭐⭐⭐ |
| 部署难度 | ⭐⭐⭐ | ⭐⭐ | ⭐⭐⭐⭐⭐ |

开发者 A: "React 生态最成熟,但 bundle 太大"
开发者 B: "Python 开发最快,FastAPI 很爽"
开发者 C: "Go 性能无敌,部署超简单,但库少一些"

Step 6: 最终决策

决策矩阵:

markdown
优先级权重:
- 性能: 40%(核心需求)
- 开发速度: 30%
- 部署简易: 20%
- 生态: 10%

加权得分:
- React+Node: 2.8 / 5.0
- Vue+Python: 3.6 / 5.0  ← 推荐
- Svelte+Go: 3.9 / 5.0   ← **最终选择**

最终选择:Svelte + Go
理由:性能优势明显,部署极简,学习曲线可接受

保留方案: Vue + Python 作为备选(如果 Go 生态不足时切换)


👥 团队协作模式

模式 1:规格先行协作

角色分工:

产品经理 → 编写 spec.md(What & Why)

技术负责人 → Review spec,提出澄清问题

产品经理 → 澄清(/speckit.clarify)

后端团队 → 生成 plan.md(后端技术栈)
前端团队 → 生成 plan.md(前端技术栈)
    ↓(并行开发)
后端 → 实现 API
前端 → 实现 UI

集成测试 → 验证功能

Git 工作流:

bash
# 1. 产品经理创建 spec
git checkout -b 001-user-dashboard
/speckit.specify 用户仪表盘功能
git add specs/001-user-dashboard/spec.md
git commit -m "spec: Add user dashboard specification"
git push origin 001-user-dashboard

# 2. 技术负责人 Review
gh pr create --title "Spec: User Dashboard" --body "Please review specification"
# Team reviews in GitHub PR comments

# 3. 澄清后,产品经理更新 spec
/speckit.clarify
git add specs/001-user-dashboard/spec.md
git commit -m "spec: Clarify real-time update requirements"
git push

# 4. 后端团队创建 plan
git checkout 001-user-dashboard
/speckit.plan FastAPI + PostgreSQL + WebSocket
git add specs/001-user-dashboard/plan-backend.md
git commit -m "plan: Backend technical design"
git push

# 5. 前端团队创建 plan(基于同一个 spec)
/speckit.plan React + TypeScript + Socket.io
git add specs/001-user-dashboard/plan-frontend.md
git commit -m "plan: Frontend technical design"
git push

# 6. 并行实现
# 后端团队
cd backend
/speckit.tasks --plan=../specs/001-user-dashboard/plan-backend.md
/speckit.implement
git add backend/
git commit -m "feat: Implement user dashboard API"

# 前端团队(同时进行)
cd frontend
/speckit.tasks --plan=../specs/001-user-dashboard/plan-frontend.md
/speckit.implement
git add frontend/
git commit -m "feat: Implement user dashboard UI"

# 7. 集成
git merge 001-user-dashboard
# 由于都基于同一个 spec + 契约,集成顺利

模式 2:宪法驱动标准化

团队宪法示例:

markdown
# Team Constitution v2.0

## Article I: Code Review 标准
所有代码必须通过至少 2 人 review

**验证方法**:
```bash
# GitHub branch protection rules
gh api repos/:owner/:repo/branches/main/protection \
  --field required_pull_request_reviews[required_approving_review_count]=2

Article II: 测试覆盖率

所有新代码测试覆盖率 ≥ 80%

验证方法:

bash
# CI pipeline
pytest --cov=src --cov-report=term --cov-fail-under=80

Article III: 安全扫描

所有依赖必须通过安全扫描

验证方法:

bash
# CI pipeline
npm audit --audit-level=high
safety check --json

Article IV: 性能预算

所有 API 响应 < 200ms (P95)

验证方法:

bash
# Load testing in CI
k6 run performance-test.js

**CI/CD 集成(自动验证宪法):**
```yaml
# .github/workflows/constitution-check.yml
name: Constitution Compliance

on:
  pull_request:
    branches: [main]

jobs:
  check-constitution:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3

      - name: Article I - Verify PR approvals
        run: |
          approvals=$(gh pr view ${{ github.event.pull_request.number }} --json reviews --jq '.reviews | length')
          if [ "$approvals" -lt 2 ]; then
            echo "❌ Article I violated: Need 2 approvals, got $approvals"
            exit 1
          fi

      - name: Article II - Test coverage
        run: |
          pytest --cov=src --cov-report=term --cov-fail-under=80

      - name: Article III - Security scan
        run: |
          npm audit --audit-level=high
          safety check

      - name: Article IV - Performance test
        run: |
          k6 run --quiet performance-test.js
          # Fails if P95 > 200ms

🚀 CI/CD 集成

完整 CI/CD 管道

yaml
# .github/workflows/spec-driven-pipeline.yml
name: Spec-Driven CI/CD

on:
  push:
    branches: [main]
    paths:
      - 'specs/**'
      - 'src/**'
      - 'tests/**'

jobs:
  validate-spec:
    name: Validate Specification
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3

      - name: Install Spec-kit
        run: |
          pip install uv
          uv tool install specify-cli --from git+https://github.com/github/spec-kit.git

      - name: Validate against constitution
        run: |
          # 检查所有 spec 符合宪法
          for spec in specs/*/spec.md; do
            echo "Validating $spec"
            specify analyze --spec=$spec --constitution=.specify/memory/constitution.md
          done

      - name: Verify OpenAPI contracts
        run: |
          npm install -g @apidevtools/swagger-cli
          for contract in specs/*/contracts/*.yaml; do
            swagger-cli validate $contract
          done

  test-backend:
    name: Backend Tests
    needs: validate-spec
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3

      - name: Setup Python
        uses: actions/setup-python@v4
        with:
          python-version: '3.11'

      - name: Install dependencies
        run: |
          pip install -r backend/requirements.txt
          pip install pytest pytest-cov

      - name: Run tests
        run: |
          cd backend
          pytest --cov=src --cov-report=xml --cov-fail-under=80

      - name: Contract compliance tests
        run: |
          # 验证实现符合 OpenAPI 契约
          pytest tests/test_contract_compliance.py

      - name: Upload coverage
        uses: codecov/codecov-action@v3
        with:
          file: ./backend/coverage.xml

  test-frontend:
    name: Frontend Tests
    needs: validate-spec
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3

      - name: Setup Node.js
        uses: actions/setup-node@v3
        with:
          node-version: '20'

      - name: Install dependencies
        run: |
          cd frontend
          npm ci

      - name: Run tests
        run: |
          cd frontend
          npm run test:coverage

      - name: Build
        run: |
          cd frontend
          npm run build

      - name: Check bundle size
        run: |
          cd frontend
          size=$(du -sb dist | awk '{print $1}')
          max_size=$((200 * 1024))  # 200KB
          if [ $size -gt $max_size ]; then
            echo "❌ Bundle too large: ${size}B > ${max_size}B"
            exit 1
          fi

  performance-test:
    name: Performance Testing
    needs: [test-backend, test-frontend]
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3

      - name: Setup services
        run: |
          docker-compose -f docker-compose.test.yml up -d
          sleep 10  # Wait for services to be ready

      - name: Install k6
        run: |
          sudo gpg -k
          sudo gpg --no-default-keyring --keyring /usr/share/keyrings/k6-archive-keyring.gpg --keyserver hkp://keyserver.ubuntu.com:80 --recv-keys C5AD17C747E3415A3642D57D77C6C491D6AC1D69
          echo "deb [signed-by=/usr/share/keyrings/k6-archive-keyring.gpg] https://dl.k6.io/deb stable main" | sudo tee /etc/apt/sources.list.d/k6.list
          sudo apt-get update
          sudo apt-get install k6

      - name: Run load tests
        run: |
          k6 run --quiet performance/load-test.js
          # Fails if metrics don't meet constitution requirements

  deploy-staging:
    name: Deploy to Staging
    needs: [test-backend, test-frontend, performance-test]
    if: github.ref == 'refs/heads/main'
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3

      - name: Deploy backend
        run: |
          # Deploy to staging environment
          ./scripts/deploy-staging.sh backend

      - name: Deploy frontend
        run: |
          ./scripts/deploy-staging.sh frontend

      - name: Smoke tests
        run: |
          # Verify deployment
          curl -f https://staging.example.com/health || exit 1
          curl -f https://staging.example.com/ || exit 1

🐛 调试与故障排查

常见问题 1: Spec 与 Plan 不一致

症状:

实现的功能与 spec.md 描述不符

排查方法:

bash
# 运行一致性检查
/speckit.analyze

# 输出:
# ❌ Inconsistency detected:
# - spec.md requires "User can filter by tags"
# - plan.md does not mention tag filtering
# - tasks.md has no tag-related tasks

解决方案:

bash
# 更新 plan 包含遗漏的功能
/speckit.plan [重新生成,包含标签过滤]

# 更新 tasks
/speckit.tasks

# 重新实现
/speckit.implement

常见问题 2: 宪法违规

症状:

plan.md 中使用了 5 个依赖,违反宪法(≤3)

排查方法:

bash
# 检查依赖数量
grep "^dependencies:" plan.md -A 10 | wc -l

# 输出:5 ❌(违规)

解决方案:

markdown
## Complexity Justification(在 plan.md 中添加)

| Dependency | Justification | Simpler Alternative | Why Rejected |
|------------|---------------|---------------------|--------------|
| FastAPI | Web framework | Flask | FastAPI async performance needed |
| SQLAlchemy | ORM | Raw SQL | Complex queries, migrations |
| Pytest | Testing | unittest | Better fixtures, plugins |
| Redis | Caching | In-memory | Distributed deployment requirement |
| Celery | Task queue | Threading | Requires distributed workers |

**Total Dependencies**: 5
**Constitution Limit**: 3
**Approval Required**: Yes

**Mitigation Plan**:
1. Phase 1: Ship with 5 deps (approved violation)
2. Phase 2 (Q2 2025): Replace Celery with lightweight alternative
3. Target: Reduce to 4 deps by Q2, 3 deps by Q3

常见问题 3: 契约测试失败

症状:

Contract test failed: Response does not match OpenAPI schema

排查方法:

python
# tests/test_contract_compliance.py
def test_create_user_contract(client):
    response = client.post("/api/users", json={...})

    # 详细错误信息
    from openapi_core.validation.response import openapi_response_validator
    validator = openapi_response_validator(openapi_spec)
    result = validator.validate(response)

    for error in result.errors:
        print(f"❌ {error}")

    # 输出:
    # ❌ Response body does not match schema:
    #    Missing required field: 'created_at'

解决方案:

python
# 修复实现,添加缺失字段
@app.post("/api/users")
def create_user(user_data: UserCreate):
    user = User(
        email=user_data.email,
        name=user_data.name,
        created_at=datetime.utcnow()  # ← 添加缺失字段
    )
    # ...
    return user

💡 最佳实践总结

✅ DO(推荐做法)

  1. 早期定义宪法

    ✅ 项目启动时就创建宪法
    ✅ 团队共同讨论,达成共识
    ✅ 版本化管理宪法
  2. 契约优先

    ✅ API 先定义 OpenAPI 契约
    ✅ 前后端基于契约并行开发
    ✅ 使用 Mock 服务器
    ✅ 契约测试保证一致性
  3. 多方案探索

    ✅ 技术选型不确定时,生成多个 plan
    ✅ 并行实现 POC,基准测试对比
    ✅ 数据驱动决策
  4. 自动化验证

    ✅ CI/CD 管道验证宪法合规性
    ✅ 自动运行契约测试
    ✅ 性能测试门控

❌ DON'T(避免做法)

  1. 跳过宪法

    ❌ 直接开始写代码
    ❌ 每个人各自为政
    ❌ 事后才定义标准
  2. 先实现再定义契约

    ❌ 后端实现完再定义 API
    ❌ 前端等待后端完成
    ❌ 手工编写 API 文档
  3. 单一技术栈盲目推进

    ❌ 不验证就选择技术栈
    ❌ 没有对比基准测试
    ❌ 凭感觉做决策

🚀 下一步

恭喜你掌握了 Spec-kit 的高级技巧!现在你已经学会:

✅ 宪法框架的深度应用 ✅ 契约优先开发完整流程 ✅ 多技术栈并行探索 ✅ 团队协作最佳实践 ✅ CI/CD 集成方案 ✅ 调试与故障排查

下一步: 4.5 本章小结 - 回顾核心知识点,查看常见问题和资源推荐!


Spec-kit 核心概念教程 v1.0 | 2025 Edition | 基于 GitHub Spec-kit 官方仓库

基于 MIT 许可证发布。内容版权归作者所有。