Steven
Steven1 分钟阅读

一次 127 次提交的发布究竟是什么

GeekBye v1.7.0 在十一天里提交了 127 次。从外面看,这像是一百件小事。从里面看,它是两个大功能交织在一起 —— 而其中一个被建到了错误的地方,然后在发布中途被拆掉重建。这是一次大型发布的解剖。

工程
发布
架构
GeekBye 发布
一次 127 次提交的发布究竟是什么

有一个版本的这篇博文,只会把 GeekBye v1.7.0 里的一切一一列出 —— 重新设计的主屏、一个校准流程、一个可折叠的侧边栏、新的设置,如此这般没完没了。它会是准确的,也会什么都教不了你。因为一次 127 次提交的发布,诚实的故事不在那份清单里。它在于那个形状

形状是这样的。一百二十七次提交听上去像是一百二十七件小事。它几乎从来都不是。v1.7.0 是两个大功能,在约十一天里于长期存在的分支上并行开发,最后交织在一起。理解一次大型发布,意味着理解那两股线 —— 以及那一处我们把东西建错了地方、不得不在半空中把它拆回来的地方。

第一股线:校准

第一股线是校准 —— 一次对你沟通能力的 AI 语音评估。你与一位 AI"职业教练"开启一场实时通话,走完一组结构化的阶段(热身、行为、技术沟通、压力应对、目标设定),最后你会在六个维度上得到评分:自信、清晰、具体、投入、沉着、切题。在底层,它还会测量具体的言语指标 —— 你的语速、口头禅的频率、你的停顿读起来是有策略的还是犹豫的。

产出的不是一个分数,而是一个起点。校准会给出你的优势、你的成长空间,以及 —— 关键的 —— 一个建议你从哪个难度开始练习的档位。它校准的是产品应当在哪里迎接你。每一项技能都以一张可展开的反馈卡片返回,附带一段总结、一条具体建议,以及一句从你自己通话中实际引用出来的话作为例子。这个功能,是练习体验的其余部分赖以搭建的地基。

第二股线:一整个全新的窗口

第二股线是一次高级版重设计 —— 而把它叫作重设计其实低估了它。它不是给现有屏幕换层皮;它实际上是第二个应用窗口,分六个明确的阶段搭建出来:一个 Notion 风格的可折叠侧边栏、一个取代旧会话列表的顶部下拉菜单、带历史与面包屑的浏览器式导航,以及对主页、档案、会议和设置的高级版重建。

两个大功能。这才是 127 次提交真正的样子。而交付它们最难的部分,不是写出其中任何一个 —— 而是那个交织。这两个分支互相依赖;一个被合进了另一个,而校准分支不得不四次单独拉入 main 分支,才不至于在重设计于它脚下移动时漂离同步。提交数量不是一次大型发布的成本。长期存在的分支和集成顺序才是。

值得一读的部分:我们把校准建在了错误的地方

这就是那个错误,而它是个好错误,因为它太常见了。

GeekBye 有一条坚定的架构规则:所有 AI 操作都在后端。 客户端是一个与服务器对话的薄壳。人人都知道这一点。

然而校准最初被建在了客户端的本地数据库里。 一张专用的表、一次数据库迁移、一个 254 行的仓储、若干 IPC 处理器,以及一个 515 行的评估问题库 —— 全都住在用户的机器上。它能跑。它也悄悄违反了整个应用赖以建立的那份契约。

三天后,一次提交跨八个文件删掉了 680 行,把这一切都挪到后端,校准数据在那里成了一个正经的服务端模型,而问题逻辑和评分成了服务端的事。另一次提交则直接删掉了那 515 行的客户端问题库。这份 diff 几乎有点好笑:一处新增,六百八十处删除。

没人是奔着写 680 行一次性代码去的。它发生的方式,正是这类事情总是发生的方式:客户端的捷径就在那儿,本地原型跑得更快,而"我们回头再挪到后端"感觉起来无伤大雅。可当你的架构早已告诉你真相来源住在哪里,把它建在别的任何地方就不是捷径 —— 而是你给自己预先排好的返工。 留下来的教训是:把它一次性放到契约所说的地方,哪怕本地版本搭起来更快。

那个只有集成才能找到的 bug

再来一张收据,因为它是大型发布的标志性失败模式。一旦校准与新导航接到一起并真正跑起来,应用就开始触碰一个速率限制 —— HTTP 429 —— 没有任何显而易见的缘由。

原因纯粹在于集成。校准状态是在组件层级被 fetch 的,于是每一次导航都会重新去取它 —— 而 React 的 strict 模式,那个为了暴露 bug 而在开发中刻意双重调用副作用的机制,又把它翻了一倍。结果就是每次切屏发出四到八个一模一样的校准请求,足以触碰服务器的速率限制器。修复把 fetch 合并成了挂载时的寥寥几次调用。

单独测校准,或者单独测导航,你都不可能找到这个 bug。它只存在于那个接缝处 —— 两个各自正确的功能相遇之处。这就是一次大型发布收取的税:最后一公里不是把功能建出来,而是发现所有那些只在它们终于同处一室时才会坏掉的东西。

一次大型发布教给我们的三件事

  1. 一次 127 次提交的发布是两三个大主题,而不是一百件小事。 找到那些线。工作 —— 以及风险 —— 都住在它们如何交织,而不在那个数字里。
  2. 一次性把真相来源放到契约所说的它该住的地方。 我们删掉了 680 行,把校准从客户端搬到后端。本地捷径是你预先排好的返工;架构早就把答案告诉了你。
  3. 集成会暴露隔离测试暴露不了的失败。 那场 429 风暴住在两个正确功能之间的接缝里,只有等它们一起跑起来才现形。为一次集成通检留出预算,而不只是逐功能测试。

这是一个 v1 时代的表亲故事,我们会在大得多的尺度上再讲一遍 —— 见第二版究竟要付出什么:206 次提交的诚实状态(v2.0.0),在那里,同样那个"一个大数字其实是几个大想法"的真相,贯穿了整场 v2 重写。至于 v1 故事的上一章,见如何流式呈现实时报告而不闪烁(v1.6.13);而整条弧线,见把软件打磨到完美地交付的解剖学