Steven
Steven1 分钟阅读

从容的软件:终结闪烁的开关,让聊天助手告诉你它在用哪种模式回答

GeekBye 的两个小版本,没有任何头条级新功能——只是让一个设置开关不再闪烁,让聊天助手终于会告诉你它是用会议模式还是编程模式回答的。这就是"从容的软件"真正的代价,一个细节一个细节地攒出来。

产品
设计
工程
GeekBye 发布
从容的软件:终结闪烁的开关,让聊天助手告诉你它在用哪种模式回答

不是每个版本都是一场硬仗。有些版本只是一份清单,列着一堆几乎看不见的小毛病——它们不会让任何东西崩溃,却会让一个应用显得有点不值得信任、有点毛躁、有点不那么"属于你"。GeekBye v2.0.3v2.0.5 就是这样的两个版本。没有新功能。只有从容。

"从容的软件"听起来像是一种情绪。它其实是一堆具体的决定。这里讲其中三个。

一个拿不定主意的开关

有一个设置开关——就是控制音频恢复的那个——你一点它就会闪烁。你把它点开,有那么一瞬间它显示为 ,然后猛地弹回 ,最后才稳定下来。只是一个极小的视觉抖动,可你的眼睛会捕捉到,它读起来就是 这个应用不确定自己在干什么。

原因是一种经典的 UI 竞态,叫做乐观更新(optimistic update)。当你点击一个开关时,应用有两个选择:等设置真正保存好之后再更新开关(正确,但感觉卡顿),或者立刻翻转开关、在后台保存(感觉即时)。GeekBye 选的是第二种——立刻翻转——但它 同时 又在保存值返回时重新读取了一遍。于是过程就是:你点击,开关乐观地翻到开,真实的保存值晚一拍到达,在那一帧里两者不一致,开关就明显地弹了一下。

修复的办法,是让乐观值和确认值干净利落地达成一致——开关认定你选择的状态,在保存确认回来时不再自我怀疑。与此同时,v2.0.3 还做了一次并不光鲜的文案梳理:恢复音频的描述被精简,好和它旁边的同类项对齐,设置里的措辞也更像人话了。这些都算不上功能。但所有这些加起来,就是"一个感觉是被工程实现出来的设置面板"和"一个感觉是被人细心打磨过的设置面板"之间的差别。

一段赖着不走的引导

新手引导恰好只有用一次。问题就出在这个"一次"上:当你已经看过它之后,一个无法关掉的引导浮层就变成了杂讯,它在暗示 这个应用觉得你还是个新手。 v2.0.3 把这两头都修好了——产品引导现在可以隐藏了,而如果你真想再看一遍,还有一个重看引导按钮。有用的时候展示,没用的时候让开,并让用户按照自己的意愿把它召唤回来。承认用户已经不再是新手,本身就是一种小小的从容。

那个不肯说清自己怎么想的助手

这才是真正重要的一个,它牵连着一个我们一直在追的更深的问题。

GeekBye 的助手会根据场景给出不同的回答。在会议里,"你觉得这个怎么样?"应该得到一个对话式的、懂会议语境的答案。在编程会话里,同样这句话应该得到一个技术性的答案。所以后端会用对应的框架来处理这个问题——就叫它会议模式编程模式——而这层框架,实实在在地改变了你拿到的答案。

麻烦在于:应用从不告诉你是哪个模式回答了你。所以当助手对一个对话式的问题给出编程味十足的回复时——或者反过来,把一个代码问题当成闲聊来回答时——它看上去就像 AI 单纯 答错了。 它并没有错;它只是在另一个模式里,而你没有任何办法看到这一点。一个隐藏的状态,让正确的行为看起来像是坏了。(模式逻辑本身是更大的一块工作——那个决定在编程会话中如何回答非编程问题的编排器——但如果你连它做出的决定都 看不见,这一切对你都毫无用处。)

v2.0.5 给聊天加了一个只读的模式标签:一个小小的标记,显示助手是用会议模式还是编程模式回答的。只读是重点所在——它不是你去设置的控件,而是 一扇窗,让你看到系统已经做出的决定。 你不必再猜为什么某个答案感觉不对劲;你能看到它是从哪个框架里出来的。

让这个标签诚实的那个细节

这里有一个值得分享的工程选择,因为正是这类东西,把一个"硬贴上去的指示灯"和一个"值得信任的指示灯"区分开来。

模式信息来自后端,作为流式响应的一部分——在服务器发送事件(SSE)流里的一个小小的 mode 帧。但一个早于这个功能的老客户端,并不知道 mode 帧是什么;往好了说它会忽略这一帧,往坏了说它会渲染出一堆乱码。所以客户端会声明自己的能力:它发出一个请求头,说 我知道怎么显示模式标签, 而后端只会把 mode 帧发给那些发过这个请求头的客户端。老客户端永远收不到它处理不了的信号;新客户端拿到的正是它请求的那一帧。

这是一次只用一个请求头的握手,而它就是"我们加了个功能"和"我们加了个功能却没有搞坏任何还没更新的人"之间的差别。同一轮评审还收紧了其余的行为:这个标签会在重置时、以及在对话上下文变化时自动清空(一个过时的模式标签本身就是一个小小的谎言),而且它只在它该在的聊天视图里显示。

两个"没有功能"的版本教会我们的事

  1. 抖动是一种信任信号。 一个闪烁的开关、一次弹跳的切换、一个多停留了一帧的标签——从崩溃的意义上说它们都不是 bug,但每一个都在低声说 这个应用没完全掌控局面。 从容就是这些低语的缺席,而你只能一个竞态一个竞态地把它挣来。
  2. 一个隐藏的模式会让正确的行为看起来像 bug。 助手做的是对的事,却因此挨了骂,纯粹是因为用户看不到它用的框架。当你的系统做出一个改变输出的隐形决定时,就把这个决定亮出来——一个只读的标签往往就是全部的修复。
  3. 新功能对用不了它的客户端应该是隐形的。 能力请求头的握手意味着模式信号只会抵达那些能渲染它的客户端。向后兼容不是事后补上去的一次版本检查;它是客户端说清自己能理解什么,而服务器尊重这个答案。

这些都是没人会为它写更新日志头条的版本,而它们恰恰是 GeekBye v2 之所以是现在这种手感的重要原因。想了解这份从容所建立其上的那个版本,见 做出一个 version 2 究竟要花多少(v2.0.0)。想了解与之并行的可靠性工作,见 我们的应用把自己 DDoS 了的那一天(v2.0.1)以及 为什么你的 AI 会议记录会在会议进行到一半时停止录制(v2.0.9)。

相关文章

一个 CSS 变量、五轮评审,还有一个撒谎的 Swift 工具链
Steven
Steven1 分钟阅读

一个 CSS 变量、五轮评审,还有一个撒谎的 Swift 工具链

GeekBye v2.0.7 让整个悬浮层变得可调节的半透明 — 这听起来像是一行 CSS 的改动,但绝对不是。真正的故事在于代码评审抓到了什么: 两个死活不肯变淡的面板、一个在同样透明度下看起来不对劲的录音条,还有一个来回变化了 672 字节的编译二进制文件,只因为我们自己的文档告诉了评审者一个错误的 Swift 版本。

工程
设计
构建
将软件打磨到完美的解剖学:代码审查如何抓住测试抓不到的问题
Steven
Steven1 分钟阅读

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

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

工程
流程
代码审查
你的 Mac 应用授予了麦克风权限 — 然后每次启动都忘得一干二净
Steven
Steven1 分钟阅读

你的 Mac 应用授予了麦克风权限 — 然后每次启动都忘得一干二净

GeekBye 请求麦克风权限,你授予了,它也确实能用。可下次启动:没了。而且这个应用压根就没出现在「系统设置 → 隐私与安全性 → 麦克风」里。罪魁祸首是 macOS 一个悄悄运行的安全特性,它让应用从一个转瞬即逝的路径运行 — 下面是诊断过程,以及那个一步搞定的修复。

macOS
权限
工程