news 2026/9/12 1:46:11

用 prototype 技能回答设计问题:一次性的可运行原型如何沉淀为真实决策

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
用 prototype 技能回答设计问题:一次性的可运行原型如何沉淀为真实决策

用 prototype 技能回答设计问题:一次性的可运行原型如何沉淀为真实决策

【免费下载链接】skillsSkills for Real Engineers. Straight from my .agents directory.项目地址: https://gitcode.com/GitHub_Trending/skills13/skills

导读

prototype是本仓库(Skills for Real Engineers)中一个模型可自动调用的工程技能:当团队遇到"这个状态模型对不对""这个界面应该长什么样"这类无法靠讨论拍板的设计问题时,它指导你写一段回答问题的临时代码(throwaway code),快速产出一个可运行、可分享、可由非开发者亲手把玩的产物。读完本文,你将掌握 prototype 技能的双分支选型逻辑(逻辑原型 vs UI 原型)、两份分步实操指南(LOGIC.md 与 UI.md)、"原型即一手资料(primary source)"的留存纪律,以及它与 wayfinder、to-spec、handoff 等技能如何组成一条完整的设计决策流水线。


一、prototype 是什么:一次性代码,回答一个问题

技能入口定义在 SKILL.md 中,元信息写得很克制:

"Build a throwaway prototype to answer a design question. Use when the user wants to sanity-check whether a state model or logic feels right, or explore what a UI should look like."

一句话概括:prototype 写的是"回答问题的临时代码",问题是第一位的,问题决定后面一切产物的形状。一个回答了错误问题的原型,无论做得多么漂亮,都是纯粹的浪费。

关键澄清两点:

  1. "一次性"是写代码方式的约束,不是销毁代码的承诺。不写测试、不做超出"能跑起来"的错误处理、不抽象、不持久化——因为这些都不会帮助你学到那个唯一想学的东西。
  2. 真正幸存下来的是"答案":答案被折叠进真实代码;原型本身则停在 main 之外的一个临时分支上,作为"答案确实来自这里"的证据。

从仓库结构看,该技能是一个独立的技能目录skills/engineering/prototype/,包含SKILL.md(总纲)、LOGIC.md(逻辑分支)、UI.md(UI 分支)和agents/openai.yaml(面向 Codex 等 Agent 的显示名配置,仅声明display_name: "Prototype")。它在 README.md 的 Reference 中被归为Model-invoked(模型可调用)技能——既可以被用户主动/prototype唤起,也可以在任务匹配时由 Agent 自动接取。

二、何时使用:把"谈不拢"变成"看一眼"

2.1 触发时机

当你遇到一个靠对话无法解决的问题时,就该动用它:

  • 一个状态机的边界情况,你在脑子里装不下;
  • 一个界面,你没看到三个版本并排放在一起就无法想象它。

grilling 系列会话恰恰容易在这类问题上膨胀:Agent 反复改述、你不断猜测、范围随着不确定性越滚越大。停止追问,构建一次性版本,看一眼,然后一行字回答。这正是原型存在的意义——把高保真讨论转化为一个可反应的实物。

2.2 与相邻技能的边界

  • 如果已经构建好的东西行为异常、你想知道它为什么坏了,应该用 diagnosing-bugs。原型探索的是"该构建什么",而不是"已构建的东西为什么坏了"。
  • 如果你已经知道要构建什么,下一步是 implement。只有某个具体的设计问题真正悬而未决、且对话无法解决时,才值得进入原型。

2.3 被动进入

你也会在没主动选择的情况下到达这里:wayfinder 会在它的地图上为prototype决策签发决策工单(decision ticket),处理这个工单本身就是本技能。详见下文"技能生态"。

三、两条分支:先选对,再做对

问题决定分支,两条分支产出截然不同的产物。选错分支会浪费整个原型。

分支要回答的问题产物形态适用场景
逻辑分支(Logic)"这个逻辑 / 状态模型感觉对吗?"单个可分享的 HTML 文件业务逻辑、状态迁移、数据结构
UI 分支(UI)"这应该长什么样?"同一路由上多个结构迥异的 UI 变体页面布局、信息层级、视觉方向

如果问题确实模棱两可且用户不在场,SKILL.md 给出的默认策略是:以周围代码判断——后端模块倾向于逻辑分支,页面或组件倾向于 UI 分支,并在原型顶部显式声明这个假设。

3.1 逻辑分支:一个能双击打开、能发邮件的 HTML 文件

详尽的逻辑分支操作手册见 LOGIC.md。它的目标产物是一个自包含的单个 HTML 文件(shareable demo):无构建、无服务器,任何人双击即可打开,能被当作邮件附件转发。页面背后的逻辑是一个纯净的小模块(reducer、状态机或一组函数),保持与 DOM 解耦,这样经过验证的版本能直接"抬升"(lift)进真实代码。

适用场景的典型表述:

  • "我不确定这个状态机能不能处理 X 然后 Y 的边缘情况。"
  • "这个数据模型真的能表达……这种情况吗?"
  • "我想在动手写之前感受一下这个 API 应该长什么样。"
  • 任何"想按按钮、看状态变化"的诉求。

文件结构(自上而下的清晰层级):

  1. 标题 + 一句话说明:这个 demo 让你探索什么(即第一步写下的问题)。这段说明要放在可见的引言区,而不是只写进代码注释——因为需要确保问题可被事后核查,无论用户是在旁观看还是之后 AFK 回来。
  2. 当前状态面板:完整相关状态以可读的面板渲染(带标签的字段,而不是原始 JSON dump),每次点击后重新渲染,让变化可见;在有助于非开发者跟上时,标注"刚才发生了什么"。
  3. 自由探索按钮:每个动作一个按钮,始终可用,任何人可以任意顺序戳模型;每次点击派发对应 action 并重新渲染。
  4. 引导式演练(guided walkthroughs):一组场景,每个场景一个标签页。每个标签页包含一段场景的通俗描述(它建立什么情境、该观察什么),下方是该场景按顺序要按的按钮。每个步骤都是真实按钮:点击执行该动作并进入下一步。启动演练会重置到已知初始状态,保证场景每次以相同方式运行。

场景应选择纸上推理困难的情况:快乐路径、棘手的边缘情况、一次"应该被判定为非法"的尝试。

逻辑的四种形状(取决于问题类型):

  • 纯 reducer(state, action) => state——动作是离散事件、状态是单一值;
  • 状态机:显式的状态与迁移——"当前哪些动作合法"本身就是问题的一部分;
  • 一组纯函数:作用于普通数据类型、没有隐式当前状态、只有变换;
  • 类或带清晰方法面的模块:逻辑确实拥有持续的内部状态。

核心纪律:保持逻辑纯净——不碰 DOM、不碰document、内部不放按钮处理器。页面调用模块,反向不成立。这是原型在其生命周期之外仍然有用的原因:一旦问题得到回答,被验证的 reducer / 状态机 / 函数集能独立抬升进真实模块。HTML 壳是临时性的,逻辑模块不是。

3.2 UI 分支:几个结构迥异的变体,一个浮动切换条

详尽的 UI 分支操作手册见 UI.md。目标产物是在同一条路由上生成几个结构迥异的 UI 变体,通过浮动的底部切换条和?variant=URL 参数切换。用户在浏览器里翻来翻去,挑一个(或从每个里偷一点),然后把其余的扔掉。

关键约束:变体必须在"结构"上分歧,而不是颜色。三个微调过的卡片网格只是"壁纸",不是原型。变体尽量在真实页面里渲染——真实页头、真实侧边栏、真实数据、真实密度——因为在真空中评判的变体永远显得不错。

两种子形态(强烈优先子形态 A)

  • 子形态 A:改造现有页面(首选)。路由已存在,变体在同一路由上渲染,由?variant=搜索参数门控。现有的数据获取、参数、鉴权全部保留,只有渲染子树切换。即便原型针对的是"还没有页面、但天然会住进某个页面"的东西(dashboard 的新区块、设置页的新卡片、现有流程的新步骤),也归为 A——把变体挂载进宿主页面。
  • 子形态 B:新页面(最后手段)。仅当原型对象确实没有可寄居的现有页面时使用(例如全新的顶级界面,或无法嵌入任何合理位置的流程)。创建一次性路由时遵循项目既有的路由约定,不要发明新的顶层结构,路径或文件名里包含prototype字样以便一眼可辨。提交到 B 之前先自检:真的没有现有页面可以嵌入吗?空路由会隐藏布满真实数据时才会暴露的设计问题。

两种子形态的浮动切换条完全一致。

四、UI 分支实操流程(含可复制的切换器代码)

4.1 第一步:陈述问题并确定 N

默认 3 个变体;超过 5 个就不再是"结构迥异"而开始变成噪声,所以上限是 5。在原型所在位置或文件顶部注释里写一行计划,例如:

"设置页的三个变体,通过?variant=切换,位于现有/settings路由上。"

4.2 第二步:生成结构迥异的变体

每个变体必须对照:页面目的与其可访问的数据;项目的组件库 / 样式体系(TailwindCSS、shadcn、MUI、纯 CSS……);一个清晰的导出组件名(如VariantAVariantBVariantC)。

变体必须在**布局、信息层级、主操作(primary affordance)**上真正不同。如果两个草案过于相似,用"不要用卡片网格"的明确指引重做其中一个。

4.3 第三步:接线——单一切换器组件

在路由上创建一个切换器组件,UI.md 给出了可直接参考的伪代码(需按项目框架适配):

// pseudo-code, adapt to the project's framework const variant = searchParams.get('variant') ?? 'A'; return ( <> {variant === 'A' && <VariantA {...data} />} {variant === 'B' && <VariantB {...data} />} {variant === 'C' && <VariantC {...data} />} <PrototypeSwitcher variants={['A','B','C']} current={variant} /> </> );
  • 子形态 A:所有既有数据获取保持在切换器之上,只有渲染子树按变体切换。
  • 子形态 B:/prototype/<name>下的一次性路由挂载同一个切换器。

4.4 第四步:构建浮动切换条

一个固定在屏幕底部居中的小条,包含三件套:

  • 左箭头:循环切到上一个变体(可回绕);
  • 变体标签:显示当前变体键,若变体导出了名称则一并显示,如B (Sidebar layout)
  • 右箭头:循环切到下一个变体(可回绕)。

行为要求:

  • 点击箭头更新 URL 搜索参数(用框架的路由器:Next 用router.replace、React Router 用navigate等),使变体可分享、刷新后仍稳定;
  • 键盘/也能循环;当<input><textarea>[contenteditable]获得焦点时不得拦截方向键;
  • 与页面视觉明显区分(高对比胶囊、微妙阴影),让人一眼看出它不属于被评估的设计;
  • 在生产构建中隐藏:用process.env.NODE_ENV !== 'production'或等价检查门控,防止一次意外的原型合并把切换条发给真实用户。

切换器放进单一共享组件,两种子形态复用;放在项目共享 UI 通常所在的位置。

4.5 第五、六步:交接与收尾

把 URL 和?variant=键交给用户。最有趣的反馈通常是"我想要 B 的页头配 C 的侧边栏"——那才是他们真正想要的设计。

变体胜出后:捕获答案(哪个变体、为什么),然后把原型按 SKILL.md 的方式归档(见下一节)。收尾映射:

  • 子形态 A:把胜者折叠进现有页面;从 main 中移除落选变体和切换器;
  • 子形态 B:把胜者提升为真实路由;从 main 中移除一次性路由和切换器。

完整变体集合是"一手资料",所以它落在临时分支上而不是垃圾桶——因为变体组件和切换器留在 main 分支会快速腐化并误导后来的读者。

4.6 UI 分支反模式清单

  • 变体只在颜色或文案上有差异:那是微调,不是原型;真正的变体在结构上分歧;
  • 变体间共享太多代码:共享<Header>没问题,共享<Layout>就破坏了意义;每个变体应能自由推翻布局;
  • 把变体接到真实写操作:只读原型没问题;若变体需要变更数据,指向桩(stub)——问题在于"应该长什么样",而不是"后端能不能跑";
  • 把原型直接提升到生产:变体代码是在原型约束下写的(无测试、最小错误处理),折叠时必须用正确方式重写。

五、逻辑分支的反模式与"真相时刻"

LOGIC.md 同样给出反模式清单:

  • 别加测试——需要测试的原型就不再是原型;
  • 别接真实数据库——除非问题本身就关于持久化,否则用内存状态;
  • 别泛化——没有"万一以后要支持 X";原型只回答一个问题;
  • 别把逻辑和页面搅在一起——纯模块一旦引用 DOM、document或按钮处理器,就不可抬升了;
  • 别上框架、打包器或服务器——单个可双击文件;一个 React 应用或 dev server 就毁了"可分享";
  • 别把 HTML 壳发到生产——页面是为被人手工点击而优化的,它背后的逻辑模块才是值得保留的部分。

交接时的真相时刻:把文件发过去或帮对方打开,让他们点演练、自由探索。真正有价值的瞬间是当他们说出"等等,这不应该可能发生""咦,我还以为 X 会不一样"时——那是想法本身的 bug,而这正是原型的全部意义。如果他们想要新动作或新场景,就加上,原型是会演化的。

六、原型是一手资料:答案进 main,证据留分支

这是 prototype 方法论最独特的一环:完成后的原型留下两样东西,它们去往不同的地方。

  1. 答案(结论 + 它所解决的问题)被持久化捕获:一条 commit message、一份 ADR、或实现工单。这是 main 分支保留的内容——折叠进真实代码。
  2. 原型是答案来自哪里的可运行证据不删除。但它同样不属于 main:那里没有需要维护它的东西,而且它腐化得很快。因此它被提交到 main 之外的一个一次性分支prototype/<name>永不合并,并在实现工单上留下指向该分支的上下文指针(context pointer)。

main 保持干净,探索保持可查找、可重跑——无论下一个接手工作的人是谁。

6.1 围绕"是否删除"的演进

"等等,原型不是应该删掉吗?"——曾经确实如此:构建、保留答案、扔掉代码。对这种做法最尖锐的反对从来与速度无关,而是:下一个接手的会话有什么可依据?一份散文式总结会丢掉让原型有说服力的东西。所以现在原型被当作一手资料对待:它落在 main 之外的prototype/<name>分支上,实现工单指向它。改变的是代码存放的位置,不是纪律本身——它仍然永不合并进 main。

6.2 "那个终端应用去哪了?"

逻辑分支以前产出终端应用,现在改为产出单个可分享的 HTML 文件。原因很实际:终端应用只能由"克隆了仓库且装了运行时"的人驱动,这恰好把原型最需要其意见的人排除在外——设计师、PM、知道状态模型本该表达什么的领域专家。而一个双击即开、可被邮件转发的自包含文件,任何人都能驱动。底层的纯逻辑模块不变,它依然是可以抬升进真实代码的部分。

七、常见问题与边界澄清

"Agent 在应该实现的时候叫我/prototype。"已知问题,而且是个命名问题。prototype是个通用而有吸引力的词,对不了解流程的 Agent 来说,一旦工单存在,"原型"读起来像"显而易见的下一步",所以它会在设计已经通过对话完全敲定的情况下被按名字推荐。如果你已经知道要构建什么,下一步是 implement;只有当某个具体设计问题真正悬而未决、且对话解决不了时,才动用原型。

"我应该在构建任何生产功能之前先原型整个应用(比如给潜在客户演示)吗?"那是戴着本技能名字的另一种产物。这里的原型范围限定为一个问题,"整个应用是什么"不是一个问题。全应用原型没有自然的停止点,于是会靠惯性变成生产应用:清理永远不会发生,在原型规则下写的代码(无测试、无错误处理)会跑到用户面前。需要销售演示,就把它当作演示刻意构建,并明确说明其中没有什么是生产级的;需要解决设计问题,就把范围切到那个问题上。

"怎么在自己的会话里运行它?"原型生活在自己的目录里,会产生大量你不想留在提问线程里的上下文,所以要在别处运行、只把答案带回来。handoff 是双向的桥梁——它把当前会话压缩成一份交接文档,供新的 Agent 继续,并在文档中列出下一步应调用的技能。

"这不是最快的烧 token 方式吗?"可能是——如果你对能用对话回答的问题做原型,或让一个原型蔓延到整个功能。真正有意义的比较不是 token 对比零,而是token 对比"构建了错误的状态模型、等它有生产调用者之后才发现"。把问题收窄、运行时间缩短,开销就始终成比例。

八、它正在工作的标志(验收清单)

原型文档 给出了可操作的验收清单:

  • 你能用一句话说出原型要回答什么问题,而且它写在 demo 顶部,不只是在你脑子里;
  • 一个不读代码的人能驱动逻辑 demo:打开文件、按演练标签页里的按钮、用自己的话描述所见;
  • 有人说"等等,那不应该可能发生"或"咦,我以为 X 是这样"——那是想法的 bug,而这正是全部意义所在;
  • UI 变体在布局和信息层级上分歧,而不只是颜色和文案;你收到的反馈是"我要 B 的页头配 C 的侧边栏";
  • 在一次会话内得到回答——如果一天后你还在构建它,说明问题太大,拆开它;
  • 结束时,main 包含决策且不包含任何原型代码,实现工单指向仍然持有原型的分支。

九、技能生态:prototype 在决策流水线中的位置

从 README.md 和 skills/engineering/README.md 的技能分类看,prototype是一个"随时可用的独立技能(reach-for-it-anytime standalone)":你切入它解决一个设计问题,然后切出;它同时也是另一套机制赖以运行的机器

9.1 最大消费者:wayfinder

它的最大消费者是 wayfinder。wayfinder 地图由决策工单构成,而prototype是工单的四种类型之一(另外三种是researchgrillingtask),用于阻塞性问题属于"这应该长什么样 / 这应该怎么表现"、任何讨论都无法解决的情况。wayfinder 通过制造一个具体的可反应物来提升模糊讨论的保真度,而本技能就是这个具体物如何被构建出来。在 wayfinder 中,原型工单是 HITL(人在回路)类型的:原型工单由答案解决,原型作为资产从地图链接。

9.2 上下游邻居

  • 上游:grill-me 与 grill-with-docs 回答"可盘问"的问题;不可盘问的问题转到本技能,一行字的答案再回到访谈里。
  • 下游:验证过的状态模型或 UI 方向成为 to-spec 的既定输入。值得注意的是,to-spec 的规范模板有一个针对原型的专门条款:当原型产出的代码片段(状态机、reducer、schema、类型形状)比散文更精确地编码了决策时,允许在对应决策中内联该片段,并简要注明它来自原型——但要裁剪到"承载决策的部分",而不是一份可运行的 demo。这正是"原型即一手资料"在规范环节的落点。
  • 兜底路由:其他任何情况,ask-matt 会在整个技能集合之上为你指路。

十、如何在你的项目中落地

该技能已存在于本仓库,安装与使用方式如下:

  • 本技能目录位于 skills/engineering/prototype/,按 README.md 的安装说明,可用npx skills@latest add mattpocock/skills把选中的技能文件复制进你的项目后按需修改;Claude Code 用户可用claude plugins install mattpocock-skills安装整套受管只读插件。
  • 对 Codex 等 Agent,技能通过agents/openai.yaml(仅含display_name: "Prototype")声明接口。
  • 落地时建议先通读三份核心文件:SKILL.md(总纲与公共规则)、LOGIC.md(逻辑分支)、UI.md(UI 分支),再结合 wayfinder、to-spec、handoff 理解它在整条决策流水线中的位置。

最后的提醒:一旦你发现自己开始"加固"某个原型——加测试、接真实数据库、为一个"以后可能会用到"的情况做泛化——你就已经停止了原型化。保持问题窄、运行时间短、产物可分享、答案落 main、证据留分支,这六条纪律合在一起,就是原型从"烧 token 的临时脚本"变成"工程设计的一手资料"的全部秘密。

【免费下载链接】skillsSkills for Real Engineers. Straight from my .agents directory.项目地址: https://gitcode.com/GitHub_Trending/skills13/skills

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/12 1:44:22

FlatBuffers .NET 测试指南:在 Linux 上运行与清理 NetTest 测试套件

FlatBuffers .NET 测试指南&#xff1a;在 Linux 上运行与清理 NetTest 测试套件 【免费下载链接】flatbuffers FlatBuffers: Memory Efficient Serialization Library 项目地址: https://gitcode.com/GitHub_Trending/fl/flatbuffers 导读 本文以 FlatBuffers 仓库中的…

作者头像 李华
网站建设 2026/9/12 1:44:14

Java流程控制语句详解:从原理到性能优化

1. 流程控制语句&#xff1a;程序逻辑的骨架与脉络第一次接触Java的新手常会困惑&#xff1a;为什么同样的几行代码&#xff0c;在不同条件下能产生完全不同的结果&#xff1f;答案就藏在流程控制语句里。作为从C语言继承而来的核心语法结构&#xff0c;流程控制决定了代码的执…

作者头像 李华
网站建设 2026/9/12 1:41:33

asdf 安装前置依赖指南:git 与基础工具的检查、安装与验证

asdf 安装前置依赖指南&#xff1a;git 与基础工具的检查、安装与验证 【免费下载链接】asdf Extendable version manager with support for Ruby, Node.js, Elixir, Erlang & more 项目地址: https://gitcode.com/GitHub_Trending/as/asdf asdf 是一个可扩展的版本…

作者头像 李华
网站建设 2026/9/12 1:39:36

OPPO到realme手机数据迁移全攻略

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/12 1:36:52

Godot引擎2D射击游戏子弹系统开发指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华