最近用 AI 写页面,布局、样式和简单交互确实快了不少。生成一个能点的保存按钮不难,困难是确认它在请求失败、重复点击、切页和继续输入时仍然保存了正确内容。
这让我更在意任务约定与状态流。代码生成越方便,遗漏的条件越容易跟着一个看起来完整的界面一起通过评审。
保存成功需要一个真实依据
按钮发出请求、界面弹提示和服务端实际写入是不同事件。需求要约定失败保留输入,提交期间怎样处理重复操作,成功从哪个返回结果更新状态。
接口还要说明空值、分页、单位和错误码。空数组究竟是没有数据,还是错误被兜底吞掉,不能只靠组件猜。提供真实的接口形状与典型错误,比让模型根据界面名字发明数据结构更有帮助。
一次请求固定提交快照
async function saveDraft(snapshot: Draft, expectedRevision: number) {
const response = await fetch(`/api/pages/${snapshot.id}`, {
method: "PUT",
headers: {"Content-Type": "application/json", "If-Match": `"${expectedRevision}"`},
body: JSON.stringify(snapshot)
});
if (response.status === 412) return {kind: "conflict"} as const;
if (!response.ok) throw new Error(`save failed: ${response.status}`);
return {kind: "saved", document: await response.json()} as const;
}示例假设服务端用该版本号表达强 ETag,实际客户端应采用服务端返回的实体标签。412 表示前提不满足,交给冲突处理,不按普通网络失败重试。
请求发出后,用户可能继续输入。回执只能更新已保存基线,不能拿旧快照盖掉新内容。可以保存 dirtyRevision,回执时比较,说明还有哪些修改未保存。
保存状态至少区分 idle、saving、conflict、failed 和 saved;新输入使 saved 回到待保存状态。把所有情况压成一个 loading,界面就无法说明当前在等什么。
请求乱序不是取消就能保证正确
用户选 A 马上选 B,A 请求可能最后返回。响应携带对应参数版本,只允许当前版本更新当前视图。取消旧请求减少开销,版本检查处理无法取消或已经返回的情况。
同样,旧请求 finally 不能清掉新请求的加载状态。切换页面后返回的结果,也不能修改新页面。静态截图看不到这些错误,需要实际构造顺序。
评审沿着一次用户操作读代码
我会从点击跟到请求、业务结果、状态更新和界面反馈,查数据在哪变、权限由谁检查、异常由谁接住。局部函数优雅,不足以说明完整任务正确。
有副作用的请求还要说明重复提交与重试行为。方法叫 PUT 或 POST,不能替代业务操作键和下游实际保证。
测试针对风险:双击不重复创建,500 不显示成功,冲突有处理入口,保存时继续输入不丢,切页后旧响应不更新新对象。为每一行实现配相同逻辑的断言,可能只是重复实现里的假设。
人需要保留对修改的判断
如果已经看不懂生成代码的数据流,结果不对时就只能换句话继续问,很难知道它解决什么、又引入什么。
我目前愿意交出去的是重复输入,保留的是对任务、接口和状态的理解。原来的前端与架构经验没有失效,只是还得变成清楚的约定和可检查的行为。不用预测以后各写多少代码,眼前这次保存是否正确,就已经有具体标准。