# Spec Writing

> 需为非平凡功能/重构写设计文档（spec/design doc/RFC）时。

- Skill: `lion-1209/spec-writing` (Agent Skill, multi-file: 2 files)
- Install (CLI): `npx skillmds@latest add lion-1209/spec-writing`
- Raw SKILL.md: https://api.skillmd.com/api/skills/lion-1209/spec-writing/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Coding & Dev Tools
- Author: Lion-1209 (https://skillmd.com/u/lion-1209)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/lion-1209/spec-writing

---


# Spec Writing

## 概述

把一个还没动手的方案写成**可评审、可追溯、可验收**的设计文档。核心：spec 是**决策的固化**——它记录"为什么这么定、定了什么、没定什么、怎么算实现成功"，而不是知识的搬运（堆背景介绍）或愿望的罗列（只说要做什么不说怎么做）。

## 何时使用

- 要做一个非平凡功能/重构/迁移，想先写设计再动手
- 要把脑里模糊的方案固化成可给同事评审的文档
- 已有设计草稿，想审查写得好不好

**不该用**：小到一目了然的改动（直接做，写 spec 是负担）；纯研究性命题还没结论时（先做 spike 调研，有了结论再写 spec——spec 记录决策，调研产出结论）。

**与相邻 skill 的衔接**：spec-writing 在"需求澄清 → **写 spec** → 拆任务"流水线的中间。spec 定稿后，把方案交给 `task-breakdown` 拆成可执行任务；需求还太模糊连方案都形不成时，先澄清（见 `clarifying-questions`，未实现）再写 spec。

## 核心内容

### 先判断时机：spec 之前还有没有重大未知

不是所有"写个 spec"的需求都该直接开写。如果方案的核心决策还依赖未澄清的未知，硬写出来的 spec 就是空架子或一堆猜测。先问自己：**写 spec 需要的决策，我都有依据了吗？**

判断标准——把"影响方案结构的关键决策"列出来，看每条是哪种状态：

- **已明**：有依据、能定。直接写进 spec 的决策部分。
- **需要澄清**：用户一句话能定（范围、约束、目标）。**写 spec 前先问**，不要替用户猜。
- **需要调研**：一句话定不了，得查/试/比（技术选型、性能可行性）。**先做 spike（专门的调研任务，产出结论而非代码），有结论再写 spec**——否则 spec 里只能写"待定"，决策部分就空了。

如果大量关键决策都是"需要调研"状态，说明现在不是写 spec 的时机——先做调研。澄清和调研占 spec 前置工作的大头，跳过它们直接写，是最常见的失败模式。

**判断后的产出顺序**（很重要，别把几步混在一起让用户困惑）：

- **关键决策大多"已明"** → 直接写 spec。
- **有"需要澄清"项** → 先把澄清问题列给用户（阻塞项优先），**等回答**。这一步的产出就是"澄清问题清单"，不要同时甩一份假设性 spec——用户分不清该先回答问题还是改 spec。
- **有"需要调研"项** → 标出该做哪些 spike，说明"结论出来才能填 spec 的哪几节"。产出是"spike 清单 + 这些 spike 解锁的 spec 章节"，同样不提前硬写。
- **混合** → 澄清问题 + spike 清单一起给，标注各自解锁什么。把"前置工作"和"spec 本体"分开交付。

**澄清问题怎么问**（这一步的产出质量直接决定 spec 质量）：

- **每条带"为什么问"**：让用户理解这个未知为什么影响方案，而非凭空盘问。差："QPS 多少？"；好："读 QPS 大概多少？（决定能否用单机 Redis 还是必须集群）"。
- **给默认假设让用户确认，而非开放式追问**："我假设日读 < 1k QPS、单机够用，不对请纠正"——用户一句话能校正；纯开放式问题用户得从头想，消耗耐心。
- **问影响方案结构的，不问实现细节**：问"实时还是离线计算"（改变架构），不问"用 Flink 还是 Spark"（实现细节，spec 阶段还太早）。
- **一次别超过 6-8 条**：多了用户接不住。真有更多未知，先问阻塞第一刀的，其余用默认假设推进。把未知按"阻塞/非阻塞"分类（阻塞项先问、非阻塞用假设推进）很关键——`task-breakdown` 的"澄清未知"对此有更细的分类法，可参考。

> 反例：用户说"写个限流 spec"，你直接套模板写"背景/方案/步骤"——但"限流维度（接口/用户/IP）、算法（令牌桶/漏桶）、单机/分布式"都没定，写出来的方案部分全是占位符。

### spec 写什么：决策，不是知识

spec 的价值密度集中在**决策**上。每写一段问自己：**这是决策，还是背景知识？**两者的篇幅分配严重失衡是 spec 写差的信号：

- **决策**（spec 的核心）：选了什么方案、为什么选它、放弃了什么、怎么算成功。这是别人来评审、未来回溯时要看的东西，值得详细写。
- **背景**（spec 的脚手架）：问题是什么、为什么做、相关技术是什么。**点到决策够用为止**，不要写成技术科普。读者不需要在限流 spec 里学"什么是令牌桶算法"——他们需要知道"我们为什么在令牌桶和漏桶之间选了令牌桶"。

> 反例：搜索功能 spec 一半篇幅在介绍 Elasticsearch 基于 Lucene、支持全文检索、生态丰富——这是知识搬运，不是决策。读者看完不知道你们为什么选它、什么场景选它、不选它会怎样。

**研究基础怎么写**：调研/spike 的结论要进 spec，但**只写"对决策有用的结论"，不写调研过程**。差的做法是堆"我查了 A、B、C，A 是……B 是……"的流水账；好的做法是直接给"对比结论 + 选定理由"，如"对比 Redis 滑动窗口与 Sentinel 网关限流：Redis 方案在多实例下计数精确（误差<1%）、Sentinel 依赖单网关成瓶颈，选 Redis"。读者要的是结论支撑决策，不是重新跟你调研一遍。

### 显式标注未决项，别藏不确定性

spec 里一定有没定死的东西（技术选型还在权衡、依赖外部团队、待 spike 结论）。**显式标出来**，不要把它们包装成"已定方案"蒙混过关。藏起来的不确定性会在实现期爆炸——下游按"已定"去做，结果方案根本没敲定，返工。

标注方式：

- **待定项**：明确写 `TBD：xxx，待 yyy 后定`。例：`分布式事务方案 TBD，待 Saga 与最终一致性的压测对比后定`。
- **选项 + 权衡**：一时定不了的，列候选方案 + 各自的代价，标"待选"。例：`消息队列：Kafka（吞吐高、运维重）vs RabbitMQ（够用、轻量），倾向 RabbitMQ，待容量评估确认`。

显式 TBD 让评审者一眼看到"哪里还没定"，也能让 spec 在未决状态下流转（不必等所有事都想清才能写）。

### 范围：做什么，同样重要的是不做什么

明确"本轮做什么"的同时，**显式列出"不做什么"**。范围不清是 spec 失败的高频原因——什么都往里塞，最后要么无限膨胀做不完，要么做出来的和初衷不符。

"不做什么"包含两类：

- **本轮排除**：相关但本轮不做的（如"做搜索本轮不做向量搜索，留后续"）。写出来防止范围蔓延。
- **明确不属于**：容易混淆但不是 spec 范围的（如"限流 spec 不管鉴权，那是另一个 spec"）。写出来防止边界模糊。

### 验收标准：spec 要定义"实现怎样算成功"

spec 不止写"做什么"，还要写"做完怎么算成功"——可验证的验收标准。否则实现完了没法判断达标与否，"是否完成"变成主观感受。

好的验收标准是**可观测、可量化**的：

- **差的验收**："搜索功能上线"（上线了但慢、不准、缺功能都算吗？）
- **好的验收**："核心商品搜索 P95 < 200ms、Top-10 召回率 > 90%、支持前缀匹配与高亮；订单/用户搜索本轮不做"

验收标准同时是 spec 范围的**反向校验**——如果你写不出验收标准，说明"做什么"本身还没定义清楚，回去补范围。

### 风险与回滚（高风险方案的必备维度）

对**高风险**方案（迁移、架构重构、数据变更、破坏性改动），spec 必须有"风险与回滚"维度。这类方案最怕的不是"怎么做"，而是"做错了怎么办"：

- **风险**：可能出什么事？（数据不一致、服务中断、性能退化、兼容性破坏）
- **发现机制**：怎么尽早发现做错了？（监控、灰度、对比校验、回滚触发条件）
- **回滚方案**：错了怎么退回？（特性开关、双写、分阶段切换、可回滚的部署）

低风险的小改动不必硬塞这个维度，过度防御也是 spec 的负担。

### 审查已有草稿：先分类，再对症

用户拿一份已有草稿让你"看看"，先判断它属于哪种问题，处理方式完全不同：

- **信息不足型**：草稿只写了背景/愿望，核心决策全空（如"要加搜索功能，用 ES"——为什么用 ES、搜什么、怎么算成功都没写）。这种其实是"现在还不是写 spec 的时机"——**退回前置流程**：列澄清问题 + 必要的 spike，别在残缺草稿上打补丁。
- **写法缺陷型**：草稿信息基本齐，但写法差（堆背景、藏不确定性、没验收、范围蔓延）。这种才是"改草稿"——逐条指出具体问题 + 改法。

**审查意见要排优先级，别一次甩十几条**。按"致命 → 重要 → 锦上添花"分：致命的是会导致返工或方向错的（藏了不确定性、范围不清、没验收）；重要的是影响可读性的（堆背景）；锦上添花的是措辞结构。先改致命的——一份 spec 修好最致命的 1-2 条，价值远大于把 10 条小毛病都列出来。一次列太多，用户接不住、反而无从下手。

审查用**具体定位**而非泛泛批评：指出"第 X 段是背景科普，应压成一句决策依据"，而不是"写得不够详细"。

### 产出形态

最终交给用户的是**精简、结构化**的内容，不是论证长文：

- **写 spec 时**：用骨架的章节结构，决策部分每条带"为什么"，背景一两句点到。别把决策推理过程、候选方案的逐个展开（除非是 TBD 权衡需要）全倒进去——读者要结论，不是陪你想一遍。
- **判断时机 / 审查草稿时**：产出是"澄清问题清单"或"审查意见（按优先级）"，编号列表为主。别在意见里掺大段 skill 原文引用或方法论解释——那是你的工作依据，不是交付物。
- **TBD 与选项权衡**：用紧凑格式（`TBD：xxx，候选 A(代价)/B(代价)，倾向 X，待 Y`），别展开成多段。

记住：spec 的读者是**评审者和未来的实现者**，他们要快速判断"这方案对不对、怎么做"，不是欣赏你分析得多彻底。

## spec 的结构骨架

按需取用，不必每节都有——以"能讲清决策"为准：

```
# <标题>

## 元信息          <日期、状态（草稿/评审中/已定）、范围>
## 背景与目标      <问题是什么、为什么做、目标是什么；背景点到够用>
## 研究基础        <决策依据：调研结论、对标、数据；不是科普>
## 范围            <做什么 + 明确不做什么>
## 设计            <核心决策：选了什么、为什么、放弃什么；未决项标 TBD>
## 风险与回滚      <高风险方案必备；低风险可省>
## 验收标准        <怎样算实现成功：可观测、可量化>
## 后续            <下一步动作、依赖、待定项的解决计划>
```

## 常见错误

| 问题 | 修法 |
|------|------|
| 核心决策未知未澄清就硬写 spec | 先判断决策状态，需澄清先问、需调研先做 spike |
| 堆背景知识，决策却一带而过 | 压缩背景到"决策够用"，篇幅让给"为什么这么定" |
| 把未决项写成已定方案 | 显式标 `TBD` + 列选项权衡，别藏不确定性 |
| 范围只有"做什么"没有"不做什么" | 显式列排除项，防范围蔓延 |
| 没有"做完算成功"的标准 | 写可观测、可量化的验收标准 |
| 高风险方案没写风险与回滚 | 迁移/重构/破坏性改动必加风险与回滚维度 |
| 小改动也套完整模板硬撑篇幅 | 按需取节，能讲清决策即可，不为全而全 |
| 信息不足型草稿直接打补丁 | 退回前置流程：列澄清问题 + spike，别在残缺上修 |
| 审查意见一次列十几条不排优先级 | 按"致命/重要/锦上添花"分，先改最致命的 1-2 条 |

