设计评审清单

设计评审清单用于在动手写代码之前,对技术方案做系统性审视。目标是在开发前发现问题,而不是在测试或上线后补救。

要点

  • 设计评审在写代码之前进行,针对影响范围超过单模块的改动
  • 评审不是挑错,是提前发现问题、统一认知
  • 评审前必须准备材料:问题陈述、目标、方案、取舍、影响范围、风险
  • 重点检查:目标可衡量、方案可行、兼容性、异常处理、可观测性、回滚方案

1. 适用时机

需要设计评审的场景:

  • 新功能开发(影响范围超过单个模块)
  • 已有功能的重大改动(改 API、改数据结构、改业务流程)
  • 跨团队协作的需求(涉及多个团队或外部系统)
  • 引入新技术或第三方依赖

不需要设计评审的场景:

  • 修 bug(但需要查清根因)
  • 纯 UI 调整(不影响业务逻辑)
  • 配置变更(有回滚方案即可)

2. 评审前准备

评审不是临时拉会讨论。发起人需要提前准备以下材料,否则评审会沦为泛泛而谈。

必须准备

  • 问题陈述:要解决什么问题?为什么要现在解决?不解决会怎样?
  • 目标与非目标:这次改动要达成什么,明确不做什么
  • 方案描述:打算怎么做?至少给一个具体方案
  • 取舍说明:为什么选这个方案?考虑过哪些替代方案?各自优缺点?
  • 影响范围:涉及哪些模块、接口、数据表、依赖方?
  • 风险评估:可能出什么问题?最坏情况是什么?
  • 验证方式:怎么判断方案有效?上线后看什么指标?

可选但推荐

  • 时序图/流程图:复杂交互用图比文字清楚
  • 数据量估算:预估数据规模、QPS、存储需求
  • 时间估算:开发、联调、测试、灰度、全量各需要多久

3. 核心检查项

3.1 问题与目标

  • 问题陈述清晰,不是「优化一下」这种模糊描述
  • 目标可衡量(「响应时间从 2s 降到 500ms」而不是「提升性能」)
  • 非目标明确,避免评审过程中范围蔓延
  • 成功标准定义清楚,上线后能判断是否达成

3.2 方案可行性

  • 技术选型合理,不是「因为流行所以用」
  • 现有团队能维护这个方案,不是「只有作者能看懂」
  • 时间估算合理,不是「这周一定能上」
  • 不依赖尚未就绪的外部条件(别人还没开发好的接口、还没采购的服务)

Hono 示例:技术选型的判断

// 不好的选型理由
// 「因为 Express 流行所以用 Express」
 
// 好的选型理由
// 1. 团队熟悉 Hono,学习成本低
// 2. Hono 支持 Cloudflare Workers,符合边缘部署需求
// 3. Hono 性能优于 Express,P99 延迟更低
// 4. Hono 有 OpenAPI 集成,文档自动生成
 
import { Hono } from 'hono'
 
const app = new Hono()
 
// 选型决策记录
// 选择:Hono + Cloudflare Workers
// 放弃:Express + Node.js
// 理由:边缘部署延迟更低(< 50ms vs 200ms)

3.3 兼容性与迁移

  • 对现有功能无破坏(或明确列出破坏性变更,给迁移方案)
  • 数据迁移方案完整(旧数据怎么办、能否回滚、需要多长时间)
  • API 兼容性考虑(老客户端能不能继续用、是否需要版本化)
  • 配置变更平滑过渡(新旧配置能否共存)

Hono 示例:API 版本化

import { Hono } from 'hono'
 
const app = new Hono()
 
// v1 API - 保持兼容
const v1 = new Hono()
v1.get('/users', (c) => {
  return c.json({ users: [] })
})
 
// v2 API - 新增字段,不删除旧字段
const v2 = new Hono()
v2.get('/users', (c) => {
  return c.json({
    users: [],
    pagination: { page: 1, total: 100 } // 新增字段
  })
})
 
// 路由挂载
app.route('/api/v1', v1)
app.route('/api/v2', v2)
 
// 废弃通知
app.get('/api/v1/users', (c, next) => {
  c.header('Deprecation', 'true')
  c.header('Sunset', 'Sat, 01 Jan 2027 00:00:00 GMT')
  return next()
})

3.4 边界与异常

  • 主路径走通,正常情况没问题
  • 异常路径有处理(网络失败、第三方挂了、数据异常)
  • 并发场景考虑(多用户同时操作、重复提交)
  • 大数据量场景考虑(分页、批处理、索引)
  • 安全边界清楚(谁能访问、谁能修改、敏感数据如何处理)

Hono 示例:异常处理

import { Hono } from 'hono'
import { HTTPException } from 'hono/http-exception'
 
const app = new Hono()
 
// 统一的错误处理
app.onError((err, c) => {
  console.error('Unhandled error:', err)
 
  if (err instanceof HTTPException) {
    return c.json({
      code: err.message,
      message: '请求处理失败',
      details: err.name
    }, err.status)
  }
 
  return c.json({
    code: 'INTERNAL_ERROR',
    message: '服务内部错误',
    details: process.env.NODE_ENV === 'development' ? err.message : undefined
  }, 500)
})
 
// 业务异常
app.post('/orders', async (c) => {
  const body = await c.req.json()
 
  // 库存检查
  const stock = await checkStock(body.productId)
  if (stock < body.quantity) {
    throw new HTTPException(409, { message: 'INSUFFICIENT_STOCK' })
  }
 
  // 并发控制:幂等键防止重复提交
  const idempotencyKey = c.req.header('Idempotency-Key')
  if (idempotencyKey) {
    const existing = await c.env.KV.get(`order:${idempotencyKey}`)
    if (existing) {
      return c.json(JSON.parse(existing), 200)
    }
  }
 
  // 创建订单
  const order = await createOrder(body)
 
  // 保存幂等键
  if (idempotencyKey) {
    await c.env.KV.put(
      `order:${idempotencyKey}`,
      JSON.stringify(order),
      { expirationTtl: 86400 }
    )
  }
 
  return c.json(order, 201)
})

3.5 可观测性

  • 关键操作有日志,出了问题能排查
  • 核心指标有监控,能发现问题(错误率、延迟、QPS)
  • 关键流程有追踪(trace id 贯穿)
  • 异常有告警,不用等用户反馈

Hono 示例:日志与追踪

import { Hono } from 'hono'
import { logger } from 'hono/logger'
 
const app = new Hono()
 
// 请求日志
app.use('*', logger())
 
// 自定义中间件:添加 trace id
app.use('*', async (c, next) => {
  const traceId = c.req.header('X-Trace-ID') || crypto.randomUUID()
  c.set('traceId', traceId)
  c.header('X-Trace-ID', traceId)
 
  const start = Date.now()
  await next()
  const duration = Date.now() - start
 
  // 结构化日志
  console.log(JSON.stringify({
    traceId,
    method: c.req.method,
    path: c.req.path,
    status: c.res.status,
    duration,
    timestamp: new Date().toISOString()
  }))
})
 
app.get('/orders/:id', async (c) => {
  const traceId = c.get('traceId')
  const orderId = c.req.param('id')
 
  // 日志带 trace id
  console.log(JSON.stringify({
    traceId,
    event: 'order.fetch',
    orderId
  }))
 
  const order = await getFromDatabase(orderId)
 
  if (!order) {
    console.log(JSON.stringify({
      traceId,
      event: 'order.not_found',
      orderId
    }))
    return c.json({ code: 'ORDER_NOT_FOUND' }, 404)
  }
 
  return c.json(order)
})

3.6 测试与验证

  • 单元测试覆盖核心逻辑
  • 集成测试覆盖关键路径
  • 有灰度方案(不是「一次全上」)
  • 有回滚方案(发现问题能在 15 分钟内恢复)
  • 上线后的验证步骤明确(谁、做什么、看什么指标)

Hono 示例:灰度发布

import { Hono } from 'hono'
 
const app = new Hono()
 
// Feature Flag 中间件
app.use('/api/new-feature/*', async (c, next) => {
  const userId = c.get('userId')
 
  // 从 KV 读取灰度配置
  const config = await c.env.KV.get('feature:new-feature', 'json')
  const { enabled, percentage, whitelist } = config || {
    enabled: false,
    percentage: 0,
    whitelist: []
  }
 
  // 白名单用户
  if (whitelist.includes(userId)) {
    c.set('featureEnabled', true)
    return next()
  }
 
  // 按比例灰度
  const hash = userId.charCodeAt(0) % 100
  if (enabled && hash < percentage) {
    c.set('featureEnabled', true)
    return next()
  }
 
  c.set('featureEnabled', false)
  return next()
})
 
app.get('/api/new-feature/data', (c) => {
  const enabled = c.get('featureEnabled')
 
  if (!enabled) {
    // 返回旧版本数据
    return c.json({ version: 'v1', data: [] })
  }
 
  // 返回新版本数据
  return c.json({ version: 'v2', data: [] })
})

3.7 文档与沟通

  • 设计文档写清楚,新同学能看懂
  • 依赖方已沟通(涉及别人的接口、数据、资源)
  • 上下游已知晓影响(客服、运营、产品)
  • 有变更公告或通知(对用户有影响的改动)

4. 评审会上容易漏的点

评审会上大家常常关注主路径和技术细节,忽略以下几个点。主持人可以逐项过一遍。

  1. 回滚方案:问一句「如果上线后发现问题,怎么回滚?需要多久?」很多人没想过
  2. 监控告警:问「怎么知道出了问题?」如果答案是「用户反馈」,说明可观测性没做好
  3. 数据迁移:问「旧数据怎么办?」经常有人只想到了新逻辑,忘了旧数据
  4. 依赖方:问「这个改动影响谁?他们知道吗?」跨团队问题常在这里暴露
  5. 成功标准:问「上线一周后,怎么判断这次改动是成功的?」没人看指标等于白做

5. 通过标准

设计评审不是投票,但有共识才能往下走。以下情况算通过:

  • 问题陈述、目标、方案三方认可
  • 关键风险已识别,有应对措施
  • 影响范围清楚,依赖方已沟通
  • 验证方式和成功标准明确
  • 回滚方案可行
  • 评审意见已记录,未解决的问题有跟进人

6. 不通过的情况

以下情况应该打回重做,不要硬上:

  • 问题陈述模糊,没人知道为什么要做
  • 方案不可行(技术、时间、资源都不允许)
  • 关键风险未识别,或识别了没应对
  • 影响范围不清,依赖方没沟通
  • 没有回滚方案,出问题只能硬扛

7. 维护建议

这份清单不是一成不变的。每次评审后,回顾一下:

  • 这次评审有没有漏掉的点?加进清单
  • 哪些检查项其实不重要?可以降级或删除
  • 哪些项目需要按团队特点调整?(比如 AI 项目要加「prompt 管理」「模型成本」等检查项)

清单的维护者和最近一次更新时间应该记录在文档末尾,便于追溯。