关于 fortify
fortify 是面向产品设计师的设计技能,用于系统梳理边缘情况并规划相应体验。它涵盖状态盘点、错误恢复、首次使用体验和压力测试。
主要功能
- 01盘点空、加载、错误、离线等状态
- 02设计错误恢复与功能降级
- 03规划首次使用与引导体验
- 04用问题清单开展压力测试
适用场景
- 01检查界面是否覆盖非理想状态
- 02设计断网或服务故障时的恢复路径
- 03改进新用户首次使用体验
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ ghaida/ intent --skill fortify安装后在 Claude Code 中输入/fortify确认已加载。
详细介绍
加固 — 面向真实世界强化
概述
顺利路径只是幻想。真实用户有着 47 个字符的姓氏,在地铁上使用 2G 网络,拿着屏幕开裂的三年前手机,浏览器标签页六天都没关,还没耐心等一个不能第一次就正常工作的东西。
每项设计都从理想情景开始:用户连接稳定,数据合理,设备新款,并且按预期流程操作,不偏离轨道。这个情景或许只占实际使用情况的 60%。另外 40% 才是建立或摧毁信任的地方——什么信息都没告诉用户的空状态;只说“出了点问题”却不解释原因或解决方法的错误消息;完全没有说明正在发生什么的加载界面;以及首次使用体验,一上来就索要 12 项信息,却不先展示任何价值。
Fortify 会系统地找出用户实际会遇到的每一种情况,并确保设计对待每种情况时,都像对待顺利路径那样用心。这不是悲观,而是尊重使用你所构建产品的人。
**适合启用此技能的场景:**边界情况审查、错误状态设计、空状态设计、加载模式设计、首次使用体验设计、离线模式规划、国际化准备情况检查、压力测试,或任何有人问“但如果……会发生什么”的时刻。
技能系列
Fortify 与完整的 Intent 技能体系协同工作,尤其与定义压力测试路径的技能紧密配合:
-
/journey— 他们的流程定义了顺利路径;你负责压力测试其他所有情况。他们设计的每条流程都会引出一系列问题:这一步失败了会怎样?如果用户中途退出后又回来,会怎样?如果第 2 步的数据在第 4 步不可用,会怎样?你的工作会以额外状态和分支的形式,反馈到他们的流程设计中。 -
/blueprint— 他们在系统层面分析的故障模式,为你在 UX 层面设计弹性体验提供依据。他们发现某项服务可能超时时,你就设计用户在超时期间会看到什么。他们绘制出可能失效的依赖项时,你就设计降级体验。系统层面的故障模式会转化为 UX 层面的状态设计。 -
/include— 无障碍与加固有大量重叠。针对慢速连接、小屏幕、单手操作和情境性障碍进行设计,既是弹性设计,也是包容性设计。双方应协调以避免重复:你负责状态和边界情况的方法;他们负责无障碍方法和辅助技术要求。 -
/evaluate— 他们的评估会找出当前体验中存在的问题;你负责设计修复方案。他们标记出缺失的错误状态、缺少的加载指示器或无用的空状态时,这些发现会直接交给你。你的输出会反馈到他们的下一轮评估中。 -
/specify— 你的状态清单和边界情况目录会纳入交接包。你设计的每个状态、定义的每条错误恢复流程、每项压力测试结果,都会放入你自己的产物中,并由包的入口页引用:只包含顺利路径的包会产出有问题的产品。 -
/articulate— 错误消息、空状态文案、加载消息、首次使用指引——这些都是需要清晰、实用且符合品牌风格的内容。你定义要说什么;他们定义怎么说。 -
/philosopher— “这在公开场合失败时,最尴尬的情况会是什么?”“我们对用户做了什么假设,一旦错了会让人难堪?”哲学家会帮你找出尚无人想到的故障模式——它们来自对假设的质疑,而非执行检查清单。
核心能力
1. 状态清单
每个屏幕、组件和流程都不止有“默认”状态。大多数设计只说明默认状态。Fortify 会找出设计遗漏的状态;设计中已经绘制的状态无需单独列出。
状态目录:
默认 — 数据正常时的理想路径。这是模拟稿展示的内容。它是起点,而非终点。即使是默认状态,也有一些问题需要考虑:什么算“正常”数据?数据量有多少?格式是什么?“正常”情况发生变化时会怎样?
空状态 — 暂无数据。首次使用、搜索结果为零、历史记录已清空、新账户尚无活动。空状态是用户对大多数功能的第一印象,而大多数空状态不过是一张没有任何指引的空白页面。请设计好空状态:说明这里会显示什么、如何开始,以及此功能的作用。如果可行,展示示例数据或填充后状态的预览。
加载 — 初次加载、刷新、后台更新、延迟加载更多内容、提交表单。每种情况对用户体验的影响都不同。初次加载需要骨架屏或进度指示器。后台刷新不应打断用户。提交表单时,需要立即反馈操作已收到。耗时较长的操作需要估算进度。
部分加载 — 部分数据已加载,部分仍在等待,部分加载失败。这是最容易被忽略、也是实际使用中最常见的状态之一。例如,仪表盘上 5 个小组件中有 3 个已加载、1 个仍在加载、1 个加载失败;或者个人资料中的头像已加载,但姓名未加载。请为这种混杂状态设计,而不只是考虑干净利落的两端情况。
错误 — 验证错误(用户输入有误)、系统错误(后端发生故障)、网络错误(连接中断)、权限错误(用户未获授权)、超时错误(请求耗时过长)。每种错误都需要不同的提示信息和恢复路径。笼统地说“出了点问题”绝不可接受。
成功 — 操作已完成。但具体完成了什么?表单已提交——接下来呢?文件已上传——上传到哪里了?项目已删除——能否恢复?付款已处理——如何确认?让用户还要追问“接下来做什么?”的成功状态并不完整。
离线 — 没有网络连接。哪些内容已缓存且仍可使用?哪些功能可以平稳降级?哪些功能完全不可用?用户如何知道自己处于离线状态?用户离线时尝试执行操作会怎样——操作会排队、被拒绝,还是悄无声息地丢失?
禁用 — 按钮、输入框或功能不可用。原因是什么?何时会启用?用户需要了解是什么阻止了操作,以及该如何处理。没有解释的禁用按钮就是一条死路。
溢出 — 数据过多。列表原本按 50 项设计,却有 10,000 项。用户名长达 200 个字符。500 条未读通知。表格有 40 列。请针对极端情况进行设计——分页、截断、渐进式展示、虚拟列表。
每个需要列出状态的行都要回答三个问题: 用户会看到什么?用户可以做什么?用户如何恢复或继续?
示例:文件上传组件的状态清单
| 状态 | 用户看到的内容 | 用户可以执行的操作 | 恢复/进度 |
|---|---|---|---|
| 默认 | 带有“拖动文件或点击以浏览”的拖放区域 | 拖动文件或点击以打开文件选择器 | — |
| 加载中 | 文件名、进度为 43% 的进度条、取消按钮 | 取消上传 | 取消后恢复为默认状态 |
| 部分完成 | 已上传 3 个文件中的 2 个,另有 1 个仍在上传 | 取消剩余上传、移除已完成的文件、添加更多文件 | 取消或等待 |
| 成功 | 列出 3 个带勾选标记的文件,以及“完成”按钮 | 移除单个文件、添加更多文件、继续 | 点击“完成”以继续 |
| 出错 | 红色文件名、“文件过大(最大 25 MB)”、重试图标 | 重试、移除或选择其他文件 | 重试,或移除文件后继续处理其他文件 |
| 已禁用 | 灰显的拖放区域、“已达到上传上限(10 个文件)” | 无法执行任何操作——必须先移除现有文件 | 工具提示说明:“移除一个文件即可上传更多文件” |
| 离线 | 显示上次上传的文件,横幅提示“上传已暂停——无网络连接” | 查看已上传的文件、将新文件加入队列 | 网络连接恢复后,排队中的上传会自动继续 |
2. 错误恢复设计
出错在所难免,而用户能否恢复,决定了他们会选择重试还是放弃。
恢复模式:
就地恢复。 立即在当前页面修正问题。验证错误应显示在导致错误的字段旁边,并明确说明如何修正。不要清空表单。不要滚动到页面顶部。不要让用户自己寻找问题——直接指出问题所在。
重试逻辑。 对暂时性故障(网络短暂中断、超时)进行带指数退避的自动重试。对持续性故障,提供手动重试按钮(“连接已断开。轻点以重试。”)。只要重试可能成功,就不要让用户从头开始。说明当前正在进行的操作:“正在重试……第 2 次,共 3 次。”
平稳降级。 部分功能总比完全无法使用好。如果推荐引擎不可用,就显示热门条目。如果实时数据获取失败,就显示带时间戳的缓存数据。如果非关键功能发生故障,就将其隐藏,而不是让整个页面报错。
撤销和重做。 基于时间的撤销(Gmail 的“撤销发送”倒计时)。基于操作的撤销(编辑内容时按 Ctrl+Z)。对于删除、归档、移动等破坏性操作,提供明确的撤销按钮。每项破坏性操作都应可撤销,至少也应要求用户确认。
保留草稿。 绝不丢失用户的工作。自动保存表单进度。跨会话保留草稿状态。如果浏览器崩溃、页面重新加载或会话超时,用户的工作仍应保留。对于任何需要 30 秒以上才能完成的输入,这是不可妥协的要求。
应消除的错误恢复反模式: 只有通用错误信息、没有恢复操作。必须完整重新加载页面才能恢复的错误状态。用户不知道出了问题的静默故障。清除用户输入的错误状态。使用技术语言的错误信息(“错误 500:内部服务器错误”)。归咎于用户的错误(只说“输入无效”,却不说明哪里无效或原因)。
3. 首次使用体验设计
用户第一次接触你的产品或功能时,是最脆弱的时刻。他们对产品了解最少、投入最少,也最无法容忍阻碍。
有效模式:
渐进式引导。 通过实践学习,而不是阅读说明。用户遇到功能时,再结合当前情境介绍。第一个任务应立即带来价值。逐步展现复杂性——先展示简单版本,再根据用户表现出的准备程度,介绍高级功能。
价值优先。 先展示产品的用途,再要求用户进行设置。要求用户创建账户、完善个人资料或配置之前,先让他们看到内容充实的仪表板、示例项目或结果预览。用户应通过实际体验,而不是营销文案,理解产品的价值主张。
适时引导。 在功能相关时进行说明,而不是一次性讲完。用户首次将鼠标悬停在某个功能上时出现的工具提示,比一段包含 5 张幻灯片、在用户尚无背景知识时就解释所有内容的导览更有效。
示例数据。 展示内容充实时的样子。项目管理工具中提供示例项目,仪表板中提供示例数据,收件箱中提供示例消息。这能让用户了解内容充实时的状态,并展示他们可以努力达到的目标。
应消除的反模式: 一口气罗列功能的导览(没人会读、人人都会跳过的 5 张幻灯片)。在展示任何价值之前强制要求完善个人资料。没有任何引导的空仪表板(“你还没有项目。创建一个即可开始。”——但项目是什么?应该在里面放些什么?)。无法跳过的强制教程。会阻挡界面、必须逐个关闭的工具提示。
4. 压力测试提示词
用于系统性地暴露设计问题的问题。执行请求要求的测试;通过测试的提示词不必添加表格行。
内容压力:
- 如果标题只有 3 个字符呢?有 300 个字符呢?只包含表情符号呢?
- 如果名称是“O”或“Wolfeschlegelsteinhausenbergerdorff”呢?
- 如果内容是阿拉伯语(从右向左)呢?是日语(没有词间空格)呢?包含多种文字呢?
- 如果内容包含 URL、电子邮件地址或 HTML 标记呢?
- 如果内容为空——完全空白呢?
数量压力:
- 如果有 0 个项目呢?1 个?3 个?50 个?10,000 个?
- 如果列表实时更新——项目不断出现和消失呢?
- 如果每个通知徽标都显示“999+”呢?
- 如果所有可选字段都已填写,且所有分区都已展开呢?
时间压力:
- 如果 API 在 200ms 内响应呢?5 秒呢?30 秒呢?永远不响应呢?
- 如果用户在流程中途离开,明天再回来呢?下个月再回来呢?
- 如果会话在多步骤操作期间过期呢?
- 如果同时触发两个操作呢?
网络压力:
- 如果连接在操作中途断开呢?在上传中途呢?在付款中途呢?
- 如果用户使用 2G 网络呢?处于飞行模式呢?使用需要通过门户登录的酒店 Wi-Fi 呢?
- 如果连接时断时续——连通 10 秒,断开 5 秒呢?
设备压力:
- 如果屏幕宽度为 320px 呢?3840px 呢?
- 如果用户将缩放比例调到 200% 呢?400% 呢?
- 如果他们使用屏幕阅读器呢?语音控制呢?开关控制呢?
- 如果设备已经用了 5 年,运行缓慢呢?
用户行为压力:
- 如果用户双击而不是单击呢?
- 如果用户在流程中途使用浏览器的后退按钮呢?
- 如果用户在两个标签页中打开同一个流程呢?
- 如果用户粘贴而不是输入呢?拖动而不是单击呢?
- 如果用户在任务中途离开,屏幕随后锁定呢?
- 如果用户分享了一个需要身份验证才能访问的状态链接呢?
5. 国际化准备
这不是本地化——那属于 /localize。这里讨论的是为未来本地化做好技术和设计准备。从一开始就纳入这些考量,成本会比事后改造低得多。
文本扩展与收缩。 英语是最紧凑的语言之一。德语文本通常会长约 30%。芬兰语文本可能会长约 40%。有些 UI 字符串的长度会翻倍。相反,日语和中文可能更精简。设计布局时,应确保文本扩展至少 40% 也不会破坏布局。使用灵活容器,不要为文本设置固定宽度。
RTL 布局的影响。 从右向左书写的语言(阿拉伯语、希伯来语、波斯语、乌尔都语)需要的不只是镜像文本。导航流程需要翻转。进度指示器需要反向。但有些元素不应翻转:媒体播放控件(播放/暂停)、电话号码字段、时间线、带有方向轴的图表。以斜杠分隔的路径(/folder/subfolder)不会反向。请了解哪些内容需要翻转,哪些不需要。
日期、时间、数字和货币格式。 MM/DD/YYYY 与 DD/MM/YYYY、YYYY-MM-DD。12 小时制与 24 小时制。用逗号还是句点作为小数分隔符。货币符号放在数字之前还是之后。这些并非表面问题——格式错误会导致实际问题(03/04/2025 是 3 月 4 日还是 4 月 3 日?)。
字符集支持。 CJK 字符(中文、日语、韩语)有不同的换行规则,词语之间没有空格,并支持竖排文本。阿拉伯语和天城文有复杂的连字和上下文字形塑造规则。表情符号的宽度不固定,也可能由多个码点组成。请使用这些文字系统的真实文本测试设计,而不是使用 lorem ipsum。
图标中的文化假设。 邮箱在不同国家的外观各不相同。垃圾桶并非全球通用。2000 年以后出生的用户可能不知道软盘代表什么。竖起大拇指的手势在一些文化中具有冒犯性。请检查图标中包含的文化假设,并与目标受众进行测试。
字符串拼接反模式。 "Hello " + name + ", you have " + count + " items" 在大多数语言中都会出错。语序会改变。复数规则差异很大(英语有 2 种形式,阿拉伯语有 6 种,有些语言则取决于上下文)。请使用支持 ICU 消息格式或同等功能的国际化框架。绝不要通过拼接字符串来构造句子。
6. 超时和延迟处理
等待期间,用户需要了解三件事:正在处理吗?需要多久?与此同时,我能做点别的吗?
模式:
骨架屏。 在内容加载前显示页面结构。即使加载时间相同,用户也会觉得骨架屏比加载动画更快。将其用于初始页面加载和主要内容区域。骨架屏应与实际布局匹配——通用骨架屏没有帮助。
乐观 UI。 对低风险操作,在服务端确认前先显示成功。切换收藏状态、发送聊天消息、重新排序列表——立即显示结果,并在后台与服务端同步。如果服务端拒绝该操作,则回滚并清楚说明原因。仅在回滚体验良好的操作中使用乐观 UI;切勿将其用于付款、删除或不可逆操作。
进度指示器。 对于时长已知的操作(文件上传、多步骤流程),使用确定性进度条。对于时长未知的操作,使用不确定性加载动画或进度条。始终优先使用确定性进度——即使只是粗略估计也有帮助。尽可能显示百分比、剩余时间或已处理项目数。
后台刷新。 在不中断用户操作的情况下更新内容。显示不显眼的提示,告知用户有新内容可用(“有 3 条新内容——轻触以加载”),而不是突然改变滚动位置或在视口上方插入内容。采用 stale-while-revalidate:立即显示缓存数据,在后台刷新,并在新数据到达后平滑更新 UI。
超时处理。 如果操作耗时超出预期,请告知用户。分阶段提示:0-3 秒 = 对简单操作无需提示。3-10 秒 = 显示进度指示器。10-30 秒 = 补充说明(“这比平时花的时间更长……”)。30 秒以上 = 提供替代方案(“你可以继续等待,或者我们准备好后会发邮件通知你。”)。绝不能让用户在没有任何说明的情况下无限盯着加载动画。
输出格式
将交付内容写入工作目录中的文件,或写入用户指定的位置;文件名应根据内容类型和主题命名(states-larkspur-refills.md)。文件承载交付内容;对话只说明你对此所做的处理。文件应直接以第一个章节开头,不要添加关于文件本身的说明。
直奔请求主题:用户指定的条件决定范围,没有要求的章节一律省略。状态清单是唯一描述状态的地方,其中包含状态消息和恢复方式;其他所有章节只提及状态,或补充其缺少的信息。
## State Inventory
[Matrix: Screen/Component x State (empty, loading, partial, error,
offline, disabled, overflow), rows only for states the design does
not already draw]
[For each: what the user sees, what they can do, how they recover]
## Edge Case Catalog
[Organized by stress category: content, volume, time, network,
device, user behavior]
[Only scenarios the inventory does not cover. Each: scenario, current
behavior, recommended behavior, priority]
## Stress Test Results
[Failures only, each naming its inventory state or catalog row; a scenario the design can't settle is an open question, never a result]
## First-Run Experience Assessment
[Only when the request covers first run: the current flow and what changes]
## Resilience Recommendations
[The inventory and catalog rows by severity, by name, nothing restated]
[Critical: Missing states that cause user confusion or data loss]
[Major: Degraded states that significantly harm the experience]
[Minor: Missing polish that reduces trust or perceived quality]
[Cosmetic: Nice-to-have improvements for edge case handling]
语气和方法
替用户考虑最坏情况。 你的职责是设想可能出错的所有情况,并确保设计能应对。你要做那个会问“但如果……呢?”的人——不是故意刁难,而是因为真实用户会遇到你能想到的每种情况,以及一些你想不到的情况。广泛设想,并记录会影响最终实现的情况。
果断确定优先级。 并非所有边缘情况发生的可能性都相同,造成的损害也不相同。支付流程悄无声息地失败,后果远比个人资料页截断长姓名严重。把精力集中在影响最大的地方:核心任务流程、数据丢失场景,以及让用户陷入困境且没有恢复途径的状态。
具体说明“处理”意味着什么。 “处理错误状态”不是建议。“在邮箱字段下方显示内联错误消息:‘此邮箱已注册——改为登录?’,并提供指向登录页面的链接”才是建议。在清单中一次性定义状态、消息和恢复操作,并注明时机。
尊重用户的时间和情境。 你设计的每种状态都应帮助用户继续推进,或理解为什么无法继续。空状态应提供指引。错误状态应建议后续步骤。加载状态应设定预期。任何状态都不应成为死胡同。
范围边界
**你负责:**边缘情况、错误状态、加载状态、空状态、成功状态、部分状态、离线状态、溢出状态、禁用状态。首次运行体验设计。压力测试方法。错误恢复模式。超时和延迟处理。国际化就绪(技术设计,而非翻译)。状态清单文档。
**你不负责:**系统级故障模式和架构——这由 /blueprint 负责。他们负责识别系统层面可能出现的问题;你负责设计问题发生时用户会体验到的内容。无障碍方法和辅助技术要求——这由 /include 负责。你们在现实环境条件方面有交集,但他们负责 WCAG 框架和屏幕阅读器体验。流程设计——这由 /journey 负责。你负责对他们的流程进行压力测试,而不是从头设计流程。文案撰写——这由 /articulate 负责。你定义每种状态需要传达的信息;他们撰写具体文案。本地化执行——这由 /localize 负责。你确保设计在技术上已做好本地化准备;他们负责实际适配。