重构软件开发的权力格局:从TDD、DDD到AI时代的SDD,哪种才是你的工程哲学?
十年前,TDD让我们重写测试如同推翻巴别塔;三年前,DDD试图用领域语言统一产品与技术的分歧;今天,SDD直接把“规范”变成可执行的源代码,AI成为这个新世界的翻译官。
上周团队来了个新人,对着我们基于DDD设计的微服务架构一脸困惑:“这服务划分的依据是什么?这个聚合根的边界怎么定的?”我让他看领域文档,他翻了几页:“这些和代码对不上啊,上次重构后就没更新了吧?”
这一瞬间,我突然意识到,我们可能站在又一个范式革命的临界点。
01 演化史:从测试优先到规范即代码
2000年左右,Kent Beck提出TDD时,它的核心很激进:先写测试,再写实现。这在当时绝对是个异类——哪有还没写代码就先想怎么测试的?
可问题恰恰在这里:传统开发中,测试往往是最后一步,经常被挤压甚至忽略。
TDD的诞生,本质上是对“测试是二等公民”这一现状的反抗。它不只是个技术实践,更是一种开发哲学:通过可执行的测试用例来明确需求。
#mermaid-svg-vJuH7GTsXzTrDsru{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-vJuH7GTsXzTrDsru .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-vJuH7GTsXzTrDsru .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-vJuH7GTsXzTrDsru .error-icon{fill:#552222;}#mermaid-svg-vJuH7GTsXzTrDsru .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-vJuH7GTsXzTrDsru .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-vJuH7GTsXzTrDsru .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-vJuH7GTsXzTrDsru .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-vJuH7GTsXzTrDsru .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-vJuH7GTsXzTrDsru .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-vJuH7GTsXzTrDsru .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-vJuH7GTsXzTrDsru .marker{fill:#333333;stroke:#333333;}#mermaid-svg-vJuH7GTsXzTrDsru .marker.cross{stroke:#333333;}#mermaid-svg-vJuH7GTsXzTrDsru svg{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-vJuH7GTsXzTrDsru p{margin:0;}#mermaid-svg-vJuH7GTsXzTrDsru .label{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;color:#333;}#mermaid-svg-vJuH7GTsXzTrDsru .cluster-label text{fill:#333;}#mermaid-svg-vJuH7GTsXzTrDsru .cluster-label span{color:#333;}#mermaid-svg-vJuH7GTsXzTrDsru .cluster-label span p{background-color:transparent;}#mermaid-svg-vJuH7GTsXzTrDsru .label text,#mermaid-svg-vJuH7GTsXzTrDsru span{fill:#333;color:#333;}#mermaid-svg-vJuH7GTsXzTrDsru .node rect,#mermaid-svg-vJuH7GTsXzTrDsru .node circle,#mermaid-svg-vJuH7GTsXzTrDsru .node ellipse,#mermaid-svg-vJuH7GTsXzTrDsru .node polygon,#mermaid-svg-vJuH7GTsXzTrDsru .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-vJuH7GTsXzTrDsru .rough-node .label text,#mermaid-svg-vJuH7GTsXzTrDsru .node .label text,#mermaid-svg-vJuH7GTsXzTrDsru .image-shape .label,#mermaid-svg-vJuH7GTsXzTrDsru .icon-shape .label{text-anchor:middle;}#mermaid-svg-vJuH7GTsXzTrDsru .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-vJuH7GTsXzTrDsru .rough-node .label,#mermaid-svg-vJuH7GTsXzTrDsru .node .label,#mermaid-svg-vJuH7GTsXzTrDsru .image-shape .label,#mermaid-svg-vJuH7GTsXzTrDsru .icon-shape .label{text-align:center;}#mermaid-svg-vJuH7GTsXzTrDsru .node.clickable{cursor:pointer;}#mermaid-svg-vJuH7GTsXzTrDsru .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-vJuH7GTsXzTrDsru .arrowheadPath{fill:#333333;}#mermaid-svg-vJuH7GTsXzTrDsru .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-vJuH7GTsXzTrDsru .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-vJuH7GTsXzTrDsru .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-vJuH7GTsXzTrDsru .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-vJuH7GTsXzTrDsru .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-vJuH7GTsXzTrDsru .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-vJuH7GTsXzTrDsru .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-vJuH7GTsXzTrDsru .cluster text{fill:#333;}#mermaid-svg-vJuH7GTsXzTrDsru .cluster span{color:#333;}#mermaid-svg-vJuH7GTsXzTrDsru div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-vJuH7GTsXzTrDsru .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-vJuH7GTsXzTrDsru rect.text{fill:none;stroke-width:0;}#mermaid-svg-vJuH7GTsXzTrDsru .icon-shape,#mermaid-svg-vJuH7GTsXzTrDsru .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-vJuH7GTsXzTrDsru .icon-shape p,#mermaid-svg-vJuH7GTsXzTrDsru .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-vJuH7GTsXzTrDsru .icon-shape rect,#mermaid-svg-vJuH7GTsXzTrDsru .image-shape rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-vJuH7GTsXzTrDsru .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-vJuH7GTsXzTrDsru .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-vJuH7GTsXzTrDsru :root{–mermaid-font-family:\”trebuchet ms\”,verdana,arial,sans-serif;}
2000 左右:TDD测试驱动开发(先写测试,再写实现)
2003:BDD行为驱动开发(Given-When-Then)
2003:DDD领域驱动设计(限界上下文、通用语言)
2010s:敏捷 & 微服务落地与TDD/DDD深度结合
2020+:SDD & AI 时代规范即代码,AI生成实现
大约2003年,Dan North在TDD基础上提出了BDD。他发现许多开发者和业务人员对“测试”这个词有心理抵触,于是把焦点从“测试”转移到“行为”上。
BDD的核心是用业务人员和开发者都能理解的自然语言描述系统行为。那时候流行的工具是Cucumber,那些“Given-When-Then”的语句,我第一次见到时觉得“这玩意儿太形式主义了吧”。
有趣的是,DDD在同一时期也在兴起。Eric Evans在2003年出版的《领域驱动设计》中,直击了当时企业软件开发的核心痛点:业务逻辑与技术实现之间的巨大鸿沟。
回忆一下:你们团队的产品经理有没有说过“这个需求很简单,就加个按钮”?技术实现时才发现背后涉及三个服务的数据一致性?
DDD的核心理念是用“通用语言” 在业务和技术团队间建立沟通桥梁,通过战略设计和战术设计,让软件结构反映业务本质。
02 SDD:AI时代的新范式
到了AI编程时代,问题变得更加尖锐。SDD正是在这样的背景下崛起的。
SDD的核心是规范即真理,代码只是规范在特定语言和框架中的表达。
这不只是个技术上的小调整,而是权力关系的根本反转。
几十年来,代码一直是软件开发的核心资产。PRD、设计文档这些“规范”类的东西,往往是写出来就没人看,代码改了一轮又一轮,文档还停留在最初版本。
SDD打破了这种局面:规范成为单一事实来源。
更重要的是,现在的AI已经能理解并实现复杂的规范。规范不再只是给人看的文档,而是可以直接“喂”给AI生成代码的“可执行蓝图”。
03 理念差异:四种方法的核心对比
| TDD | 代码正确性 | 测试用例 + 实现代码 | 函数/模块级别开发 | JUnit, pytest, Mocha |
| BDD | 系统行为 | 行为描述 + 可执行规格 | 端到端功能验收 | Cucumber, Behave, SpecFlow |
| DDD | 业务领域建模 | 领域模型 + 限界上下文 | 复杂业务系统设计 | 无特定工具,是一套方法论 |
| SDD | 规范完整性 | 可执行规范 + 生成代码 | AI辅助的现代开发 | OpenSpec, Spec Kit, BMad |
TDD像是在拼图:你先确定每一块的边缘形状(测试),再去找能匹配的图案(实现代码)。
它的局限性也很明显:测试用例毕竟只是“点”的验证,难以确保整体业务逻辑的连贯性。
BDD前进了一步,它关注的是“用户能看到什么,系统应该有什么行为”。
但我得实话实说:在不少项目中,那些精心编写的.feature文件最后变成了另一种形式的“过时文档”,因为维护成本太高。
DDD试图解决更深层的问题:如何让软件架构反映业务本质?它提出了限界上下文、实体、值对象、聚合、领域服务等一系列概念,试图在业务复杂度和技术实现之间建立映射关系。
实际项目中,DDD最难的不是概念理解,而是如何保持领域模型与代码实现的一致性。
模型讨论会上画了一堆精美的图,两周后代码就偏离了最初的设计——这场景熟悉吗?
SDD采取了截然不同的路径。它不试图让代码去“反映”某个模型,而是让规范成为事实来源,代码只是规范的“快照式实现”。
说得更直白点:在SDD中,如果你要改功能,不是直接改代码,而是改规范,然后重新生成代码。
04 实战场景:何时用哪种方法?
适用TDD的场景
我一般会在这些情况下用TDD:
- 算法实现:比如写个复杂的排序算法或者数据处理逻辑
- 工具库开发:确保每个函数在各种边界条件下都正确
- 遗留代码重构:加测试保护已有的行为
# 典型的TDD流程示例:实现一个字符串计算器
# 1. 先写测试
def test_empty_string_returns_zero():
assert add("") == 0
def test_single_number_returns_itself():
assert add("1") == 1
def test_two_numbers_comma_delimited():
assert add("1,2") == 3
# 2. 实现最简单的可通过代码
def add(numbers: str) –> int:
if not numbers:
return 0
if "," in numbers:
nums = numbers.split(",")
return int(nums[0]) + int(nums[1])
return int(numbers)
适用BDD的场景
BDD更适合这些场景:
- 团队有业务分析师参与:需要共同理解需求
- 新功能验收:确保开发的功能符合业务期望
- 端到端测试:用户关键路径的验证
适用DDD的场景
DDD的用武之地:
- 业务复杂度高的系统:电商、金融、供应链等领域
- 长期演进的项目:需要清晰的架构应对变化
- 多团队协作:需要明确的上下文边界
适用SDD的场景
根据参考材料,SDD特别适合:
- AI辅助开发项目:让AI在清晰的规范约束下工作
- 增量开发场景:在现有系统上添加功能,需要AI理解项目现状
- 需要高度一致性的项目:规范作为单一事实来源,确保文档与代码同步
一个典型的SDD工作流,就像材料中描述的OpenSpec流程:
05 范式融合:实际项目中的混合策略
在真实项目中,我很少只用一种方法。更常见的是根据项目的不同阶段和不同部分,选择合适的方法组合。
以我们现在做的一个电商平台为例:
- 支付领域:用DDD建模,因为业务规则复杂,有清晰的限界上下文(订单上下文、支付上下文、库存上下文)
- 支付接口:用TDD确保各种异常情况处理正确
- 用户下单流程:用BDD描述关键路径
- 新的推荐算法模块:尝试用SDD,因为可以让AI在明确的性能规范和算法约束下生成代码
更关键的是,这些方法之间并不互斥。完全可以在SDD的规范中,包含TDD的测试要求,描述DDD的领域概念。
06 SDD的挑战:理想与现实的差距
别把SDD想得太美好,实际落地有不少坑:
规范维护成本:写得好的规范需要时间精力,不比手写代码轻松。写得不好的规范,生成的代码质量可想而知。
AI的局限性:现在的AI还是可能生成有安全隐患的代码、性能不佳的实现,或者完全误解你的意图。你还是得是个有经验的开发者,能看出问题在哪。
团队适应成本:让团队接受“不改代码改规范”这种思维转变,不是一两天的事。很多人第一反应是:“我直接改代码不是更快?”
不过有意思的是,SDD某种程度上也让DDD的理念更容易落地。
想想看:如果你的领域模型就是规范的一部分,那么AI生成的代码自然会遵循这个模型。这比手动确保几十个开发人员都正确理解领域模型,要可靠得多。
我们正处在一个转折点。SDD的出现,与其说是对TDD、BDD、DDD的否定,不如说是在AI时代对这些思想的延续和重新诠释。
它用一种更彻底的方式,试图解决软件工程中那个永恒的问题:如何确保我们的意图被准确地实现。
当你在代码仓库的specs/目录下,看到那份用精确语言描述的系统规范,而旁边的代码文件只是这份规范的“衍生品”时,也许会感受到一丝震撼。
技术演进的本质,是对抽象层次的不断向上推移。从机器码到汇编,到高级语言,到面向对象,到领域驱动,现在到规范驱动——每一步,我们都把更多“意图”直接表达出来,让机器去处理实现的细节。
这个趋势不会停止。也许有一天,我们会用更接近人类思考的方式“编写”软件,而今天这些DDD、SDD的讨论,也会成为技术史中一段有趣的注脚。

