第5章:Spec规范驱动开发详解
好的Spec是成功的一半。花时间编写清晰的规格说明,将在整个开发过程中获得回报。编写清晰的Spec是AI辅助编程的关键。在Spec中,我们需要尽可能详细地描述需求、技术栈、架构、代码结构和测试要求。通过实战,我们可以将Spec转化为完整的项目代码。
5.1 什么是Spec规范
Spec(规格说明)是对软件系统或组件的详细描述,包括功能、性能、设计约束、接口等方面的要求。在AI编程中,Spec是用户提供给AI的“任务书”,AI根据Spec生成代码。
5.2 如何编写清晰的规格说明
一个清晰的Spec应该包含以下要素:
-
项目概述:简要描述项目的目标和范围。
-
功能需求:详细描述系统必须实现的功能。
-
非功能需求:包括性能、安全性、可用性等要求。
-
约束条件:技术选型、开发规范等限制。
5.3 技术栈指定方法
在Spec中明确技术栈,包括:
-
编程语言及版本
-
框架、库和工具
-
数据库和中间件
-
开发环境和部署环境
5.4 架构模式说明
根据项目需求选择合适的架构模式,并在Spec中说明:
-
分层架构(如MVC、微服务)
-
组件之间的关系和通信方式
-
数据流和流程控制
5.5 代码结构规划
描述项目的代码组织方式:
-
目录结构
-
模块划分
-
命名规范
5.6 测试要求描述
说明测试策略和具体要求:
-
单元测试、集成测试、端到端测试
-
测试框架和工具
-
覆盖率要求
5.7 实战:从Spec到完整项目
我们将通过一个实际例子,展示如何从一个详细的Spec生成一个完整的项目。
示例:构建一个简单的待办事项(Todo)API服务
下面是一个具体的Spec示例:
项目概述:
开发一个RESTful API服务,用于管理待办事项(Todo)。用户可以通过API创建、查看、更新和删除待办事项。
功能需求:
-
用户可以对Todo进行CRUD操作。
-
每个Todo包含以下字段:id(唯一标识)、title(标题)、description(描述)、completed(是否完成)、created_at(创建时间)、updated_at(更新时间)。
-
提供以下API端点:
-
POST /todos:创建新的Todo
-
GET /todos:获取所有Todo列表
-
GET /todos/:id:根据id获取单个Todo
-
PUT /todos/:id:更新指定id的Todo
-
DELETE /todos/:id:删除指定id的Todo
-
非功能需求:
-
性能:每个API端点响应时间应在100ms以内。
-
安全性:API应提供基本的输入验证,防止SQL注入等攻击。
-
可维护性:代码应具有良好的结构和注释。
约束条件:
-
使用Node.js和Express框架。
-
使用SQLite数据库,并使用Sequelize作为ORM。
-
使用Jest进行单元测试,测试覆盖率不低于80%。
架构模式:
采用MVC模式,分为模型(Model)、视图(View,此处为API接口)、控制器(Controller)。
代码结构规划:
src/
├── controllers/
│ └── todos.js
├── models/
│ └── todo.js
├── routes/
│ └── todos.js
├── app.js
└── server.js
tests/
└── todos.test.js
package.json
测试要求:
-
对每个API端点进行单元测试。
-
测试应包括成功情况和错误情况。
-
使用supertest进行HTTP断言。
根据以上Spec,我们可以逐步生成代码。以下是一个简化的代码生成示例:
第一步:生成package.json和安装依赖
第二步:生成模型(Model)
第三步:生成控制器(Controller)
第四步:生成路由(Route)
第五步:生成主应用文件(app.js和server.js)
第六步:生成测试文件
由于篇幅限制,这里只展示部分关键代码。
例如,生成模型文件(src/models/todo.js):
const { DataTypes } = require('sequelize');
const sequelize = require('../config/database');
const Todo = sequelize.define('Todo', {
id: {
type: DataTypes.INTEGER,
primaryKey: true,
autoIncrement: true,
},
title: {
type: DataTypes.STRING,
allowNull: false,
},
description: {
type: DataTypes.TEXT,
},
completed: {
type: DataTypes.BOOLEAN,
defaultValue: false,
},
created_at: {
type: DataTypes.DATE,
defaultValue: DataTypes.NOW,
},
updated_at: {
type: DataTypes.DATE,
defaultValue: DataTypes.NOW,
},
});
module.exports = Todo;
然后,我们可以生成控制器、路由等。
通过这个例子,我们可以看到,一个清晰的Spec可以帮助AI生成结构清晰、符合要求的代码。在实际使用中,我们可以根据Spec分步骤生成代码,并在每一步进行验证和调整。
一、什么是Spec规范
1.1 Spec的核心概念
Spec(Specification) 是软件开发中的规格说明文档,在AI编程中特指向AI提供的详细需求说明,用于驱动代码生成。
1.2 AI编程中Spec的重要性
传统开发:需求文档 → 人工编码 → 测试
AI驱动:Spec规范 → AI生成代码 → 验证迭代
1.3 Spec的构成要素
-
功能描述:系统应该做什么
-
非功能需求:性能、安全、可用性要求
-
约束条件:技术、业务、环境限制
-
验收标准:如何验证实现正确
二、如何编写清晰的规格说明
2.1 Spec编写原则
CLEAR原则:
-
Complete(完整):覆盖所有需求
-
Logical(逻辑):结构清晰合理
-
Explicit(明确):无歧义表述
-
Actionable(可执行):AI能理解并实现
-
Reviewable(可评审):便于验证和反馈
2.2 结构化Spec模板
# 项目名称规范说明
## 1. 项目概述
- **项目目标**:[一句话描述]
- **问题描述**:[解决什么痛点]
- **用户画像**:[目标用户是谁]
## 2. 核心功能
### 2.1 功能模块A
- **功能描述**:
- **输入**:
- **处理逻辑**:
- **输出**:
- **边界条件**:
### 2.2 功能模块B
[...]
## 3. 非功能需求
- **性能指标**:[响应时间、吞吐量等]
- **安全性要求**:[数据加密、访问控制等]
- **可扩展性**:[未来扩展考虑]
- **兼容性**:[浏览器、设备支持]
## 4. 技术约束
- **必须使用**:[特定技术或框架]
- **禁止使用**:[不允许的技术]
- **遵循标准**:[编码规范、设计模式]
## 5. 交付物要求
- **代码结构**:[目录组织方式]
- **文档要求**:[README、API文档等]
- **测试要求**:[测试覆盖率、类型等]
2.3 用例式Spec编写
用户故事格式:
功能:用户登录
作为:网站用户
我希望:使用邮箱和密码登录
以便:访问个人资料
场景:正常登录
当:我输入正确的邮箱和密码
并且:点击登录按钮
那么:我应该被重定向到个人主页
并且:显示欢迎消息
场景:登录失败
当:我输入错误的密码
并且:点击登录按钮
那么:我应该看到错误提示
并且:停留在登录页面
具体用例规范:
用例: 添加商品到购物车
参与者: 注册用户
前置条件: 用户已登录,商品有库存
主流程:
1. 用户浏览商品列表
2. 用户选择商品并点击"加入购物车"
3. 系统验证库存
4. 系统添加商品到购物车
5. 系统显示添加成功消息
6. 更新购物车图标数量
异常流程:
1. 库存不足: 显示"库存不足"提示
2. 未登录: 跳转到登录页面
后置条件: 购物车包含所选商品
三、技术栈指定方法
3.1 完整技术栈规范
## 技术栈规范
### 编程语言
- **主语言**: Python 3.11+
- **版本管理**: 使用pyenv或conda
- **代码风格**: 遵循PEP 8,使用black格式化
### Web框架
- **后端**: FastAPI
- **版本**: 0.100+
- **配置**: 使用Pydantic进行配置管理
### 数据库
- **主数据库**: PostgreSQL 15+
- **ORM**: SQLAlchemy 2.0+
- **迁移工具**: Alembic
- **连接池**: asyncpg
### 缓存
- **缓存系统**: Redis 7+
- **客户端**: redis-py或aioredis
- **使用场景**: 会话缓存、API限流
### 前端(如适用)
- **框架**: React 18+
- **状态管理**: Redux Toolkit
- **构建工具**: Vite
- **UI组件**: Material-UI 5+
- **样式方案**: CSS-in-JS (Emotion)
### DevOps工具
- **容器化**: Docker + Docker Compose
- **CI/CD**: GitHub Actions
- **监控**: Prometheus + Grafana
- **日志**: ELK Stack
3.2 依赖版本精确控制
# 示例:requirements.txt或pyproject.toml
[project]
name = "my-project"
version = "1.0.0"
description = "项目描述"
dependencies = [
"fastapi>=0.100.0,<0.101.0",
"uvicorn[standard]>=0.23.0,<0.24.0",
"sqlalchemy>=2.0.0,<3.0.0",
"pydantic>=2.0.0,<3.0.0",
"alembic>=1.12.0,<2.0.0",
"psycopg2-binary>=2.9.0,<3.0.0",
]
[project.optional-dependencies]
dev = [
"pytest>=7.4.0,<8.0.0",
"pytest-asyncio>=0.21.0,<0.22.0",
"black>=23.0,<24.0",
"mypy>=1.5.0,<2.0.0",
]
3.3 技术决策文档(ADR)
# 技术决策记录:数据库选型
## 状态
已接受
## 背景
需要为电商应用选择合适的数据存储方案,需求包括:
- 处理大量交易数据
- 支持复杂查询和事务
- 保证数据一致性
- 支持水平扩展
## 考虑方案
### 方案A: PostgreSQL
- 优点:ACID兼容、丰富的数据类型、强大的查询能力
- 缺点:水平扩展相对复杂
### 方案B: MongoDB
- 优点:灵活的模式、易于水平扩展
- 缺点:不支持事务(早期版本)、JOIN操作复杂
### 方案C: MySQL
- 优点:成熟稳定、社区支持好
- 缺点:功能相对较少
## 决策
选择**PostgreSQL**,原因:
1. 需要强一致性保证
2. 复杂的商品和订单关系查询
3. 未来可能的地理空间查询需求
## 影响
- 需要配置连接池管理
- 需要考虑备份和恢复策略
- 开发团队需要熟悉PostgreSQL特性
四、架构模式说明
4.1 分层架构规范
## 六层架构规范
### 1. 表现层(Presentation Layer)
- **职责**:处理HTTP请求/响应
- **组件**:路由、中间件、序列化
- **技术**:FastAPI路由、Pydantic模型
- **约束**:只处理输入验证和输出格式化
### 2. 应用层(Application Layer)
- **职责**:业务流程编排
- **组件**:用例服务、工作流
- **技术**:Python服务类
- **约束**:无数据库操作,调用领域服务
### 3. 领域层(Domain Layer)
- **职责**:业务逻辑和规则
- **组件**:实体、值对象、领域服务
- **技术**:纯Python类
- **约束**:无外部依赖,可独立测试
### 4. 基础设施层(Infrastructure Layer)
- **职责**:技术实现细节
- **组件**:数据库访问、外部API调用
- **技术**:SQLAlchemy、HTTP客户端
- **约束**:实现领域层定义的接口
### 5. 共享内核(Shared Kernel)
- **职责**:跨限界上下文共享
- **组件**:通用工具、基础类型
- **技术**:Python工具模块
- **约束**:保持最小化,避免耦合
### 6. 横切关注点(Cross-cutting Concerns)
- **职责**:日志、监控、安全等
- **组件**:中间件、装饰器、AOP
- **技术**:FastAPI中间件、装饰器
- **约束**:透明添加,不影响业务逻辑
4.2 微服务架构规范
服务定义:
用户服务:
职责: 用户注册、登录、资料管理
接口:
- POST /api/v1/users: 创建用户
- GET /api/v1/users/{id}: 获取用户信息
- PUT /api/v1/users/{id}: 更新用户信息
数据存储: PostgreSQL users表
通信方式: REST API + 事件发布
订单服务:
职责: 订单创建、支付、状态管理
接口: [订单相关端点]
事件订阅:
- UserCreatedEvent: 用户注册时创建购物车
- PaymentCompletedEvent: 支付完成更新订单状态
通信规范:
REST API:
版本控制: URL路径版本 (/api/v1/)
认证: JWT Bearer Token
错误响应: 统一错误格式
分页: 使用cursor-based分页
消息队列:
技术: RabbitMQ或Kafka
消息格式: JSON Schema验证
重试策略: 指数退避
死信队列: 失败消息处理
五、代码结构规划
5.1 项目骨架生成
# 示例项目结构
my_project/
├── .github/ # GitHub配置
│ ├── workflows/ # CI/CD流程
│ └── ISSUE_TEMPLATE/ # Issue模板
├── src/ # 源代码
│ ├── core/ # 核心模块
│ │ ├── __init__.py
│ │ ├── config/ # 配置管理
│ │ ├── exceptions/ # 自定义异常
│ │ └── security/ # 安全相关
│ ├── modules/ # 业务模块
│ │ ├── auth/ # 认证模块
│ │ │ ├── __init__.py
│ │ │ ├── domain/ # 领域层
│ │ │ ├── application/ # 应用层
│ │ │ ├── infrastructure/ # 基础设施
│ │ │ └── api/ # API层
│ │ ├── users/ # 用户模块
│ │ └── orders/ # 订单模块
│ ├── shared/ # 共享代码
│ │ ├── schemas/ # Pydantic模型
│ │ ├── dependencies/ # FastAPI依赖
│ │ └── middleware/ # 中间件
│ └── main.py # 应用入口
├── tests/ # 测试代码
│ ├── unit/ # 单元测试
│ ├── integration/ # 集成测试
│ ├── e2e/ # 端到端测试
│ └── fixtures/ # 测试夹具
├── migrations/ # 数据库迁移
├── scripts/ # 工具脚本
├── docker/ # Docker配置
├── docs/ # 文档
├── .env.example # 环境变量示例
├── .pre-commit-config.yaml # Git钩子配置
├── pyproject.toml # 项目配置
├── Dockerfile # Docker构建文件
├── docker-compose.yml # Docker编排
├── README.md # 项目说明
└── Makefile # 常用命令
5.2 模块化设计规范
# 示例:用户模块的领域层设计
# src/modules/users/domain/
# ├── entities.py # 实体定义
# ├── value_objects.py # 值对象
# ├── services.py # 领域服务
# └── repositories.py # 仓储接口
# 实体定义示例
from dataclasses import dataclass
from datetime import datetime
from typing import Optional
from uuid import UUID, uuid4
@dataclass
class User:
"""用户实体"""
id: UUID
email: str
username: str
hashed_password: str
is_active: bool = True
is_verified: bool = False
created_at: datetime = None
updated_at: datetime = None
def __post_init__(self):
if self.created_at is None:
self.created_at = datetime.utcnow()
if self.updated_at is None:
self.updated_at = self.created_at
def change_password(self, new_hashed_password: str):
"""修改密码"""
self.hashed_password = new_hashed_password
self.updated_at = datetime.utcnow()
def verify_email(self):
"""验证邮箱"""
self.is_verified = True
self.updated_at = datetime.utcnow()
5.3 接口设计规范
# 仓储接口定义
from abc import ABC, abstractmethod
from typing import Optional, List
from uuid import UUID
class UserRepository(ABC):
"""用户仓储接口"""
@abstractmethod
async def get_by_id(self, user_id: UUID) -> Optional[User]:
"""根据ID获取用户"""
pass
@abstractmethod
async def get_by_email(self, email: str) -> Optional[User]:
"""根据邮箱获取用户"""
pass
@abstractmethod
async def add(self, user: User) -> None:
"""添加用户"""
pass
@abstractmethod
async def update(self, user: User) -> None:
"""更新用户"""
pass
@abstractmethod
async def delete(self, user_id: UUID) -> None:
"""删除用户"""
pass
@abstractmethod
async def list(
self,
skip: int = 0,
limit: int = 100
) -> List[User]:
"""列出用户"""
pass
六、测试要求描述
6.1 测试金字塔规范
## 测试策略
### 单元测试(占比70%)
- **范围**:单个函数、类、方法
- **目标**:验证代码逻辑正确性
- **要求**:
- 覆盖率 >= 80%
- 无外部依赖(使用mock)
- 快速执行(< 5分钟)
- **工具**:pytest, unittest
### 集成测试(占比20%)
- **范围**:模块间集成、数据库操作
- **目标**:验证组件协作
- **要求**:
- 使用测试数据库
- 测试关键业务流
- 包含错误场景
- **工具**:pytest + testcontainers
### 端到端测试(占比10%)
- **范围**:完整用户流程
- **目标**:验证系统整体功能
- **要求**:
- 模拟真实用户操作
- 包含主要业务流程
- 定期执行(非每次提交)
- **工具**:Playwright, Selenium
6.2 测试代码规范
# 测试文件结构示例
# tests/
# ├── conftest.py # 测试配置和夹具
# ├── unit/ # 单元测试
# │ ├── test_entities.py
# │ └── test_services.py
# ├── integration/ # 集成测试
# │ ├── test_repositories.py
# │ └── test_api.py
# └── e2e/ # 端到端测试
# └── test_user_flow.py
# 单元测试示例
import pytest
from uuid import uuid4
from datetime import datetime
from src.modules.users.domain.entities import User
class TestUserEntity:
"""用户实体测试"""
def test_create_user(self):
"""测试用户创建"""
# Arrange
user_id = uuid4()
email = "test@example.com"
username = "testuser"
password = "hashed_password"
# Act
user = User(
id=user_id,
email=email,
username=username,
hashed_password=password
)
# Assert
assert user.id == user_id
assert user.email == email
assert user.username == username
assert user.is_active is True
assert user.is_verified is False
assert isinstance(user.created_at, datetime)
assert user.created_at == user.updated_at
def test_change_password(self):
"""测试修改密码"""
# Arrange
user = User(
id=uuid4(),
email="test@example.com",
username="testuser",
hashed_password="old_hash"
)
original_updated_at = user.updated_at
# Act
user.change_password("new_hash")
# Assert
assert user.hashed_password == "new_hash"
assert user.updated_at > original_updated_at
@pytest.mark.parametrize("email", [
"invalid",
"@example.com",
"test@",
"test@.com",
"test@example."
])
def test_invalid_email_creation(self, email):
"""测试无效邮箱创建用户"""
# 这里假设实体有邮箱验证逻辑
with pytest.raises(ValueError):
User(
id=uuid4(),
email=email,
username="testuser",
hashed_password="hash"
)
6.3 测试数据管理
# 测试数据管理策略
测试夹具(Fixtures):
位置: tests/conftest.py 或 tests/fixtures/
类型:
静态数据: JSON/YAML文件
动态数据: Factory生成器
数据库: 每次测试后清理
数据生成:
工具: Faker, factory_boy
原则:
- 每个测试独立数据
- 避免测试间依赖
- 易于理解和调试
测试数据库:
策略: 每个测试用例独立数据库
工具: pytest-docker, testcontainers
清理: 自动清理测试数据
七、实战:从Spec到完整项目
7.1 完整示例:待办事项API服务
# 项目规范:待办事项管理API
## 1. 项目概述
- **名称**: Todo API Service
- **目标**: 提供RESTful API管理待办事项
- **用户**: 移动应用和Web应用开发者
## 2. 功能需求
### 2.1 待办事项管理
- 创建、读取、更新、删除待办事项
- 标记待办事项为完成/未完成
- 按状态、创建时间筛选
### 2.2 用户管理
- 用户注册和登录
- JWT认证
- 个人资料管理
## 3. 技术栈
- **后端**: FastAPI + Python 3.11
- **数据库**: PostgreSQL + SQLAlchemy
- **认证**: JWT + OAuth2密码流
- **测试**: pytest + pytest-asyncio
- **部署**: Docker + Docker Compose
## 4. 架构设计
- **模式**: 分层架构(表现层、应用层、领域层、基础设施层)
- **认证**: JWT token,有效期7天
- **API版本**: v1路径版本控制
## 5. API规范
### 5.1 认证端点
- `POST /api/v1/auth/register` - 用户注册
- `POST /api/v1/auth/login` - 用户登录
- `POST /api/v1/auth/refresh` - 刷新token
### 5.2 待办事项端点
- `GET /api/v1/todos` - 获取待办事项列表
- `POST /api/v1/todos` - 创建待办事项
- `GET /api/v1/todos/{id}` - 获取单个待办事项
- `PUT /api/v1/todos/{id}` - 更新待办事项
- `DELETE /api/v1/todos/{id}` - 删除待办事项
- `PATCH /api/v1/todos/{id}/complete` - 标记完成
## 6. 数据模型
```sql
-- 用户表
CREATE TABLE users (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
email VARCHAR(255) UNIQUE NOT NULL,
username VARCHAR(100) NOT NULL,
hashed_password VARCHAR(255) NOT NULL,
is_active BOOLEAN DEFAULT TRUE,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
-- 待办事项表
CREATE TABLE todos (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
user_id UUID REFERENCES users(id) ON DELETE CASCADE,
title VARCHAR(255) NOT NULL,
description TEXT,
is_completed BOOLEAN DEFAULT FALSE,
due_date TIMESTAMP,
priority INTEGER DEFAULT 3, -- 1:高, 2:中, 3:低
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
7. 测试要求
-
单元测试覆盖率 >= 85%
-
集成测试所有API端点
-
E2E测试主要用户流程
-
使用pytest-mock进行依赖模拟
### 7.2 分阶段实现计划
```yaml
# 第一阶段:项目搭建
任务:
- 创建项目结构
- 配置开发环境
- 设置数据库连接
- 创建基础配置
交付物:
- 可运行的FastAPI应用
- 数据库迁移配置
- 基础测试环境
# 第二阶段:用户认证
任务:
- 实现用户模型
- 创建认证路由
- 实现JWT token生成
- 添加密码哈希
交付物:
- 用户注册/登录API
- 安全的密码存储
- token验证中间件
# 第三阶段:待办事项核心功能
任务:
- 实现Todo模型
- 创建CRUD操作
- 添加权限检查
- 实现筛选和排序
交付物:
- 完整的Todo API
- 用户隔离的数据访问
- 丰富的查询选项
# 第四阶段:高级功能
任务:
- 添加分页
- 实现搜索功能
- 添加数据验证
- 完善错误处理
交付物:
- 生产就绪的API
- 完善的错误响应
- 性能优化的查询
# 第五阶段:测试和部署
任务:
- 编写测试用例
- 配置CI/CD
- 创建Docker配置
- 编写文档
交付物:
- 测试套件
- 部署脚本
- API文档
- 用户指南
7.3 AI驱动开发工作流
开发流程:
1. 编写详细Spec → AI生成项目骨架
2. 审核生成代码 → 反馈修改意见
3. 迭代完善功能 → 逐步添加细节
4. 编写测试用例 → AI生成测试代码
5. 集成和部署 → AI生成配置脚本
沟通模式:
开发者:提供详细Spec和约束
AI助手:生成符合规范的代码
开发者:审查、测试、提供反馈
AI助手:根据反馈迭代改进
八、最佳实践总结
8.1 Spec编写检查清单
-
需求描述是否完整无歧义
-
技术栈是否明确指定
-
架构设计是否清晰
-
接口定义是否详细
-
数据模型是否完整
-
测试要求是否具体
-
约束条件是否明确
8.2 AI交互提示技巧
清晰指令格式:
"请使用[技术栈]实现[功能],要求:
1. 遵循[架构模式]
2. 包含[特定功能]
3. 使用[命名规范]
4. 提供[测试用例]
5. 添加[文档注释]"
8.3 迭代改进策略
-
首先生成骨架:让AI创建基础结构
-
逐步添加细节:分模块完善功能
-
持续验证:每步都运行测试
-
及时反馈:发现问题时立即纠正
-
文档驱动:保持Spec和代码同步更新
通过Spec规范驱动开发,你可以:
-
显著提高AI生成代码的质量
-
减少返工和重构次数
-
确保项目符合架构要求
-
加快开发速度同时保证质量
-
建立可维护的代码基础
记住:好的Spec是成功的一半。花时间编写清晰的规格说明,将在整个开发过程中获得回报。
编写清晰的Spec是AI辅助编程的关键。在Spec中,我们需要尽可能详细地描述需求、技术栈、架构、代码结构和测试要求。通过实战,我们可以将Spec转化为完整的项目代码。
在下一章,我们将学习如何与AI协同进行代码调试和优化。
更多推荐


所有评论(0)