
Notes / 工程笔记
修复 Bug 之后,怎样真正吃透相关代码
从状态来源、正常路径、框架生命周期和测试脚本四个角度,整理一次修复结束后继续读懂系统的方法。
修好之后,最容易丢掉的是“为什么”
一个 Bug 能够复现、修复并通过构建,不代表我已经理解了相关代码。
如果只记住最后改了哪一行,下次遇到相似问题时,我仍然可能从界面表现开始试错。更值得留下的是:这个值原本从哪里来,哪一层第一次偏离,为什么另一个看起来合理的方向并不是根因。
最近几次状态问题给了我很直接的提醒:
- 生成结果预览显示了输入框现在的内容,而不是创建任务时的提示词;
- 新会话已经写进状态仓库,地址栏却仍保留旧会话标识;
- 页面已经开始离场,旧视图却根据新路由重新计算了自己的顶部状态;
- 自动化脚本报告“没有进入预览”,实际抛错的却是脚本里一行无关的调试代码。
它们的表面现象不同,继续追下去都在问同一件事:页面现在使用的值,究竟是不是这项业务事实的正确来源?
第一步:给每个值标出来源和时间
前端状态经常不止一份。输入框、组件属性、页面状态、全局仓库、URL、服务端记录和本地持久化里,都可能保存看起来相同的字符串或标识。
我先把它们分成三类:
- 当前值:用户此刻在输入框或页面上看到的内容;
- 事实快照:创建任务、发送消息或完成操作时实际使用的值;
- 恢复标识:页面重新进入后,用来找到同一项业务数据的稳定身份。
例如生成图片时,用户可能在任务提交后继续选择其他模板。输入框会变化,但已经生成的结果不能跟着变化。结果卡需要携带任务创建时保存的提示词快照,预览也应该读取这份快照,而不是在字段为空时回退到当前输入框。
修复本身并不复杂,重要的是把“生成结果属于哪次请求”重新写清楚。否则今天污染的是预览文案,明天还可能污染“复用提示词”等后续操作。
第二步:把两个状态源的优先级画出来
有些问题不是值缺失,而是两份状态都存在,却没有同步。
聊天页面的会话身份同时保存在 URL 和状态仓库中。旧会话进入页面时,URL 是可靠的恢复入口;新会话创建成功后,仓库会得到新标识。如果此时只更新仓库,地址栏仍然指向旧会话,离开页面再返回时,页面就可能按 URL 的高优先级重新加载旧内容。
这类问题可以先写成一条很短的优先级关系:
页面恢复时:URL 会话标识 > 仓库当前会话
新建成功后:新会话事实 -> 仓库 + URL 同步
当两份状态确实都承担职责时,不应该靠“以后大概会刷新”维持一致。需要在业务事实变化的那个时刻,显式同步两边;同时清理只属于旧会话的临时标记。
画出优先级后,我也更容易判断应该用新增历史记录还是替换当前地址。若只是把当前页面从“待创建”变成“已创建”,替换地址通常比再压入一层相同页面更符合返回语义。
第三步:用正常路径寻找第一次分叉
异常入口很复杂时,一个表现正常的入口往往是最好的对照组。我不需要把两条链路重新讲一遍,只比较相同数据从哪里开始使用了不同字段、哪一步之后才出现连锁偏差。
这个对照能把修改位置留在第一处分叉,而不是一路追到最终的预览组件。它也能保护已经正常的入口,避免修复范围继续扩大。
第四步:把框架和验证脚本也当成边界
如果现有证据指向路由缓存、组件生命周期或测试环境,我会再读相关源码,并检查脚本是否真的执行到了目标动作。源码可以证伪一个看似合理的框架假设;脚本日志也可能只说明验证过程提前失败,不能直接证明业务代码有问题。
这里不需要为每个误判再写一篇案例。我要确认的只有两件事:状态依赖是否属于当前组件,以及现有证据能不能覆盖我准备写下的结论。
修复后还会补做什么
一个问题修好后,我会用下面几步确认自己是否理解了它:
写出用户现象
-> 列出这个值的全部来源
-> 标出每份状态的更新时间和优先级
-> 找一个正常入口做对照
-> 定位第一次分叉
-> 排除框架与测试环境的假象
-> 记录验证边界
最后再用一句不依赖文件名的话解释根因。如果只能说“改了某个组件里的判断”,通常还没有吃透;如果能说明“预览读取了当前输入,而业务需要请求快照”,这条经验才有机会迁移到下一次问题。
验证仍然要保留边界
这几类问题中,有的完成了浏览器场景回归,有的通过了生产构建和定向检查,也有的仍需要真实设备或后端环境确认。
我不会因为找到统一的方法,就把所有案例写成同一种完成状态。理解代码也包括理解证据能证明到哪里:源码能够排除错误假设,构建能够证明打包链路,浏览器能够证明页面时序,真机和真实账号才能覆盖系统能力与完整业务结果。
修复 Bug 是交付的终点之一,但它也可以是重新理解系统的起点。
Recommended