
12/07/2026
为什么 AI 时代反而需要 SDD 和 TDD?
AI Coding 时代,SDD帮助我们明确“开发什么”,TDD帮助我们验证“是否正确”。本文结合 OpenSpec、真实项目案例和个人理解,探索两者如何结合,构建更高效、更可靠的软件开发流程。
最近在学习 AI Coding 相关的开发流程时,我接触到了两个之前没有深入理解的概念:
- SDD(Specification Driven Development,规范驱动开发)
- TDD(Test Driven Development,测试驱动开发)
最开始接触 SDD 的时候,我其实比较容易理解。
因为它和传统的软件开发流程非常接近:
需求分析
↓
产品设计
↓
UI设计
↓
技术方案
↓
前端/后端开发
↓
测试
↓
上线
但是 TDD 一开始让我非常困惑。
为什么测试要提前写?
测试不是应该在代码完成之后,用来验证代码有没有问题吗?
而且如果测试用例先写,那开发之前怎么可能考虑完整所有情况?
带着这些疑问,我开始深入了解 TDD 和 SDD,并结合 AI Coding 时代的软件开发方式重新思考这两个概念。
这篇文章记录一下我的理解过程。
一、为什么现在重新关注 SDD 和 TDD?
在传统软件开发过程中,通常是:
需求
↓
开发人员理解需求
↓
设计方案
↓
编写代码
↓
测试
↓
上线
这种方式在过去几十年中非常成熟。
但是随着软件复杂度提升,以及 AI Coding 工具出现,我发现一个新的问题:
> 现在写代码越来越容易,但是确定“应该写什么代码”越来越困难。
以前:开发人员需要花大量时间写代码。
现在:AI 可以快速生成大量代码。例如:
告诉 AI:
帮我开发一个博客系统
AI 很快可以生成:
- 页面
- API
- 数据库模型
- 组件代码
但是 AI 不知道:
- 这是个人博客还是商业博客?
- 是否需要用户体系?
- 是否需要权限?
- 是否需要评论?
- 技术架构是什么?
- 哪些功能是必须的?
最终可能生成一个:
> 看起来完整,但是并不是我真正想要的系统。
所以 AI Coding 时代,最大的挑战逐渐从:“如何写代码” 变成:“如何准确描述我要构建什么”。
这也是 SDD 重新受到关注的重要原因。
二、我对 SDD 的理解
SDD 可以理解为:
> 在真正开始开发之前,通过 Specification(规范)明确系统应该是什么样子。
它解决的问题是:
> 我们到底要开发什么?
传统开发:
需求文档
↓
开发
而 SDD:
需求
↓
Specification
↓
设计
↓
任务拆分
↓
开发
三、通过一个真实项目理解 SDD
假设我要开发一个: 打牌记账微信小程序
需求:
> 用户创建牌局房间,邀请朋友加入,然后记录每个人输赢,最终自动结算。
如果直接开发:可能马上开始:
创建房间页面
↓
房间接口
↓
数据库
↓
结算逻辑
但是开发过程中会不断遇到问题:
- 房间有没有人数限制?
- 房主退出怎么办?
- 输赢如何计算?
- 是否支持重新结算?
- 是否保存历史记录?
这些问题如果没有提前明确,开发过程会不断返工。
使用 SDD 后
首先拆 Specification。例如:
requirements.md
描述业务规则:
功能:
创建牌局房间
用户输入:
- 房间名称
系统返回:
- 房间ID
规则:
- 创建者拥有管理权限
- 一个房间最多10人
- 房间创建后可以邀请成员加入
design.md
描述技术设计:
系统架构:
微信小程序
↓
NestJS API
↓
MySQL
数据模型:
Room
id
name
creatorId
status
createdAt
接口:
POST /rooms
tasks.md
拆分开发任务:
Task1:
创建Room数据库表
Task2:
实现createRoom Service
Task3:
实现创建房间接口
Task4:
增加权限校验
这样开发人员或者 AI Agent 才知道:
- 为什么做
- 做什么
- 怎么拆分
所以:
> SDD解决的是“开发方向问题”。
四、为什么 AI Coding 时代更加需要 SDD?
以前:
需求
↓
人理解需求
↓
人写代码
现在:
需求
↓
Specification
↓
AI Agent
↓
生成代码
AI 最大的问题不是不会写代码。
而是不知道:
> 你真正想要什么。
Specification 就成为:
人与 AI 之间的沟通层。
它把人的想法转换成 AI 可以执行的约束。
五、我最开始不理解 TDD 的地方
相比 SDD,TDD 一开始让我更加疑惑。
传统开发:
写代码
↓
运行
↓
发现问题
↓
修改
而 TDD:
写测试
↓
测试失败
↓
写代码
↓
测试通过
↓
重构
我的第一个疑问:
> 为什么要反过来?
后来我理解:TDD 并不是:
“提前写很多测试代码”。
它真正表达的是:
> 先定义代码应该具备什么行为,再实现这个行为。
六、通过一个真实案例理解 TDD
还是以:创建房间功能为例。
SDD 已经拆出来:
Task:
实现 createRoom Service
普通开发方式
开发人员可能直接:
async createRoom(dto){
return repository.save(dto)
}
然后测试发现问题:
- 房间名称为空也可以创建
- 返回格式不符合要求
- 缺少权限判断
于是:
写代码
↓
发现问题
↓
修改代码
TDD 的实际过程:红 → 绿 → 重构
TDD 通常遵循:
Red
↓
Green
↓
Refactor
第一步:Red
先写测试。例如:
test(
"创建房间应该成功",
async()=>{
const room =
await service.createRoom({
name:"周末麻将"
})
expect(room.name)
.toBe("周末麻将")
})
运行:
FAIL
失败是正常的。因为功能还没有实现。
第二步:Green
实现最简单代码:
async createRoom(dto){
return {
name:dto.name
}}
再次运行:
PASS
第三步:Refactor
现在代码可以优化。
例如:拆分:
RoomService
↓
RoomValidator
↓
RoomRepository
只要测试通过:就可以放心重构。
八、TDD最大的价值:让重构变得安全
这是我后来认为 TDD 最重要的价值。
很多人认为:
> TDD只是为了减少 Bug。
但是实际上:
> TDD 最大的价值,是让未来修改代码变得更加安全。
例如:
第一版:
function calculateScore(){
}
半年后:业务越来越复杂:
- 不同牌局规则
- VIP积分
- 活动奖励
- 特殊计算方式
代码可能变成:
calculateScore(){
if(){
}
if(){
}
if(){
}
}
这时候开发人员想重构。拆成:
ScoreCalculator
RuleEngine
BonusCalculator
如果没有测试:只能依靠人工验证。风险很高。 但是有 TDD:
修改代码
↓
运行测试
↓
测试通过
↓
确认行为没有改变
↓
安全上线
所以:
> 测试不是限制重构,而是保护重构。
九、TDD 的测试能覆盖全部情况吗?
这是我最开始最大的疑问。如果测试不能考虑全面:
> 那 TDD 有意义吗?
后来理解:
> TDD 不要求一次性预测未来所有情况。
真实项目中:
测试会随着需求变化不断增加。
例如:
第一版本:
创建房间
记录输赢
结算
测试:
创建房间成功
金额计算正确
上线之后:
用户提出:
> 玩家中途退出怎么办?
那么增加:
玩家退出重新计算
对应增加测试。所以测试不是: 预测未来。
而是:
记录当前系统应该具备的行为。
十、为什么 TDD 会导致更好的架构设计?
这是 TDD 最容易被忽略的价值。原因:
> 难测试的代码,通常也是难维护的代码。
例如:
一个订单服务:
class OrderService{
createOrder(){
查询用户
查询商品
检查库存
计算价格
创建订单
扣库存
发送邮件
}}
测试这个方法,需要准备:
- 数据库
- 用户数据
- 商品数据
- 库存服务
- 邮件服务
测试非常困难。
这说明:代码职责太多,耦合严重。
于是拆分:
OrderService
↓
InventoryService
PricingService
NotificationService
每个模块:
- 职责单一
- 可以独立测试
- 更容易维护
所以 TDD 会推动:
- 单一职责原则
- 低耦合设计
- 面向接口设计
- 模块化架构
十一、SDD 和 TDD 如何结合?
如果使用 OpenSpec:生成:
proposal
design
tasks
是不是直接 apply 执行?我的理解:不是简单执行。
更合理流程:
需求
↓
OpenSpec
↓
proposal
↓
design
↓
tasks
↓
选择Task
↓
编写测试
↓
实现代码
↓
运行测试
↓
重构
↓
Task完成
十二、OpenSpec 怎么知道执行哪些测试?
这里容易产生误解。
> OpenSpec 本身不知道。
因为:
> SDD 和 TDD 解决的问题不同。
SDD:
我要做什么
TDD:
如何证明做对了
两者通过工程规范连接。
例如:
团队规定:每个 Task, 必须包含:
Implementation
Test
Validation
例如:
Task:
实现createRoom API
Implementation:
创建接口
Test:
创建成功
空名称失败
Validation:
npm test
十三、TDD实际使用哪些工具?
TDD不是一个工具。而是一种开发方法。常见测试工具:
- Jest
- Vitest
- React Testing Library
十四、AI Agent 为什么更加需要 TDD?
AI 写代码最大的风险:不是不会写。而是:
- 理解错误
- 修改错误文件
- 过度实现
- 破坏已有逻辑
TDD提供一个反馈闭环:
AI生成代码
↓
运行测试
↓
测试失败
↓
AI根据错误修复
↓
测试通过
测试成为:AI Agent 的自动反馈机制。
十五、我现在对 SDD 和 TDD 的最终理解
如果把开发软件比作建房子:
SDD
类似:建筑设计图。决定:
我要建什么房子?
房间如何布局?
TDD
类似:施工验收标准。保证:
每个结构符合要求。
所以:
SDD解决:
> 我们是不是在开发正确的东西?
TDD解决:
> 我们开发出来的东西是不是正确?
十六、总结
以前的软件开发:
人理解需求
↓
人设计方案
↓
人写代码
↓
人测试
AI Coding 时代:
人定义 Specification
↓
AI生成任务
↓
AI编写代码
↓
TDD验证
人的角色正在从:
> 代码生产者
转变为:
> 系统设计者和约束制定者。
最终我的理解:
> SDD 是 AI 时代解决“方向问题”的方法。
> TDD 是 AI 时代解决“质量问题”的方法。
两者结合,会成为未来 AI 软件开发的重要工作流。
(以上内容是我总结出来的并不代表正确,仅供参考,如有问题可联系我纠正)