Steven
Steven1 分钟阅读

将软件打磨到完美的解剖学:代码审查如何抓住测试抓不到的问题

纵观 GeekBye v2 系列,同样的事情反复上演:一个修复在开发者的机器上通过了每一项测试,随后代码审查证明它对几乎所有人都会失败。这就是九次发布背后的工作流程——审查关卡、先修复后收网的拦截、以及把“在我这儿能跑”变成“它就是能跑”的发布前测试纪律。

工程
流程
代码审查
GeekBye 发布
将软件打磨到完美的解剖学:代码审查如何抓住测试抓不到的问题

在短短几周里,GeekBye 发布了九个版本——从 v2.0.0 到 v2.0.11——本系列讲述了其中每一个的故事。把它们连起来读,会跳出一个比任何单个 bug 都更有意思的模式:一次又一次,一个修复在开发者的机器上通过了每一项测试,而代码审查证明它对几乎所有其他人都会失败。

那道鸿沟——横亘在“在我这儿能跑”和“它就是能跑”之间——正是可靠性真正栖身之处。这就是弥合它的工作流程,也是它所催生的每一次发布的索引。

这个模式:测试全绿,答案却错

下面是本系列中三个最清晰的案例,因为它们把抽象化为了具体。

  • 多显示器捕获修复(v2.0.10)中,第一版实现把屏幕捕获锚定在了应用的悬浮窗上。它通过了测试——在一台单显示器的开发机上。审查推理了那个悬浮窗实际处在哪里(永远在主显示器上,除非你亲手把它拖走),并证明这个“修复”对几乎每一个真实用户都会重新解析回错误的显示器。正确的锚点——光标——是从那场论证里得出的,而不是从某次测试运行里得出的。
  • WebSocket 回退发布(v2.0.8)中,审查发现一个拦截型代理返回的那个确切 403 被归类为致命的鉴权错误——于是这个功能存在的意义所在的回退根本不可能触发。这个功能本会照常发布、通过它的顺利路径测试,却对它真正的受众毫无作为。
  • 空闲超时修复(v2.0.9)中,第一版把“仍然存活”的时钟盖章打在了一个代码路径里,而一部分转录本会合理地跳过这个路径——也就是对方说话人的那部分。审查抓住了这一点:将来的一次改动可能悄悄重新引入正在被修复的那个确切 bug,于是时间戳被移到了某个无条件执行的地方,并配上一个测试把它固定在那里。

这些没有一个是靠运行代码抓住的。它们全都是靠审查者推理代码为什么能工作——并找到一个它不能工作的情形——才抓住的。

这道关卡的三个部分

本系列背后的工作流程并不繁复。它是三个毫无例外地贯彻的习惯。

1. 审查推理正确性,而不只是运行代码。 一个通过的测试证明的是:代码对你想到的那个情形能工作。而审查是系统的第二个、对抗式的模型,在追问你没想到哪个情形?——第二台显示器、企业代理、跳过分支的转录本、落后一个版本的客户端。本系列中的审查环节常常是一个独立的智能体审查者,被提示去驳倒这个修复,而不是给它盖章放行。这个立意就是全部要点所在:一个试图击穿你推理的审查者,会找到那个试图批准你的审查者一扫而过的漏洞。

2. 每一个行为修复都随附一个把确切故障钉死的测试。 不是一个证明功能能工作的测试——而是一个证明这个特定 bug 已经死掉的测试。被拦截代理的 403 必须落入回退;一个真正的鉴权 403 则绝不能。活跃时钟必须在一个跳过归属判断的转录本上盖上时间戳。这些测试存在,是为了让 bug 在六个月后有人在附近重构时无法悄悄回归——故障被钉死在了地板上。

3. 构建在发布前经过公证和验证。 这些修复中有几个从诊断到一个签名、公证、自动更新的发布只用了一天。这种速度之所以安全,只因为关卡足够自律:诊断证明了根因(麦克风权限发布发出了它的诊断),测试把修复钉死,审查驳倒推理,然后才让一个真正的公证构建上线。严谨是让速度安全的东西,而不是与速度此消彼长的东西。

为什么这对一个 AI 应用更重要

这套纪律之所以对像 GeekBye 这样的工具尤其没有商量余地,是有原因的。本系列中几个最棘手的 bug 都是悄然出错,而非崩溃喧闹型的:一张把错误的显示器喂给 AI 的截图(v2.0.10)、一次偏向垃圾术语以至“speak”被识别成一个人名的转录(v2.0.11)、一个用错误模式作答却无从察觉的助手(v2.0.3 + v2.0.5)。当你的应用把上下文喂给模型时,一个错误的输入会产生一个自信满满的错误输出,而任何地方都没有报错。你无法靠测试摆脱那些不会抛出异常的故障。你只能靠推理摆脱它们——而这正是审查关卡的用武之地。

本系列,按顺序

下面每一篇都是围绕一次发布的独立案例研究。从头读到尾,它们就是把一款产品从“能用”带到“可信”的解剖学。

  1. 一个版本 2 究竟需要什么:206 次提交换来诚实的状态 —— v2.0.0。地基所在:绝不显示一个不为真的状态。
  2. 我们的应用把自己 DDoS 了的那一天 —— v2.0.1 + v2.0.4。一个启动时的上传积压踩踏了我们自己的后端,以及它逼出来的存活性阶梯。
  3. 从容的软件:闪烁修复与作答模式标签 —— v2.0.3 + v2.0.5。没有新功能的发布,一次一个细节地换来信任。
  4. 你的 Mac 应用每次启动都忘掉麦克风权限 —— v2.0.6。macOS 应用位移(App Translocation),以及在修复之前先发出诊断。
  5. 一个 CSS 变量、五轮审查,和一条撒谎的 Swift 工具链 —— v2.0.7。统一的半透明,以及一个因为文档与强制脚本互相矛盾而改变了大小的二进制文件。
  6. 当防火墙拦截 WebSocket 时的实时转录 —— v2.0.8。一个纯 HTTPS 回退,以及那个本会把它对自己隐藏起来的 403
  7. 为什么你的 AI 会议记录助手会在会议中途停止录制 —— v2.0.9。一个只能听见你的空闲计时器,以及一次可能锁死你桌面的崩溃。
  8. 为什么屏幕录制捕获了错误的显示器 —— v2.0.10。选错显示器的 bug,以及那个在一台显示器上通过、却会在两台上失败的修复。
  9. 为什么 AI 转录会听错技术术语 —— v2.0.11。把语音偏向你的词汇表——以及那次先让情况变糟、然后才让它变好的回归。

要点

完美不是一个你抵达的状态;它是一道你守住的关卡。九次发布,每一次都有同样的三个问题:你没想到哪个情形,确切的故障有没有被测试钉死,以及一个真正的签名构建到底有没有发出去? 这一切都不光鲜。而这一切正是 GeekBye v2 让人感到从容的原因。如果你在构建软件——无论是 AI 还是别的——可迁移的部分不是任何单个修复。它是这样一个习惯:把一整套绿色测试当作论证的开始,而不是它的终点。

上面每一次发布都已通过自动更新上线。想看看这些修复加在一起构成的产品,请看 GeekBye v2 有什么新变化