项目文章联系
← 返回文章列表
技术实践2026-07-16

将代码审查集成到 SDD:从需求设计到质量门禁的工程实践

很多团队并不是没有 Code Review,而是审查发生得太晚、标准不一致、反馈也缺少统一处理方式。

这篇文章介绍如何将标准化代码审查 CR 集成到 SDD,也就是 Spec-Driven Development,需求驱动开发流程中。

核心思想是:

SDD 负责定义应该实现什么以及如何设计,Spec-CR 负责验证实际实现是否符合设计、是否安全可靠、是否具备长期维护条件。

一、先定义要解决的问题

研发任务至少包含四类信息:

需求:用户需要什么
设计:系统准备如何实现
代码:实际实现了什么
验证:实现是否满足要求

如果这四类信息没有关联,就容易出现四种问题:

  • 实现偏离需求;
  • 代码绕过既定架构;
  • API 和数据模型与契约不一致;
  • 审查标准依赖个人经验。

因此,真正需要解决的不是要不要做 Code Review,而是三个问题:

1. 什么时候必须审查?

2. 审查时应该检查什么?

3. 收到反馈后如何判断、修复?

二、SDD 与 Spec-CR 的分工

SDD 的核心是先把需求和设计结构化,再进入实现阶段。

一个典型的 SDD 产物包括:

spec.md :为什么做、做什么、验收标准是什么
plan.md :系统如何分层、模块如何协作 
data-model.md : 数据结构和关系是什么             
contracts/ :API、事件或模块接口如何约定      
tasks.md :具体拆分成哪些任务

Spec-CR 则验证实现阶段和交付阶段:

  • 代码是否实现了 spec 中的需求;
  • 模块划分是否符合 plan;
  • 数据模型和接口是否符合约定;
  • 是否存在运行时缺陷;
  • 是否存在安全和并发风险;
  • 代码是否已经复杂到难以维护;
  • 反馈是否被合理验证和处理。

两者可以表示为:

spec.md
   ↓
plan.md / data-model.md / contracts
   ↓
tasks.md
   ↓
代码实现与测试
   ↓
Spec-CR 审查
   ↓
修复、验证、阶段交付

三、完整研发闭环

一个阶段的完整流程可以设计为:

需求澄清
   ↓
编写 spec
   ↓
制定 plan
   ↓
定义数据模型和接口契约
   ↓
拆分 tasks
   ↓
逐任务开发与自测
   ↓
提交代码
   ↓
阶段代码审查
   ↓
修复并验证
   ↓
进入下一阶段

项目全部阶段完成后,再执行一次全量审查。阶段审查关注局部实现是否可靠,全量审查关注跨模块契约、重复实现、临时方案和部署配置。

四、代码审查的触发时机

阶段完成时强制审查

当一个开发阶段的全部任务完成后,执行阶段审查:

/speckit.codereview Phase X

阶段审查的作用是阻止问题进入下一阶段。比如,一个阶段负责权限和数据接口,如果阶段结束时没有检查越权、错误处理和接口契约,后续页面开发可能建立在错误接口之上。

全项目完成时强制审查

当所有阶段完成后,执行:

/speckit.codereview all

全量审查不只是重复阶段审查,还要检查跨模块问题:

  • 模块之间的契约是否一致;
  • 是否存在跨模块权限漏洞;
  • 是否有临时方案没有清理;
  • 文档、代码和测试是否仍然一致。

高风险功能完成后主动审查

权限、认证、敏感数据、并发、事务、文件上传、网络访问、复杂 Bug 修复和大规模重构,都适合提前审查。

五、审查范围如何确定

推荐按以下优先级确定范围:

用户明确指定的 commit、文件或阶段
              ↓
Git 提交和工作区变更文件
              ↓
根据 tasks.md 推断关联文件

审查报告应该明确写出审查范围,避免审查者和开发者对“这次到底审了什么”产生误解。

六、审查的四个维度

1. 规范合规

先对照 spec、plan、data-model 和 contracts:

  • 用户故事是否完整实现;
  • 验收标准是否满足;
  • 模块是否放在正确分层;
  • 数据字段、API 请求和响应是否一致;
  • 是否增加了需求没有要求的复杂功能。

2. 基础代码质量

重点关注:

  • 异常是否被吞掉;
  • 异步是否有错误处理;
  • 网络、文件和数据库操作是否处理失败;
  • 是否存在 N+1 查询、无限集合和主线程阻塞;
  • 是否处理空值、空数组、除零、超长输入和合法的 0 值。

3. 安全与并发可靠性

重点关注:

  • XSS、SQL 注入、路径遍历和 SSRF;
  • IDOR 越权和缺失的服务端权限校验;
  • 密钥硬编码和敏感日志;
  • 依赖漏洞和资源耗尽;
  • 无锁共享状态、缺失事务和竞态条件。

4. 设计与可维护性

关注真实维护成本:

  • 函数是否承担太多职责;
  • 类是否变成上帝类;
  • 是否出现魔法值和死代码;
  • 是否过度抽象;
  • 抽象是否真的有多个使用场景;
  • 是否依赖具体实现而不是稳定接口。

七、收到反馈后的六步流程

开发者不要看到一条反馈就立刻修改。推荐顺序是:

通读全部反馈
    ↓
复述并澄清问题
    ↓
回到代码验证
    ↓
判断建议是否适用
    ↓
按优先级修复
    ↓
逐项测试验证

审查意见是待验证的判断,不是自动成立的事实。需要确认问题是否真实存在、是否可以复现、是否已经被其他层覆盖,以及建议是否符合业务上下文。

问题可以分成四级:

| 等级 | 典型问题 | 处理策略 |

| ---- | ------------------------ | ---------------------- |

| P0 | 崩溃、安全漏洞、数据损坏 | 立即修复并阻塞流程 |

| P1 | 逻辑错误、严重性能退化 | 当前任务完成前修复 |

| P2 | 一般质量问题 | 当前修复或创建跟踪任务 |

| P3 | 优化建议 | 可选或集中治理 |

每个修复都要有验证结果。比如,发现接口存在越权风险,不只是增加一行判断,还要补充非资源所有者访问测试。

八、如何处理不合理反馈

Code Review 不是审查者单方面下结论。以下情况可以基于事实推回:

  • 采纳建议会破坏已有功能;
  • 审查者不了解完整业务上下文;
  • 建议与项目架构或技术栈冲突;
  • 引入的复杂度高于它解决的问题。

推荐这样回复:

当前实现的行为是……
这样设计的原因是……
如果改成建议方案,会导致……
因此本次暂不采纳。
如果未来出现……场景,再考虑引入该抽象。

例如,目前一个策略只有一个稳定调用方,增加策略模式不会减少重复代码,反而会增加配置和测试成本,那么可以保留直接实现,等出现第二种策略时再抽象。

九、如何集成到 SDD 项目

建议把审查记录和 SDD 文档放在同一套项目结构中:

spec.md
plan.md
data-model.md
contracts/
tasks.md
reviews/
├── phase-1.md
├── phase-2.md
└── final.md

项目约定可以包括:

1. 没有执行验证命令,不声明任务完成;

2. 阶段任务全部完成后,必须执行阶段审查;

3. P0 和 P1 未关闭时,不进入下一阶段;

4. P2 和 P3 必须决定当前修复还是创建跟踪任务;

5. 最终审查必须覆盖跨模块契约和部署配置;

6. 审查报告记录范围、发现、修复和验证结果。

任务流可以写成:

读取 spec 和 plan
    ↓
确认 task 的验收标准
    ↓
编码与单元测试
    ↓
提交代码
    ↓
必要时执行单任务审查
    ↓
阶段完成后执行 Phase X 审查
    ↓
修复 P0/P1 并重新验证
    ↓
进入下一阶段

十、一个完整案例

假设某阶段实现“用户查看订单详情”。

spec 要求:

  • 用户只能查看自己的订单;
  • 订单不存在时返回明确错误;
  • 订单列表支持分页;
  • 数据接口返回统一错误结构。

plan 要求:

  • Controller 负责参数接收;
  • Service 负责业务判断;
  • Repository 负责数据访问;
  • 权限校验必须在服务端完成。

审查发现三个问题:

P0:存在越权风险

代码直接使用客户端传入的 orderId 查询数据,没有验证订单是否属于当前用户。

修复方式:

  • 从服务端登录上下文取得 userId;
  • 查询时同时使用 orderId 和 userId;
  • 增加其他用户访问订单的失败测试。

P1:列表没有分页

数据访问层直接返回全部订单,数据量增大后可能造成内存和响应时间问题。

修复方式:

  • 增加 page 和 pageSize;
  • 限制最大 pageSize;
  • 增加数据库排序和索引;
  • 增加大数据量测试。

P2:Controller 直接调用 Repository

这违反了 plan 中的分层约定,但当前不影响功能。

处理方式:

  • 当前阶段完成 Service 层迁移;
  • 如果迁移范围较大,则建立跟踪任务;
  • 不为了修复一个 P2 问题而引入未经验证的大规模重构。

这个案例体现了三层校验:

需求合规:权限是否符合 spec
架构合规:调用层次是否符合 plan
运行质量:分页、边界和安全是否可靠

十一、如何判断体系是否有效

流程建立之后,还需要观察结果:

  • 阶段审查发现的问题数量;
  • P0/P1 问题比例;
  • 合并后才发现的问题数量;
  • 审查反馈平均处理时间;
  • 审查修复引入的回归缺陷;
  • P2/P3 跟踪任务关闭率;
  • 需求、契约与实现不一致的次数。

不要把“发现问题越多”简单等同于成功。早期问题数量增加,可能只是审查能力变强。更重要的是观察高风险问题是否更早被发现,线上缺陷和返工成本是否下降。

结语

SDD 和代码审查不是两套独立流程。

SDD 通过 spec、plan、data-model、contracts 和 tasks 明确:

为什么做
做什么
如何设计
如何验收

Spec-CR 则进一步验证:

实现是否符合需求
代码是否符合架构
运行时是否安全可靠
反馈是否被合理处理
修复是否经过验证

最终形成的质量闭环是:

需求
  → 设计
  → 任务
  → 实现
  → 自测
  → 阶段审查
  → 修复验证
  → 全量审查
  → 交付

一套有效的代码审查体系,不是增加更多表格,也不是让审查者拥有更大的权力,而是让团队在同一套需求、架构和验证标准上讨论代码。

当审查有明确触发点,标准可以被复用,反馈必须经过验证,P0/P1 问题能够阻止流程继续,代码质量就不再依赖某个“经验丰富的人刚好看到了问题”,而会成为研发流程本身的一部分。

参考资料