# Story Splitting

> Apply INVEST + SPIDR + 7 splitting strategies when a feature, requirement, or epic is too large to ship in one PR / one sprint / one week. Use whenever 用户 says "这个需求太大" / "拆一下" / "怎么分阶段做" / "acceptance criteria 怎么写" / "edge case 漏没漏" / "spec 写不下去" / "split this epic" / "break down this story". Forces INVEST checking (Independent / Negotiable / Valuable / Estimable / Small / Testable), produces vertical slices not horizontal layers, drafts acceptance criteria in Given-When-Then, enumerates edge cases by 4 axes (input / state / boundary / failure). Self-contained methodology — no external docs required.

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

---


# 故事拆分 + Acceptance Criteria + Edge Case

## 何时触发

- 一个需求看起来 ≥ 1 周工作量
- 写 spec 写到一半发现"还要包括 X / Y / Z"开始膨胀
- "这个 epic 太大，拆一下"
- acceptance criteria 怎么写
- "上线前 edge case 过一遍"
- 团队估算分歧 > 50%（说明大家理解的"做完"不是同一回事）
- PRD review 时被问"那 X 情况怎么办"

## 何时不触发

- 单文件 hot fix（一行代码改动不需要拆）
- 已经按 phase 切好的 dev 任务 → 用 dev-phase-rollout
- 创意发散阶段（拆故事是收敛阶段，发散用 jtbd-framework / brainstorm）

## 第一步：INVEST 自检

每个故事过这 6 项：

| 字母 | 含义 | 通过标准 |
|---|---|---|
| **I**ndependent | 独立 | 可以脱离其他故事单独 ship 上线 |
| **N**egotiable | 可商量 | 内容、UI、实现可在 dev 中协商，不是死的 |
| **V**aluable | 有价值 | 上线后用户 / 业务能感受到具体价值 |
| **E**stimable | 可估算 | 团队能给出 ≤ 3 天的合理估算 |
| **S**mall | 小 | 1-3 天可完成（≤ 1 个 sprint） |
| **T**estable | 可测 | 有明确的"做完了"判断标准 |

任何一项不通过 → 必须拆。

## 第二步：SPIDR 拆分（5 条主路径）

| 路径 | 何时用 | 例子 |
|---|---|---|
| **S**pike | 技术不确定，先 spike 验证可行性 | "新支付方式接入"先做 1 天技术 spike |
| **P**ath | 一个故事多个用户路径 → 按路径拆 | 注册流程 = 邮箱注册 / 手机注册 / 第三方登录 三个故事 |
| **I**nterface | UI 多端 → 按端拆 | 桌面 / 移动 / API 三个故事 |
| **D**ata | 数据多类型 → 按类型拆 | 单一货币先做 → 多货币扩展 |
| **R**ules | 业务规则复杂 → 先做主流程，规则后续加 | 主流程不含权限 → 加权限 → 加白名单 |

## 第三步：7 splitting strategies（备用，SPIDR 不够时用）

1. **Workflow steps**：按工作流步骤拆（注册 → 验证 → 激活 → 完成）
2. **Business rule variations**：先核心规则，再扩展规则
3. **Major effort**：把 80% 工作量集中处先做最简版本
4. **Simple/complex**：MVP 简单版 → 复杂场景版
5. **Variations in data**：先一种数据类型，再扩展
6. **Data entry methods**：先一种输入方式，再扩展
7. **Defer performance**：先功能正确，再性能优化

## 第四步：垂直切片不水平切片（关键）

❌ **水平切片**：DB 层 → Backend API 层 → Frontend 层（每层一个故事）
- 问题：单层完成无价值，必须三层全做完才上线

✅ **垂直切片**：完整功能但范围小（一个最小用户场景的 DB+Backend+Frontend 端到端）
- 第一片：单一最简场景全栈打通
- 第二片：扩展到第二个场景
- 第三片：覆盖更多边界

## 第五步：Acceptance Criteria（Given-When-Then 格式）

```
Given <初始状态 / 前置条件>
When <用户动作 / 触发事件>
Then <预期结果>
And <附加预期结果>
```

每个故事至少 3 条 AC，覆盖：

1. **Happy path**（正常流程）
2. **Sad path**（异常 / 错误处理）
3. **Edge boundary**（边界值 / 极限情况）

## 第六步：Edge Case 4 轴枚举

对每个故事过这 4 个轴，每轴至少列 3 个 case：

### 轴 1：Input

- 空值 / null / undefined
- 极大值 / 极小值
- 特殊字符（emoji / SQL injection / HTML / 全角半角）
- 错误类型（数字字段输入字符串）
- 多语言（中英日韩 / RTL 阿拉伯）

### 轴 2：State

- 首次使用（无任何历史）
- 中间状态（部分完成被打断）
- 重复操作（同一动作连点 5 下）
- 多 tab / 多设备同时操作
- 并发冲突

### 轴 3：Boundary

- 数量边界（0 / 1 / 上限 / 上限+1）
- 时间边界（凌晨跨日 / 月底 / 年底 / 闰年 / 时区切换）
- 容量边界（大文件上传 / 长字符串 / 大列表分页）
- 权限边界（无权限 / 部分权限 / 临时过期）

### 轴 4：Failure

- 网络断（前端断 / 后端断 / 中途断）
- 服务降级（依赖服务挂）
- 超时（请求超时 / 长任务超时）
- 数据不一致（缓存过期 / DB 主从延迟）
- 非预期数据（脏数据 / 历史遗留格式）

每轴至少列 3 个 case → 4 × 3 = 12 个 edge case 起步。

## 模板（完整故事）

```markdown
## Story: <故事标题>

### INVEST 自检
- [x] Independent
- [x] Negotiable
- [x] Valuable
- [x] Estimable（估算 2 天）
- [x] Small
- [x] Testable

### Acceptance Criteria

**AC1（Happy）**：
Given <前置>
When <动作>
Then <结果>

**AC2（Sad）**：
...

**AC3（Edge）**：
...

### Edge Cases

**Input 轴**：
- 空 / null / 长度 0
- 单字符
- 1000 字符（上限）
- 特殊字符 emoji + SQL keyword
- 阿拉伯语 RTL

**State 轴**：
...

**Boundary 轴**：
...

**Failure 轴**：
...

### 拆分历史
- 原 epic: <epic 名>
- 拆分路径: SPIDR-<P/I/D/R> + Workflow steps
- 兄弟故事: <story 2>, <story 3>
```

## Anti-Rationalization

| 逃逸路径 | 为什么不行 |
|---|---|
| "故事太多了 INVEST 走不完" | 走不完说明你应该拆，正是 INVEST 要解决的 |
| "AC 写一条 happy path 够了" | 三条最少：happy / sad / edge。少一条 = 故事不完整定义 = 测试漏洞 |
| "Edge case 太多写不完" | 4 轴 × 3 个 = 12 个起步线。写不完说明你需要再拆一次故事 |
| "水平切片更省事一层一层来" | 水平切片每层完成都没价值，要全部完成才能上线 = 一次性大爆炸 |
| "技术 spike 也算一个故事吧" | Spike 是 INVEST 失败的应急路径，不是常规故事。Spike 必须有时间 box（≤ 1 天）+ 明确产出（学到 X / 排除 Y） |
| "拆这么细 stand-up 时间不够" | 拆细的成本在 PM 端（一次性）；不拆细的成本在团队全程（估算偏差 + 测试漏 + 上线返工） |
| "acceptance criteria 测试时再补" | AC 是"做完了"的定义。事后补 = 开发期间没有目标 = 做出来不一定符合期望 |
| "INVEST 太理论了，跳过" | INVEST 不是理论，是预防核武器：没 Independent → 上线被卡 / 没 Valuable → 团队做了没价值的工作 / 没 Testable → 不知道做完没 |

## 关联

- 拆完前优先级排序：用 `rice-prioritization` 先排
- 拆完后失败推演：用 `pre-mortem` 跑风险
- 拆完后进 sprint：用 `product-management:sprint-planning`
- 写完 spec 后交付实现：确保 spec 自包含 + 按 phase 分阶段推进

## Status

v1.0 — 2026-05-08 product-thinking plugin v0.1.0 首发。

