关于 shaping
这是一套协作方法,用于定义需求、探索解决方案、检查适配度,并将选定设计拆分为实现切片。它适合需要保持不同详细层级规划文档一致的团队。
主要功能
- 01迭代整理需求与解决方案
- 02通过二元适配检查比较方案
- 03细化选定方案的功能与连线
- 04将面包板化设计转为实现切片
- 05保持不同抽象层级文档的一致
适用场景
- 01为明确的问题探索解决方案
- 02依据需求比较备选方案
- 03将选定设计拆分为实现切片
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ rjs/ shaping-skills --skill shaping安装后在 Claude Code 中输入/shaping确认已加载。
详细介绍
塑造方法论
一种用于协作式定义问题并探索解决方案的结构化方法。
多层级一致性(至关重要)
塑造过程会产出不同抽象层级的文档。各层级之间必须保持事实一致。
文档层级(从高到低)
- 塑造文档 — R、方案、组成部分和适配性检查的事实依据
- 切片文档 — 切片定义和面包板的事实依据
- 各切片计划(V1-plan 等)— 实现细节的事实依据
原则
每个层级都会总结或呈现其下层级的内容。较低层级包含更多细节;较高层级则经过设计,便于快速了解上下文。
变更会双向传递:
- 高层级变更 → 逐层传递: 如果你修改了塑造文档中的组成部分表格,也要更新切片文档。
- 低层级变更 → 逐层向上传递: 如果切片计划揭示了新的机制,或改变了某个切片的范围,则切片文档和塑造文档都必须反映这一点。
实践
每次进行变更时:
- 确认你正在修改哪个层级
- 询问:“这会影响上层或下层文档吗?”
- 在同一次操作中更新所有受影响的层级
- 绝不让文档彼此脱节
只有各层级彼此保持一致,这套系统才能发挥作用。
开始会话
开启新的塑造会话时,向用户提供两个入口:
- 从 R(需求)开始 — 描述问题、痛点或约束条件。逐步建立需求,并让方案逐渐显现。
- 从 S(方案)开始 — 勾勒已有构想的解决方案。将其记录为一个方案,并在过程中提取需求。
没有规定的顺序。塑造是迭代过程 — R 和 S 会始终相互影响。
使用现有的塑造文档
如果塑造文档中已有选定方案:
- 仅展示所选方案的适配性检查 — 展示 R × [所选方案](例如 R × F),而不是所有方案
- 总结尚未解决的问题 — 指出任何状态为 Undecided 的需求,或所选方案中标记为 ❌ 的需求
这样可以让用户立即了解当前塑造进展以及需要关注的事项。
核心概念
R:需求
一组编号条目,用于定义问题空间。
- R0、R1、R2…… 是需求集合中的成员
- 需求通过协作协商确定 — 不会自动填入
- 跟踪状态:核心目标、待定、倾向是/否、必需、优先考虑、排除
- 从适配性检查中提取的需求应独立成项(不依赖于任何特定方案)
- R 表示需要什么,而不是已满足什么 — 是否满足始终通过适配性检查(R × S)展示
- 分组策略: 顶层需求不得超过 9 项。当 R 超过 9 项时,将相关需求归入组,并拆分为子需求(R3.1、R3.2 等),使顶层需求保持在 9 项或以内。这样便于快速浏览需求,并促成有意义的分组。
S:方案(解决方案选项)
用字母表示互斥的解决方案路径。
- A、B、C…… 是顶层方案选项(选择其中一个)
- C1、C2、C3…… 是方案 C 的组成部分/部分(可以组合使用)
- C3-A、C3-B、C3-C…… 是组成部分 C3 的备选方案(选择其中一个)
方案标题
为方案起一个简短且有描述性的标题,概括其方法。展示方案时,同时显示标题:
## E: Modify CUR in place to follow S-CUR
| Part | Mechanism |
|------|-----------|
| E1 | ... |
好的标题能用几个词概括方案的核心:
- ✅ “E:原位修改 CUR,使其遵循 S-CUR”
- ✅ “C:两个数据源搭配混合分页”
- ❌ “E:解决方案”(过于笼统)
- ❌ “E:通过替换……为 widget-grid 添加搜索”(过长)
符号层级
| 层级 | 符号 | 含义 | 关系 |
|---|---|---|---|
| 需求 | R0、R1、R2... | 问题约束 | 属于集合 R |
| 方案形态 | A、B、C... | 解决方案选项 | 从 S 中选择一个 |
| 组件 | C1、C2、C3... | 方案形态的组成部分 | 在方案形态内组合 |
| 替代方案 | C3-A、C3-B... | 组件的不同做法 | 每个组件选择一个 |
符号延续
将符号贯穿始终,作为审计轨迹。定稿时,通过引用先前的组件来组合新选项(例如,“方案形态 E = C1 + C2 + C3-A”)。
阶段
方案设计分为两个阶段:
Shaping → Slicing
| 阶段 | 目的 | 输出 |
|---|---|---|
| 方案设计 | 探索问题和解决方案空间,选择并细化一种方案形态 | 包含 R、方案形态、适配检查和面包板的方案设计文档 |
| 切片 | 拆分工作以便实现 | 可演示 UI 的垂直切片 |
阶段转换
满足以下条件时,从方案设计 → 切片:
- 已选定一种方案形态(通过适配检查,且感觉合适)
- 已将方案形态通过面包板细化为具体的交互方式
- 需要规划实现顺序
没有经过面包板细化的方案形态,就无法进行切片。
适配检查(决策矩阵)
适配检查是一个将所有方案形态与所有需求进行比较的唯一表格。需求作为行,方案形态作为列。我们据此决定要推进哪种方案形态。
格式
## Fit Check
| Req | Requirement | Status | A | B | C |
|-----|-------------|--------|---|---|---|
| R0 | Make items searchable from index page | Core goal | ✅ | ✅ | ✅ |
| R1 | State survives page refresh | Must-have | ✅ | ❌ | ✅ |
| R2 | Back button restores state | Must-have | ❌ | ✅ | ✅ |
**Notes:**
- A fails R2: [brief explanation]
- B fails R1: [brief explanation]
约定
- 始终显示完整的需求文本——在适配检查中绝不缩写或概括需求
- 适配检查采用二元判断——通过用 ✅ 表示,未通过用 ❌ 表示。不使用其他值。
- 方案形态列中只能包含 ✅ 或 ❌——不添加行内说明;解释应放在“备注”部分
- 适配检查中绝不使用 ⚠️ 或其他符号——⚠️ 仅用于“部件”表中标记的列
- 备注尽量简短——只解释未通过的情况
比较组件内的替代方案
比较特定组件的替代方案(例如 C3-A 与 C3-B)时,使用相同格式,但范围仅限于该组件:
## C3: Component Name
| Req | Requirement | Status | C3-A | C3-B |
|-----|-------------|--------|------|------|
| R1 | State survives page refresh | Must-have | ✅ | ❌ |
| R2 | Back button restores state | Must-have | ✅ | ✅ |
缺失的需求
如果某种方案形态通过所有检查,但感觉仍不合适,说明缺少一项需求。将隐含约束明确表述为新的 R,然后重新运行适配检查。
宏观适配检查
这是一种独立于标准适配检查的工具,用于在高层级处理分块需求和早期方案形态,此时大多数机制仍标记为 ⚠️。仅在明确要求时使用。
宏观适配检查中,每种方案形态有两列,而不是一列:
- 是否涉及?——方案形态中的某个部分是否在高层级上回应了这项需求?
- 是否有答案?——能否追溯到具体做法?机制是否已明确说明?
格式:
## Macro Fit Check: R × A
| Req | Requirement | Addressed? | Answered? |
|-----|-------------|:----------:|:---------:|
| R0 | Core goal description | ✅ | ❌ |
| R1 | Guided workflow | ✅ | ❌ |
| R2 | Agent boundary | ⚠️ | ❌ |
约定:
- 仅显示顶层需求(R0、R1、R2...),不显示子需求
- 不设备注列——保持表格精简,便于快速浏览
- “是否涉及”使用 ✅(是)、⚠️(部分)或 ❌(否)
- “是否有答案”使用 ✅(是)或 ❌(否)
- 宏观适配检查后另附一张差距表,列出具体缺失部分及其相关子需求
可执行的操作
这些操作可以按任意顺序进行:
- 收集 R——随着需求逐渐明确而收集需求
- 勾勒方案形态——提出高层级的做法(A、B、C...)
- 细化(组件)——将一种方案形态拆分为组件(B1、B2...)
- 细化(交互方式)——将选定的方案形态扩展为具体的 UI/非 UI 交互方式和连接关系
- 探索替代方案——为某个组件确定不同选项(C3-A、C3-B...)
- 检查适配情况——构建适配检查(决策矩阵),将各选项与 R 进行对照
- 提取 R——当适配检查揭示隐含需求时,将其作为独立条目加入 R
- 制作面包板——绘制系统映射图,了解变更发生的位置,并使方案形态更加具体
- Spike——调查未知事项,找出所需的具体步骤
- 决策——选择替代方案,组合最终解决方案
- 切片——将经过面包板细化的方案形态拆分为可实现的垂直切片
沟通
显示完整表格
显示 R(需求)或任何 S(形状)时,始终展示所有行,绝不总结或缩写。完整表格才是交付物;只展示部分内容会丢失信息,并破坏协作流程。
- 展示所有需求,即使数量很多
- 展示所有形状部分,包括子部分(E1.1、E1.2……)
- 展示适配检查中的所有备选方案
这为何重要
塑造是一个协作协商过程。用户需要看到全貌,以便:
- 发现遗漏的需求
- 注意到不一致之处
- 做出明智的决定
- 跟踪已确定的事项
摘要会隐藏细节,并将控制权从用户手中转移。
用 🟡 标记变更
修改后重新呈现需求表或形状表时,用 🟡 标记每一行变更或新增内容。将 🟡 放在变更单元格内容的开头。这样可以轻松跟进迭代完善,用户无需在脑中对比表格,就能立即发现差异。
调研任务
调研任务是为了了解现有系统的工作方式,以及实现某个组件需要哪些具体步骤。对于机制或可行性存在不确定性的情况,请使用调研任务。
文件管理
始终将调研任务单独保存为一个文件(例如,spike.md 或 spike-[topic].md)。调研任务是独立的调查文档,可以独立于塑造文档分享或处理。
目的
- 了解相关领域中现有系统的工作方式
- 明确我们需要做什么才能达成目标
- 支持对是否继续进行做出明智的决定
- 不涉及工作量;工作量已隐含在具体步骤中
- 先调查,再提出方案——了解已有内容;你可能会发现系统已经满足需求
结构
## [Component] Spike: [Title]
### Context
Why we need this investigation. What problem we're solving.
### Goal
What we're trying to learn or identify.
### Questions
| # | Question |
|---|----------|
| **X1-Q1** | Specific question about mechanics |
| **X1-Q2** | Another specific question |
### Acceptance
Spike is complete when all questions are answered and we can describe [the understanding we'll have].
验收指南
验收描述的是我们将获得的信息或理解,而不是结论或决定:
- ✅ “……我们可以描述用户如何设置语言,以及非英文标题会出现在哪里”
- ✅ “……我们可以描述实现 [component] 所需的步骤”
- ❌ “……我们可以回答这是否是阻碍因素”(这是决定,不是信息)
- ❌ “……我们可以决定是否应该继续”(决定应在调研任务之后做出)
调研任务负责收集信息;之后再根据这些信息做出决定。
问题指南
好的调研问题应询问具体机制:
- “[X] 逻辑位于哪里?”
- “需要做哪些改动才能实现 [Y]?”
- “我们如何 [执行 Z]?”
- “是否存在会影响 [approach] 的限制?”
避免询问:
- 工作量估算(“这需要多长时间?”)
- 模糊的问题(“这很难吗?”)
- 无法揭示具体机制的是非题
面包板
使用 /breadboarding 技能来绘制现有系统,或将某个形状细化为具体的功能点。面包板会生成:
- UI 功能点表
- 非 UI 功能点表
- 按位置分组的接线图
在以下情况下,请使用面包板:
- 绘制现有代码,以了解改动会落在哪里
- 将高层级形状转化为具体功能点
- 揭示彼此正交的关注点(互相独立的部分)
表格是唯一事实来源
功能点表(UI 和非 UI)定义了面包板。Mermaid 图会将其呈现出来。
收到关于面包板的反馈时:
- 首先——更新功能点表(添加、移除或修改功能点,更新 Wires Out)
- 然后——更新 Mermaid 图,以反映这些变更
绝不要将图视为主要交付物。变更应从表格流向图,而不是反过来。
CURRENT 是保留的形状名称
使用 CURRENT 描述现有系统。这样可以为理解提议的变更如何融入现有系统提供基线。
形状部分
标记为未知(⚠️)
可以从较高层面描述某个机制,却尚未真正理解它。标记列用于跟踪这一点:
| 部分 | 机制 | 标记 |
|---|---|---|
| F1 | 创建 widget(组件、定义、注册) | |
| F2 | 魔术认证处理程序 | ⚠️ |
- 空白 = 已理解该机制——我们确切知道如何构建它
- ⚠️ = 标记为未知——我们已经描述了要做什么,但还不知道怎么做
为什么标记为未知的部分无法通过适配检查:
- ✅ 表示声称已掌握——意思是“我们知道这个方案如何满足这项要求”
- 满足要求需要一种机制——某个能具体实现该要求的部分
- 标记表示我们不知道怎么做——我们描述了想要什么,而不是如何构建
- 不能声称自己知道未知之事——因此必须标记为 ❌
适配检查始终是二元的——只能是 ✅ 或 ❌,没有第三种状态。标记为未知的部分在解决之前都算失败。
这一区分了“我们有个草案”和“我们确实知道该怎么做”。早期方案(A、B、C)通常有很多标记部分——探索阶段这样很正常。但选定的方案不应有任何标记(所有 ❌ 都已解决),或者应明确列出用于解决它们的探索任务。
部分必须是机制
方案的各个部分描述的是我们要构建或更改的内容,而不是意图或约束:
- ✅ “将
childType === 'letter'路由到typesenseService.rawSearch()”(机制) - ❌ “类型不变”(约束——应归入 R)
避免 R 和 S 之间的同义反复
R 描述需求或约束(需要什么结果)。S 描述实现机制(如何实现)。如果两者说的是同一件事,方案部分就没有提供额外信息。
- ❌ R17:“管理员可以批量请求成员签署” + C6.3:“管理员可以批量请求成员签署”
- ✅ R17:“管理员可以将现有成员纳入弃权书跟踪” + C6.3:“批量请求界面支持成员筛选,并批量创建 WaiverRequests”
需求描述所需的能力。方案部分描述提供该能力的具体机制。如果你发现自己在把 R 中的文字复制到 S 中,请停下来——方案部分应具体说明 如何 实现。
各部分应是垂直切片
避免使用“数据模型”这类将所有表归到一起的水平分层。应将数据模型与其支持的功能放在一起:
- ❌ B4:数据模型——Waivers 表、WaiverSignatures 表、WaiverRequests 表
- ✅ B1:签署处理程序——包含 WaiverSignatures 表和处理程序逻辑
- ✅ B5:请求跟踪——包含 WaiverRequests 表和跟踪逻辑
每个部分都应是一个垂直切片,包含机制及其所需的数据。
提取共享逻辑
当同一逻辑出现在多个部分中时,应将其提取为独立部分,供其他部分引用:
- ❌ 在 B1 和 B2 中重复“签署处理程序:创建 WaiverSignature + 设置布尔值”
- ✅ 将其提取为 B1:签署处理程序,然后在 B2 和 B3 中注明“→ 调用 B1”
| **B1** | **Signing handler** |
| B1.1 | WaiverSignatures table: memberId, waiverId, signedAt |
| B1.2 | Handler: create WaiverSignature + set member.waiverUpToDate = true |
| **B2** | **Self-serve signing** |
| B2 | Self-serve purchase: click to sign inline → calls B1 |
| **B3** | **POS signing via email** |
| B3.1 | POS purchase: send waiver email |
| B3.2 | Passwordless link to sign → calls B1 |
层级标记法
从扁平标记法开始(E1、E2、E3……)。只有在以下情况下才引入层级(E1.1、E1.2……):
- 部分太多,难以理解
- 你正在得出结论,并希望展示结构
- 对相关机制进行分组有助于沟通
| 标记法 | 含义 |
|---|---|
| E1 | 方案 E 的顶层组件 |
| E1.1、E1.2 | E1 的子部分(需要时再添加) |
层级分组示例(在方案成熟时使用):
| 部分 | 机制 |
|---|---|
| E1 | 替换数据源 |
| E1.1 | 修改后端索引器 |
| E1.2 | 将 letters 路由到新服务 |
| E1.3 | 将 posts 路由到新服务 |
| E2 | 添加搜索输入框 |
| E2.1 | 添加带防抖的输入框 |
细化方案
选定方案后,可以将其展开为具体的实现手段。这称为细化。
标记法
使用“Detail X”(而不是新字母),以表明这是对方案 X 的分解,而非替代方案:
## A: First approach
(shape table)
## B: Second approach
(shape table)
## Detail B: Concrete affordances
(affordance tables + wiring)
细化的产出
使用 /breadboarding 技能来产出:
- UI 交互元素表 — 用户可以看到并与之交互的内容(输入框、按钮、显示内容)
- 非 UI 交互元素表 — 数据存储、处理程序、查询、服务
- 连接图 — 展示各处交互元素如何连接
为什么用“细化 X”而不是“C”
形状字母(A、B、C……)代表互斥的备选方案——你需要从中选一个。细化并非备选方案,而是对已选形状进行更深入的拆解。使用新字母会错误地暗示它是一个并列选项。
A, B, C = alternatives (pick one)
Detail B = expansion of B (not a choice)
文档
塑形过程最多会产出四份文档。每份文档的作用各不相同:
| 文档 | 内容 | 用途 |
|---|---|---|
| 框架 | 来源、问题、结果 | “为什么”——简明扼要,面向利益相关者 |
| 塑形文档 | 需求、形状(CURRENT/A/B/...)、交互元素、面包板、适配检查 | 工作文档——在此进行探索和迭代 |
| 切片文档 | 切片详情、每个切片的交互元素表、连接图 | 实施计划——如何逐步构建 |
| 切片计划 | V1-plan.md、V2-plan.md 等 | 各切片的独立实施计划 |
文档生命周期
Frame (problem/outcome)
↓
Shaping (explore, detail, breadboard)
↓
Slices (plan implementation)
框架可以先行编写——在任何解决方案工作开始前,它会记录“为什么”。其中包含:
- 来源 — 促成本项工作的原始请求、引述或材料(原文照录)
- 问题 — 存在哪些故障或痛点(从来源提炼)
- 结果 — 成功的样子(高层次描述,不限定具体解决方案)
记录来源材料
用户在框定阶段提供来源材料时(用户请求、引述、电子邮件、Slack 消息等),务必在框架文档顶部的“来源”部分原文记录。
## Source
> I'd like to ask again for your thoughts on a user scenario...
>
> Small reminder: at the moment, if I want to keep my country admin rights
> for Russia and Crimea while having Europe Center as my home center...
> [Additional source material added as received]
---
## Problem
...
原因:
- 来源是事实依据——问题和结果都是解读
- 保留可能在后续工作中有用的上下文
- 如果提炼过程有所遗漏,可以重新查看原始请求
- 框定过程中收到更多来源材料时,可以继续添加
需要记录的情况:
- 用户粘贴了请求或引述
- 用户分享了利益相关者的电子邮件或消息
- 用户描述了别人告诉他们的场景
- 任何有助于形成框架的原始材料
塑形文档是开展实际工作的地方。所有探索、需求收集、形状比较、面包板设计和适配检查都在此进行。这是 R、形状、组成部分和适配检查的工作文档与事实依据。
切片文档在所选形状完成面包板设计并准备好构建时创建。其中包含切片拆分、每个切片的交互元素表以及详细连接关系。
文件管理
- 塑形文档:迭代时可随时更新——这是事实依据
- 切片文档:准备好切片时创建,并在切片范围明确后更新
- 切片计划:各自独立的文件(V1-plan.md 等),包含实施细节
Frontmatter
每份塑形文档(塑形文档、框架、切片文档)的 YAML frontmatter 都必须包含 shaping: true。这会启用工具钩子(例如 ripple-check 提醒),帮助维护文档间的一致性。
---
shaping: true
---
# [Feature Name] — Shaping
...
保持文档同步
请参阅本文档顶部的多层级一致性。任何层级的变更都必须向上传递至受影响的层级,并向下传递。
切片
完成形状的面包板设计后,将其切分为垂直实现增量。使用 /breadboarding 技能进行切片——该技能定义了什么是垂直切片、创建步骤以及可视化格式。
流程:
- 组成部分 → 形状中的高级机制
- 面包板设计 → 带连线的具体操作能力(使用
/breadboarding) - 切片 → 每个都可演示的垂直增量(使用
/breadboarding的切片部分)
关键原则: 每个切片都必须以可演示的 UI 告终。没有可见输出的切片是水平层,而非垂直切片。
文档产出:
- 切片文档 — 切片定义、每个切片的操作能力表、切片后的面包板
- 切片计划 — 单独的实现计划(V1-plan.md、V2-plan.md 等)
示例
用户正在设计一项搜索功能:
---
shaping: true
---
## Requirements (R)
| ID | Requirement | Status |
|----|-------------|--------|
| R0 | Make items searchable from index page | Core goal |
| R1 | State survives page refresh | Undecided |
| R2 | Back button restores state | Undecided |
---
## C2: State Persistence
| Req | Requirement | Status | C2-A | C2-B | C2-C |
|-----|-------------|--------|------|------|------|
| R0 | Make items searchable from index page | Core goal | — | — | — |
| R1 | State survives page refresh | Undecided | ✅ | ✅ | ❌ |
| R2 | Back button restores state | Undecided | ✅ | ✅ | ✅ |
**Notes:**
- C2-C fails R1: in-memory state lost on refresh
- C2-B satisfies R2 but requires custom popstate handler