软件开发”驱动”范式全景指南
软件开发领域存在大量以”XX-Driven”命名的开发范式,每种范式都试图解决特定维度的痛点。本文将对主流范式进行全面梳理,帮助你在不同场景下做出合理选择。
一、三大核心范式
1.1 Test-Driven Development(TDD)
测试驱动开发
TDD 是 Kent Beck 在 1990 年代提出的开发方法论,核心思想是在编写实现代码之前先编写测试。它并非简单的”先写测试再写代码”,而是一种通过测试来驱动设计的工程实践。
核心循环:红-绿-重构
TDD 三定律(Uncle Bob):
- 在编写失败的测试之前,不编写任何产品代码
- 只要有一个测试失败,就不再编写更多测试代码
- 产品代码刚好让测试通过即可,不做过多的实现
循环流程:
- Red(红) — 写一个失败的测试用例,测试先运行,预期失败,这个测试定义了”什么算完成”
- Green(绿) — 写最少的代码让测试通过,不关心设计,不关心性能,能过就行,最快速度让红变绿
- Refactor(重构) — 在测试保护下重构代码,优化设计,消除重复,提高可读性,测试确保重构不破坏功能
TDD 的本质:测试驱动设计
TDD 的真正价值不在于”测试”,而在于”驱动设计”:
- 可测试性驱动 — 写测试时发现代码难以测试,说明设计有问题,强迫解耦:依赖注入、接口抽象、单一职责
- 接口优先 — 先写测试就是先定义调用方视角的 API,促使思考”使用者想要什么”,而非”如何实现”
- 小步快跑 — 每次只增加极少量功能,持续获得反馈,避免大方向错误
- 安全网 — 测试覆盖率提供重构信心,敢于改进设计,代码不会腐化
TDD 的节奏感:
好的 TDD 实践者会形成一种自然的节奏,就像音乐的节拍:
-
Red(30秒) → 写测试:空购物车总价为 0
-
Green(10秒) → 返回 0
-
Refactor(5秒) → 无变化
-
Red(30秒) → 写测试:添加一个商品后总价等于商品价格
-
Green(30秒) → 实现添加商品和计算总价
-
Refactor(20秒) → 提取 Money 值对象
-
Red(30秒) → 写测试:添加多个商品后总价为各商品价格之和
-
Green(10秒) → 已有实现刚好满足
-
Refactor(10秒) → 无变化
每个循环 30 秒到 2 分钟,持续前进。
TDD 的层次:
TDD 可以在不同粒度上应用:
- 单元 TDD(Unit TDD) — 测试单个类/方法,速度最快,反馈最快,适合纯业务逻辑
- 验收 TDD(Acceptance TDD) — 测试完整功能/用户故事,端到端验证,适合需求验证
- 集成 TDD(Integration TDD) — 测试模块间协作,关注接口契约,适合微服务场景
实践中通常组合使用:单元 TDD 驱动编码,验收 TDD 驱动需求。
TDD 的争议与真相:
- ❌ “TDD 就是先写测试” → ✅ TDD 是设计方法论,不是测试方法论
- ❌ “TDD 要求 100% 覆盖率” → ✅ TDD 关注核心逻辑,不追求数字指标
- ❌ “TDD 适用于所有场景” → ✅ TDD 最适合确定性的业务逻辑,不适合 UI/探索性代码
- ❌ “TDD 会降低开发速度” → ✅ 初期慢,后期快(减少调试和返工时间)
TDD 的实用技巧:
- 三角法(Triangulation) — 写两个测试约束一个实现,避免过度泛化
- 假实现(Fake It) — 先返回常量让测试通过,逐步替换为真实实现
- 明显实现(Obvious Implementation) — 当实现很明显时,直接写真实代码,不需要假实现过渡
- 单向测试(One-to-One) — 一个测试只验证一个行为,测试名即行为描述
解决的核心问题:
| 问题 | TDD 的解法 |
|---|---|
| 代码质量不可控 | 测试即规范,自动验证 |
| 重构恐惧 | 测试网兜底,敢改代码 |
| 需求理解偏差 | 测试用例即需求实例 |
| 回归缺陷 | 持续回归,即时发现 |
| 设计耦合 | 可测试性要求强制解耦 |
示例:
// Step 1: Red - 写一个失败的测试
@Test
void should_return_fizz_when_number_is_multiple_of_3() {
assertEquals("Fizz", FizzBuzz.of(3));
}
// Step 2: Green - 写刚好通过的最小代码
public static String of(int n) {
if (n % 3 == 0) return "Fizz";
return String.valueOf(n);
}
// Step 3: Refactor - 优化(在此例中暂无必要)
适用场景:
- 逻辑密集的业务模块
- 需要长期维护的核心代码
- 团队追求高代码质量
- 对正确性有高要求的系统
局限性:
- 测试覆盖 UI/交互逻辑困难
- 过度 Mock 导致测试价值下降
- 对架构设计能力要求高
- 不适合探索性/原型代码
TDD 在 AI 时代的角色:
AI 生成代码的质量参差不齐,TDD 提供了一种验证机制:
- 先写测试(人) — 明确需求,定义验收标准,测试即需求规格说明
- 让 AI 生成实现(AI) — 将测试作为 Prompt 的一部分提供给 AI,如”请实现以下测试用例的通过代码”
- 运行测试验证(工具) — 自动验证 AI 输出是否正确,红/绿结果即时反馈
- 人工重构(人) — 审查 AI 生成的代码质量,在测试保护下安全重构
优势: AI 生成代码的正确性有保障,测试作为 Prompt 减少了歧义,人工只需关注设计质量而非正确性。
1.2 Spec-Driven Development(SDD)
规约驱动开发
SDD 强调在编码之前先编写可执行的规约文档,将需求转化为精确、无歧义的形式化规范。SDD 并非新概念(形式化方法可追溯到 1970 年代的 Z Notation),但在 AI 辅助编程时代,它获得了全新的生命力。
1.2.1 传统 SDD:形式化方法
传统 SDD 源于形式化方法(Formal Methods),追求数学级别的精确性。
核心思想:
传统方式:需求文档 → 口头沟通 → 编码 → 发现偏差 → 返工
SDD 方式:形式化规约 → 自动验证 → 编码 → 规约即测试
SDD 的核心:
- 规约是”活文档”(Living Documentation) — 规约是可执行的,不是静态 Word 文档
- 规约是团队共识的唯一来源
经典形式化规约语言:
- TLA+(Temporal Logic of Actions) — 用于并发和分布式系统建模,由 Leslie Lamport(LaTeX 作者)开发,示例:验证 Raft 共识算法的正确性
- Alloy — 轻量级形式化方法,基于关系逻辑,适合软件结构建模
- Z Notation — 基于集合论和一阶谓词逻辑,用于定义系统状态和操作
- OCL(Object Constraint Language) — UML 配套的约束语言,用于定义模型的不变量和前置/后置条件
TLA+ 示例:
-------------------------- MODULE SimpleCounter --------------------------
EXTENDS Naturals
VARIABLE counter
Init == counter = 0
Next == counter' = counter + 1
Spec == Init /\ [][Next]_counter
==========================================================================
规约 vs 测试:
| 维度 | TDD 的测试 | SDD 的规约 |
|---|---|---|
| 受众 | 开发者 | 所有干系人 |
| 语言 | 编程语言 | 形式化语言 + 领域语言 |
| 粒度 | 函数/方法级别 | 系统/特性级别 |
| 关注点 | 实现正确性 | 需求正确性 |
| 变更成本 | 低 | 中高 |
| 验证方式 | 执行测试 | 模型检查/定理证明 |
| 完备性 | 采样验证 | 穷举验证(理论上) |
传统 SDD 的局限性:
- 编写成本高 — 形式化规约需要专业训练,比写代码本身更耗时
- 学习曲线陡峭 — TLA+/Alloy 等工具门槛高,团队难以普及
- 抽象鸿沟 — 形式化模型与真实实现之间存在差距,模型验证通过不代表实现正确
- 不适合快速迭代 — 规约的变更成本高于代码,敏捷开发中难以落地
1.2.2 AI 时代的 SDD:规约即 Prompt
AI 辅助编程彻底改变了 SDD 的实践方式。规约不再需要形式化语言,而是以自然语言 Prompt 的形式存在。
AI-SDD 的核心转变:
传统 SDD(形式化方法):人类写形式化规约 → 模型检查器验证 → 手工编码实现(成本高,门槛高,不适合日常开发)
AI-SDD(Prompt 即规约):人类写自然语言规约 → AI 理解并生成代码 → 人工审查(成本低,门槛低,适合日常开发)
关键洞察:AI 本身就是”规约执行器”——你给它什么规约,它生成什么代码。规约的质量直接决定了 AI 输出的质量。
Prompt 即规约 —— 三层结构:
- 系统规约(System Prompt) — 角色设定、技术栈、编码规范,全局约束,影响所有对话,如”你是一个资深 Java 工程师,使用 DDD 架构…”
- 任务规约(Task Prompt) — 功能需求、输入输出、验收标准,当前任务的具体描述,如”实现一个订单聚合,支持创建订单、添加商品…”
- 示例规约(Example Prompt) — 具体输入输出示例,边界条件说明,如”当订单金额超过 1000 元时,需要审批…”
从规约到代码的完整流程:
AI-SDD 工作流包含四个阶段:
- 编写规约(Spec) — 用自然语言描述功能、约束、边界条件,包含具体示例,产物为 Spec 文档
- AI 生成(Generate) — 将规约作为 Prompt 输入给 AI,AI 理解规约并生成代码和测试
- 验证(Verify) — 编译检查、静态分析,运行测试验证,人工审查是否符合规约意图
- 迭代(Iterate) — 发现偏差→精炼规约→重新生成,发现缺陷→补充规约→重新生成,需求变更→更新规约→重新生成
规约质量对 AI 输出的影响:
案例:实现一个”用户注册”功能
❌ 模糊规约: “实现用户注册功能”
- AI 输出:可能用 Spring Boot 也可能用其他框架,可能包含密码加密也可能不包含,可能校验邮箱格式也可能不校验
- 结果:需要大量人工修改
✅ 精确规约: “实现用户注册功能,要求:1. 使用 Spring Boot 3.2 + JPA;2. 注册字段:邮箱(唯一)、密码(BCrypt 加密)、昵称;3. 邮箱格式校验;4. 密码至少 8 位,包含字母和数字;5. 注册成功后发送欢迎邮件(异步);6. 接口文档:POST /api/v1/users/register;7. 请求体:{email, password, nickname};8. 响应体:{id, email, nickname, createdAt}”
- AI 输出:技术栈匹配,字段校验正确,密码加密实现,异步邮件发送
- 结果:基本可用,仅需少量调整
规约模式库:
常用规约模板包括:
- 功能规约模板 — 功能名称、输入/输出定义、正常流程、异常流程、边界条件
- API 规约模板 — 端点路径、HTTP 方法、请求体结构、响应体结构、错误码定义
- 业务规则规约模板 — 规则描述、触发条件、执行结果、例外情况、示例
- 数据规约模板 — 实体定义、字段约束、关联关系、索引需求、数据量级
AI-SDD 的优势:
传统编码 vs AI-SDD:
| 传统编码 | AI-SDD |
|---|---|
| 编码即设计 | 规约即设计 |
| 边想边写 | 想清楚再写 |
| 代码质量取决于个人 | 代码质量取决于规约 |
| 修改需求 = 改代码 | 修改需求 = 改规约 |
| 调试是主要时间 | 规约是主要时间 |
| 一个人的脑力 | 人 + AI 的脑力 |
核心转变:开发者的角色从”编码者”转变为”规约者”
AI-SDD 的挑战:
- 规约的完备性 — 规约写得太粗则 AI 输出不可控,写得过细则不如自己写代码,需要在”粗”和”细”之间找到平衡
- 规约的维护 — 代码变更后需要同步更新规约,规约与代码的”距离”增大,需要建立规约版本管理机制
- 验证的可靠性 — AI 可能”看起来正确”但实则错误,需要测试来验证 AI 输出,规约→测试→代码三者闭环
适用场景:
- AI 辅助编程的所有场景
- 需求明确、规则清晰的业务模块
- 需要多人协作的 AI 编码项目
- 需要保持代码风格一致的团队
局限性:
- 规约编写本身需要经验
- 模糊需求难以精确规约
- 探索性/创新性工作不适合
1.2.3 从传统 SDD 到 AI-SDD 的演进
传统 SDD → AI-SDD 的演进路径:
- 阶段 1: 形式化规约(1970s-2000s) — TLA+, Alloy, Z Notation,数学级别精确性,安全关键系统专用
- 阶段 2: 可执行规约(2000s-2020s) — BDD (.feature 文件),契约式设计(Design by Contract),更贴近开发者
- 阶段 3: AI 规约(2023-至今) — 自然语言即规约,Prompt 即接口,人人可写规约
趋势:精确性降低但可用性提升,门槛降低使普及度提高,从形式化向自然语言演进。
1.2.4 AI-SDD 工具生态
在 AI-SDD 的实践中,出现了三个关键工具/框架:OpenSpec、Spec-Kit、Superpowers。它们从不同维度支撑了”规约驱动开发”在 AI 时代的落地。
OpenSpec:规范化体系
OpenSpec 是一套开放的 AI 应用规范体系,它为 AI-SDD 提供了标准的规约格式和通信协议。
OpenSpec 规范体系包含四大规范:
- 接口规范 — API 设计原则、请求/响应格式、错误处理规范
- 数据规范 — 数据模型定义、数据格式标准、数据交换协议
- 文档规范 — API 文档标准、代码注释规范、用户文档模板
- 版本规范 — 版本号规则、变更管理流程、兼容性保证
OpenSpec 在 SDD 中的角色:
当 AI 理解规约时,它需要知道”规约的格式是什么”。OpenSpec 提供了:
- 标准化的规约描述格式 — AI 无需猜测规约的意图,规约的字段、类型、约束一目了然
- 接口契约的规范定义 — 请求体和响应体的精确 Schema,错误码和异常流程的统一描述
- 版本管理机制 — 规约本身可以版本化,支持规约的平滑演进
OpenSpec 解决的痛点:“AI 生成的代码接口不统一,集成维护成本高”
Spec-Kit:工具链支撑
Spec-Kit 是一套从规约到代码的自动化工具链,它让”规约驱动”不再停留在理念层面,而是有实实在在的工具支撑。
Spec-Kit 工具链包含四大工具:
| 工具 | 功能 |
|---|---|
| spec-validator(规约验证器) | Schema 验证、规范符合性检查、错误报告 |
| spec-generator(代码生成器) | 从规约生成接口代码、API 文档、测试用例 |
| spec-linter(规约检查器) | 代码风格检查、规范一致性检查、最佳实践建议 |
| spec-docs(文档生成器) | API 文档生成、数据字典生成、示例代码生成 |
Spec-Kit 在 SDD 中的角色:
Spec-Kit 解决的是”规约如何落地”的问题:
- Spec → Validator — 验证规约的质量,防止”坏规约”产生”坏代码”
- Spec → Generator — 从规约自动生成代码骨架,AI 在此基础上填充业务逻辑,效率倍增
- Spec → Linter — 自动检查代码是否偏离规约,保持规约与代码的同步
- Spec → Docs — 从规约自动生成文档,文档即规约,规约即文档
Spec-Kit 解决的痛点:“规约写好了,但手工实现和规约总是对不上”
Superpowers:增强开发模式
Superpowers 是一种 AI 增强的开发模式,它从更高维度定义了”人如何与 AI 协作来实现 SDD”。
Superpowers 开发模式包含四大能力:
- AI 增强 — 规约理解(AI 理解自然语言规约)、代码生成(AI 根据规约生成代码)、代码审查(AI 审查代码合规性)
- 人机协作 — 人类决策(定义规约、做关键决策)、AI 执行(生成代码、编写测试)、持续反馈(人类审查 AI 输出)
- 效率提升 — 自动化重复任务、加速学习曲线、提升代码质量
- 能力扩展 — 知识扩展(AI 提供跨领域知识)、技能增强(AI 辅助完成不擅长的任务)、视野拓展(AI 提供多种方案对比)
Superpowers 在 SDD 中的角色:
Superpowers 解决的是”人如何与 AI 协作”的问题:
- 人类角色(决策者):编写规约(Spec)、审查 AI 输出(Review)、做关键设计决策(Decide)
- AI 角色(执行者):理解规约意图(Understand)、生成代码和测试(Generate)、提供多种方案(Suggest)
- 协作流程:Spec(人)→ Understand(AI)→ Generate(AI)→ Review(人)→ Feedback(人)→ Refine(AI)
Superpowers 解决的痛点:“有了 AI 工具,但不知道如何高效协作”
三大工具的关系:
AI-SDD 工具生态中,三者分工明确:
- OpenSpec — 定义”规约长什么样”(标准)
- Spec-Kit — 提供”规约怎么用”的工具(工具链)
- Superpowers — 定义”人和 AI 怎么配合”(方法论)
三者共同构成了 AI-SDD 的完整实践体系。
在 AI-SDD 工作流中的位置:
基于三大工具的 AI-SDD 工作流:
- 编写规约 — 使用 OpenSpec 规范格式编写规约,使用 Spec-Kit 的 validator 验证规约格式,产物为符合 OpenSpec 标准的规约文档
- AI 生成(Superpowers 协作模式) — 人类将规约作为 Prompt 输入给 AI,AI 理解规约并生成代码,使用 Spec-Kit 的 generator 生成代码骨架
- 验证 — 使用 Spec-Kit 的 linter 检查代码与规约一致性,运行测试验证功能正确性,人工审查代码质量(Superpowers 的 Review 环节)
- 文档与维护 — 使用 Spec-Kit 的 docs 自动生成文档,规约变更时更新 OpenSpec 文档,持续迭代(Superpowers 的 Feedback 循环)
适用场景总结:
| 工具 | 核心价值 | 解决的核心痛点 | 适用阶段 |
|---|---|---|---|
| OpenSpec | 规约标准化 | AI 生成的代码接口不统一 | 规约定义阶段 |
| Spec-Kit | 规约自动化 | 规约与代码脱节,难以落地 | 规约落地阶段 |
| Superpowers | 人机协作方法论 | 有了 AI 但不知道如何高效使用 | 全阶段 |
1.3 Taste-Driven Development(TDD)
品鉴驱动开发
Taste-Driven Development(也常被戏称为 TDD 的第三种含义)强调开发者的品味和判断力在软件设计中的核心作用。它并非正式方法论,而是对”过度依赖流程而忽视人”的反思。在 AI 生成代码日益普及的今天,品味成为开发者的核心竞争力。
1.3.1 品味在软件设计中的角色
什么是编程品味?
编程品味是对代码好坏的直觉判断力。它不是可以量化的指标,而是一种经过大量实践积累的”感觉”。
编程品味不是代码规范(那是规则)、不是设计模式(那是方案)、不是性能指标(那是度量)。
编程品味是看到一段代码就知道”这不对”,面对多个方案时选择”最优雅的”,知道什么时候该抽象、什么时候该具体,在”过度设计”和”设计不足”之间找到平衡。
品味体现在哪些方面:
| 维度 | 低品味 | 高品味 |
|---|---|---|
| 命名 | data1, handleThing, temp | invoice, processPayment, customer |
| 抽象 | 过度抽象或完全没有抽象 | 恰到好处的抽象层次 |
| 一致性 | 混用多种风格 | 风格统一,遵循约定 |
| 简洁性 | 重复代码,冗长逻辑 | 简洁清晰,消除冗余 |
| 接口设计 | 参数过多,职责不清 | 小接口,单一职责 |
| 错误处理 | 吞异常或到处 try-catch | 统一错误处理,语义清晰 |
| 测试 | 测试耦合实现细节 | 测试行为,关注契约 |
| 组合 | 继承层次过深 | 组合优于继承 |
品味的来源:
品味 = 经验 × 反思 × 广度
- 经验:写过的代码量,踩过坑才知道什么方案好,见过坏代码才知道好代码的珍贵
- 反思:对经验的总结,为什么这个方案好?为什么那个方案坏?有没有更好的方案?
- 广度:跨领域的视野,不同编程语言的设计哲学,不同领域的架构模式,不同学科的设计原理
1.3.2 AI 时代:品味是最后的壁垒
AI 可以生成代码,但无法判断代码的好坏。品味成为区分”优秀开发者”和”普通开发者”的关键分水岭。
AI 能做什么 vs 不能做什么:
- AI 擅长:生成符合语法的代码、实现常见模式、生成大量样板代码、按照规范格式化
- AI 不擅长:判断代码是否”优雅”、在多个方案中选择”最合适的”、知道什么时候该打破规则、预见未来需求变化的方向、评估代码的长期可维护性
这些都需要人的品味来判断。
AI 时代的核心技能转变:
传统开发者的技能树:编码能力 > 设计能力 > 需求理解能力
AI 时代开发者的技能树:品味判断 > 需求理解 > 规约编写 > 代码审查 > 编码能力
关键转变:
- 从”自己能写”到”能判断 AI 写得好不好”
- 从”写代码”到”评代码”
- 从”实现者”到”决策者”
AI 代码审查中的品味判断:
审查 AI 生成代码时的品味检查清单:
1. 命名是否传达意图?
- AI 常用模糊命名(data, info, temp)
- 需要重命名为业务含义
2. 抽象层次是否一致?
- AI 可能在同一方法中混用不同抽象级别
- 需要拆分为合理层次
3. 是否有不必要的复杂性?
- AI 可能过度设计("以防万一")
- 需要删除不需要的代码
4. 错误处理是否合理?
- AI 可能忽略边界情况
- 需要补充异常处理
5. 是否有重复代码?
- AI 可能生成重复代码
- 需要提取公共逻辑
6. 测试是否测试行为而非实现?
- AI 可能生成脆弱的测试
- 需要确保测试关注契约
AI 生成代码的品味分级:
Level 1: 能用(Surviving)
── 语法正确,功能跑通
── 但命名混乱,结构臃肿
── 需要大量人工修改
Level 2: 合格(Acceptable)
── 符合规范,逻辑清晰
── 但缺乏设计感,中规中矩
── 少量人工调整即可
Level 3: 优雅(Elegant)
── 简洁清晰,恰到好处
── 设计有品味,读起来舒服
── 几乎不需要修改
Level 4: 卓越(Exceptional)
── 有洞见的设计
── 预见未来变化
── AI 很少能达到这个级别
品味作为 Prompt 的一部分:
将品味要求写入 Prompt,提升 AI 输出质量:
"请实现订单服务,要求:
1. 使用有意义的业务命名(不要用 data, info 等模糊词)
2. 单一职责,每个方法只做一件事
3. 避免过度设计,只实现当前需求
4. 使用组合而非继承
5. 错误处理要语义化,不要吞异常
6. 代码要符合 DDD 的 Ubiquitous Language"
通过将品味显式化,AI 的输出质量会显著提升。
Taste 的培养路径:
1. 大量阅读高质量代码
- 开源项目:Redis, SQLite, Go stdlib, Spring
- 经典书籍:《Clean Code》《重构》《程序设计实践》
- 优秀团队的代码库
2. 大量实践和反思
- 同一功能写三遍,比较优劣
- 定期重构自己过去的代码
- 写代码日记:记录设计决策和理由
3. 深度参与代码审查
- 多审查别人的代码:学习"什么不该做"
- 多让别人审查自己的代码:发现"自己看不到的问题"
- 关注 PR 讨论中的设计决策
4. 跨领域学习
- 建筑设计:形式追随功能
- 工业设计:少即是多
- 写作:简洁、清晰、有节奏
- 好的设计原理是相通的
5. 在 AI 时代刻意练习
- 审查 AI 代码:找出 AI 的"品味缺陷"
- 对比 AI 方案和人工方案:理解差异
- 用品味指导 Prompt:将隐性的品味显性化
Taste-Driven 的陷阱:
⚠️ 过度追求品味可能导致:
- 过度设计(Over-engineering)
→ 为了"优雅"而引入不必要的抽象
- 个人偏好强加于团队
→ "我的品味比你的好"的心态
- 延误交付时间
→ 追求完美的代价
⚠️ AI 时代的特殊陷阱:
- 过度依赖 AI 导致品味退化
→ 长期不自己写代码,判断力下降
- 对 AI 生成质量"麻木"
→ 习惯了 AI 的平庸代码,降低标准
平衡之道:
- 团队达成一致的代码规范作为底线
- 在"足够好"和"完美"之间取舍
- 品味指导设计,但不要成为阻碍
- 保持自己写代码的习惯,维护品味
品味与流程的关系:
品味 vs 流程,不是非此即彼:
- 流程是下限 — 确保最差的代码也不会太差,可重复、可度量、可培训
- 品味是上限 — 让好的代码可以更好,不可度量、不可培训、只能培养
- 好团队 = 流程(保底)+ 品味(追求)
AI 时代:流程可以让 AI 执行(lint, format, test),品味只能由人类提供,品味越好的团队,AI 带来的收益越大
1.4 三种 TDD 的对比
| 维度 | Test-Driven | Spec-Driven | Taste-Driven |
|---|---|---|---|
| 驱动因素 | 测试用例 | 规约文档 | 个人判断 |
| 首要目标 | 正确性 | 精确性 | 优雅性 |
| 验证方式 | 自动化测试 | 形式化验证 / AI 执行 | 代码审查 |
| 学习成本 | 低 | 中(传统)/ 低(AI) | 长期积累 |
| 团队依赖 | 低 | 中 | 高(需共识) |
| 适用阶段 | 编码阶段 | 设计阶段 | 全阶段 |
| AI 时代角色 | 验证 AI 输出的正确性 | 将需求转化为 AI Prompt | 判断 AI 输出的质量 |
| 核心产出 | 可执行的测试套件 | 可执行的规约文档 | 高质量的代码库 |
二、Domain-Driven Design(DDD)
领域驱动设计
DDD 是 Eric Evans 在 2004 年提出的软件设计方法论,核心思想是将复杂业务逻辑的建模作为软件设计的核心。
2.1 核心概念
战略设计:
战略设计关注”大图景”,通过限界上下文划分领域边界,每个上下文内部有独立的领域模型。上下文之间通过上下文映射(Context Map)定义交互关系,如订单→库存通过事件驱动异步同步,订单→支付通过防腐层隔离。
战术设计:
战术设计关注”具体实现”,以聚合(Aggregate)为基本单位。聚合根(如 Order)作为唯一的外部访问入口,内部包含实体(OrderItem, Address)和值对象(Money, OrderStatus),通过一致性边界保证数据完整性。
2.2 限界上下文(Bounded Context)
限界上下文是 DDD 中最核心的概念之一。它定义了模型应用的边界,在边界内部保持统一的领域语言。
限界上下文的特征:
- 统一语言(Ubiquitous Language) — 每个上下文内有自己的术语体系,同一个词在不同上下文中含义可能不同
- 独立演进 — 每个上下文可以独立开发、部署,内部变化不影响外部
- 明确边界 — 通过上下文映射定义交互关系,使用防腐层(Anti-Corruption Layer)隔离
示例:电商系统中的”订单”
- 订单上下文(Order Context) — Order = { id, items, address, status, totalAmount },关注订单的创建、修改、状态流转
- 财务上下文(Finance Context) — Order = { id, amount, tax, invoiceNo },关注订单的结算、开票、对账
- 物流上下文(Logistics Context) — Order = { id, items, weight, destination, trackingNo },关注订单的仓储、配送、签收
同一个”订单”,在不同上下文中关注不同的属性。
2.3 聚合(Aggregate)
聚合是 DDD 中数据一致性的基本单位。
聚合设计原则:
- 聚合根(Aggregate Root) — 唯一的外部访问入口,通过聚合根保证内部一致性
- 一致性边界 — 聚合内部强一致性,聚合之间最终一致性
- 小聚合原则 — 聚合越小性能越好,聚合越大一致性越强
示例:订单聚合,Aggregate Root 为 Order,内部包含 OrderItem、Address 等实体以及 Money、OrderStatus 等值对象。外部只能通过 Order 访问 OrderItem,不能直接操作 OrderItem。
2.4 复杂业务架构腐化
架构腐化是指软件系统随着需求变更,逐渐偏离原始设计,变得越来越难以维护的过程。
架构腐化的症状:
- 上帝类(God Class) — 一个类做了太多事情,数百行甚至上千行的方法
- 霰弹式修改(Shotgun Surgery) — 修改一个需求要改 N 个文件,改漏一个就出 Bug
- 循环依赖(Circular Dependency) — A 依赖 B,B 依赖 C,C 依赖 A,无法独立理解任何一个模块
- 重复代码(Duplicated Code) — 相同逻辑散落在各处,改了一处忘了另一处
- 发散式变化(Divergent Change) — 一个类因不同原因被修改,违反单一职责原则
DDD 如何对抗腐化:
DDD 的防腐策略:
- 限界上下文隔离 — 防止不同领域的逻辑纠缠,上下文之间通过防腐层(ACL)转换
- 聚合约束 — 明确的数据一致性边界,防止随意绕过业务规则
- 领域事件驱动 — 松耦合的上下文间通信,事件日志可追溯
- 持续重构 — 战术设计支持渐进式改进,限界上下文内可独立重构
2.5 DDD 适用性判断
DDD 适合的场景: 业务逻辑复杂(如金融、电商、医疗)、需要长期迭代的核心系统、多个团队协作开发、业务规则频繁变化
DDD 不适合的场景: 简单的 CRUD 应用、原型验证阶段、小团队短周期项目、技术基础设施类系统
三、其他开发范式
3.1 BDD — Behavior-Driven Development
行为驱动开发
BDD 是 TDD 的演进,强调用自然语言描述系统行为,让非技术人员也能参与需求定义。
| 维度 | 说明 |
|---|---|
| 解决的核心问题 | 需求歧义、业务与代码脱节 |
| 核心产物 | .feature 文件(Gherkin 语法) |
| 关键实践 | 三方开会(Three Amigos) |
| 代表工具 | Cucumber, SpecFlow, Behat |
Gherkin 语法示例:
Feature: 用户登录
As a 注册用户
I want 登录系统
So that 访问我的个人数据
Scenario: 使用正确的凭证登录
Given 我已注册,账号为 "user@example.com",密码为 "pass123"
When 我在登录页输入账号 "user@example.com" 和密码 "pass123"
And 点击登录按钮
Then 我应该看到"欢迎回来"的提示
And 页面跳转到首页
Scenario: 使用错误的密码登录
Given 我已注册,账号为 "user@example.com"
When 我在登录页输入账号 "user@example.com" 和密码 "wrongpass"
And 点击登录按钮
Then 我应该看到"账号或密码错误"的提示
And 页面停留在登录页
BDD 工作流:
需求讨论 → 编写 Feature → 自动化测试 → 实现 → 验证,业务方参与需求讨论,三方会议确认场景,测试通过即需求完成。
BDD 在 AI 时代的价值:
BDD + AI 的协同效应:
- .feature 文件作为 AI Prompt — Gherkin 的结构化描述天然适合作为 Prompt,Given/When/Then 对应 AI 理解的三段式
- 自动化验证 — AI 生成代码后,运行 BDD 测试验证,测试通过即业务方需求满足
- 活文档自动化 — AI 可以维护 .feature 文件与代码的同步,减少文档维护成本
3.2 EDD — Example-Driven Development
示例驱动开发
EDD 通过具体示例来明确需求,消除模糊性。它常与 BDD 配合使用,但更强调”示例”本身。
| 维度 | 说明 |
|---|---|
| 解决的核心问题 | 需求模糊、沟通成本高 |
| 核心产物 | 示例表格(Example Tables) |
| 关键实践 | 用具体例子代替抽象描述 |
| 代表方法 | Specification by Example |
示例表格:
需求:计算订单折扣。规则:满 100 减 10,满 200 减 30,满 500 减 100,新用户额外 9 折,优惠券可叠加。
| 订单金额 | 是否新用户 | 优惠券 | 预期折扣 | 预期实付 |
|---|---|---|---|---|
| 50 | 否 | 无 | 0 | 50 |
| 150 | 否 | 无 | 10 | 140 |
| 250 | 是 | 无 | 30+25 | 195 |
| 600 | 否 | 20元 | 100+20 | 480 |
| 600 | 是 | 20元 | 100+60+20 | 420 |
通过具体示例,需求从”满减”这样模糊的描述,变成了可验证的精确期望。
EDD 与 BDD 的关系:
BDD = EDD + 自动化 + 协作流程。EDD 是 BDD 的子集,专注于”用示例明确需求”。BDD 在此基础上增加了协作流程(Three Amigos)、自动化测试框架(Cucumber)、活文档体系。
3.3 CDC — Contract-Driven Development
契约驱动开发
CDC 在微服务架构中尤为重要,通过明确定义服务间接口契约来保证集成质量。
| 维度 | 说明 |
|---|---|
| 解决的核心问题 | 微服务集成风险、接口不兼容 |
| 核心产物 | 接口契约文件 |
| 关键实践 | 消费者驱动契约(Consumer-Driven Contracts) |
| 代表工具 | OpenAPI, Protocol Buffers, Spring Cloud Contract |
契约示例:
# OpenAPI 3.0 契约示例
openapi: 3.0.0
info:
title: 订单服务 API
version: 1.0.0
paths:
/api/orders:
post:
summary: 创建订单
requestBody:
required: true
content:
application/json:
schema:
type: object
required: [userId, items]
properties:
userId:
type: string
pattern: "^U\\d{8}$"
items:
type: array
minItems: 1
items:
type: object
required: [productId, quantity]
properties:
productId:
type: string
quantity:
type: integer
minimum: 1
responses:
'201':
description: 订单创建成功
content:
application/json:
schema:
$ref: '#/components/schemas/Order'
'400':
description: 参数校验失败
契约测试 vs 集成测试:
- 契约测试(Contract Test) — 验证服务提供方是否符合契约,验证服务消费方是否按契约调用,独立运行,不依赖其他服务
- 集成测试(Integration Test) — 验证多个服务协作是否正常,依赖真实部署环境,运行慢,不稳定
推荐策略:契约测试 > 集成测试
3.4 FDD — Feature-Driven Development
特性驱动开发
FDD 是一种迭代式软件开发方法,以”特性”(Feature)为粒度进行规划、跟踪和交付。
| 维度 | 说明 |
|---|---|
| 解决的核心问题 | 交付不可预测、进度难以跟踪 |
| 核心产物 | 特性列表(Feature List) |
| 关键实践 | 按特性规划、按特性交付 |
| 适用规模 | 中大型团队 |
FDD 流程:
FDD 的五步流程:
- 开发整体模型(Develop Overall Model) — 领域建模,建立高层架构图
- 构建特性列表(Build Feature List) — 将需求分解为细粒度特性,格式:
<action> <result> <object> - 按特性规划(Plan by Feature) — 评估复杂度,排定优先级,分配特性到迭代
- 按特性设计(Design by Feature) — 每个特性进行详细设计,涉及序列图、类图
- 按特性构建(Build by Feature) — 编码 + 测试 + 评审,特性完成即交付
特性列表示例:
电商系统特性列表:
- F1: 用户注册新账号 | F2: 用户使用密码登录 | F3: 用户浏览商品列表
- F4: 用户按分类筛选商品 | F5: 用户搜索商品 | F6: 用户将商品加入购物车
- F7: 用户修改购物车商品数量 | F8: 用户提交订单 | F9: 用户在线支付订单
- F10: 用户查看订单状态
每个特性估计工时:F1: 2d, F2: 1d, F3: 1d, F4: 3d, F5: 5d, F6: 2d, F7: 1d, F8: 5d, F9: 8d, F10: 2d
迭代规划:Iteration 1: F1+F2+F3 (4d), Iteration 2: F4+F5+F6 (10d), Iteration 3: F7+F8 (8d), Iteration 4: F9+F10 (10d)
四、范式对比与选择
4.1 全景对比
| 范式 | 全称 | 驱动因素 | 解决痛点 | 核心产出 | 适用阶段 |
|---|---|---|---|---|---|
| TDD | Test-Driven | 测试用例 | 质量不可控、重构恐惧 | 自动化测试 | 编码 |
| SDD | Spec-Driven | 规约文档 | 需求歧义、合规性 | 形式化规约 / Prompt | 设计 |
| Taste-Driven | Taste-Driven | 个人品味 | 代码丑、设计差 | 优雅代码 | 全阶段 |
| DDD | Domain-Driven | 领域模型 | 业务复杂、架构腐化 | 领域模型 | 架构 |
| BDD | Behavior-Driven | 系统行为 | 需求歧义、沟通断层 | .feature 文件 | 需求 |
| EDD | Example-Driven | 具体示例 | 需求模糊、沟通成本 | 示例表格 | 需求 |
| CDC | Contract-Driven | 接口契约 | 微服务集成风险 | OpenAPI/proto | 接口 |
| FDD | Feature-Driven | 特性列表 | 交付不可预测 | 特性计划 | 管理 |
4.2 选择指南
按场景选择:
- 需求分析阶段 → BDD / EDD(用示例和行为明确需求)
- 架构设计阶段 → DDD / SDD(建模和规约)
- 接口设计阶段 → CDC(定义服务契约)
- 编码实现阶段 → TDD(测试驱动编码)
- 项目管理阶段 → FDD(按特性规划和跟踪)
- 全阶段 → Taste-Driven(品味贯穿始终)
按团队规模:
| 规模 | 推荐范式 | 原因 |
|---|---|---|
| 1-3 人 | TDD + Taste-Driven | 轻量,沟通成本低 |
| 5-10 人 | TDD + DDD + BDD | 需要规范和协作 |
| 10+ 人 | DDD + CDC + FDD | 需要架构治理和项目管理 |
按系统类型:
| 系统类型 | 推荐范式 |
|---|---|
| 业务核心系统 | DDD + TDD + BDD |
| 微服务系统 | CDC + DDD |
| 安全关键系统 | SDD + TDD |
| 原型/PoC | Taste-Driven |
| 遗留系统重构 | DDD + TDD |
4.3 范式组合实践
优秀的团队通常不是只用一种范式,而是根据场景组合使用:
- 需求阶段:BDD(.feature)+ EDD(示例表格)— 业务方参与,明确需求
- 架构阶段:DDD(限界上下文 + 聚合)— 领域建模,划清边界
- 接口阶段:CDC(OpenAPI 契约)— 服务间接口约定
- 实现阶段:TDD(红-绿-重构)— 测试驱动编码
- AI 协作阶段:SDD(规约即 Prompt)— 用规约指导 AI 生成代码
- 贯穿始终:Taste-Driven — 保持代码品味
五、总结
软件开发范式的发展历程,本质上是对软件生产过程中各种不确定性的应对:
| 不确定性 | 对应范式 | 应对策略 |
|---|---|---|
| 需求不确定 | BDD / EDD | 用示例和行为明确需求 |
| 设计不确定 | DDD / SDD | 用领域模型和规约指导设计 |
| 质量不确定 | TDD | 用自动化测试保障质量 |
| 集成不确定 | CDC | 用契约定义接口协议 |
| 进度不确定 | FDD | 用特性粒度管理交付 |
| 审美不确定 | Taste-Driven | 用开发者品味提升质量 |
AI 时代的新视角:
AI 改变了”谁来做”,但没改变”该做什么”。
- TDD 仍然需要 — 验证 AI 生成代码的正确性
- SDD 变得更重要 — 规约即 Prompt,决定 AI 输出质量
- Taste-Driven 成为核心 — 品味是开发者最后的壁垒
- DDD 依然有效 — 复杂业务需要领域建模
- BDD/EDD 持续存在 — 需求沟通永远需要
- CDC 更加关键 — AI 生成代码的接口一致性
- FDD 适应变化 — AI 加速了特性交付
选择范式时记住一句话: 没有银弹。每种范式都有其适用场景和局限,理解其核心思想,结合团队和项目实际,灵活组合才是最佳实践。