速度的债务

速度的债务

风格:Paul Graham(essay 体)


上周我丢了六个番茄。

不是超市里的番茄,是番茄钟——我用自己写的 App 记录的六段专注时间。它们因为一个 token 过期的 bug,在重新登录时被静默清除了。永久丢失,无法恢复。

六个番茄钟,大约三个小时的工作记录。放在任何规模的公司里,这不算事故。但对我来说,这件事的刺痛程度远超它的实际损失。

因为它暴露了一个我一直在回避的问题。


我现在同时运维着五个个人项目:番茄 App、ClawChat、OpenClaw、喝水提醒、还有一套数字资产知识体系。全部用 AI 辅助开发。

AI 确实让我快了很多。一个后端服务,从零到上线可以压缩到一天——ClawChat 的后端就是 3 月 2 日一天之内推了十个 commit 上去的。那种速度带来的兴奋感是真实的:你觉得自己像一个全栈团队,什么都能做,什么都在推进。

但速度有一个性质,它不会告诉你自己是危险的。

3 月 5 日,ClawChat 开始返回“暂时不可用”。HTTP 上游不可达,系统直接给用户一个固定文案,没有任何自动回退。3 月 6 日,番茄后端雪崩了——一台 1 核 2GB 的阿里云小机器,用着 Tomcat 默认的 120 个线程,一条慢 SQL 触发锁等待,客户端疯狂重试,线程池耗尽,整个服务躺平。

两天,两次事故,两个不同的项目。


这两次事故表面上毫无关系。一个是聊天工具的上游不可达,一个是番茄钟的后端雪崩。但当你把它们放在一起看,会发现根因完全一样:我只设计了 happy path。

失败路径从来没有被当作一等公民。

这不是偶然的疏忽。如果你仔细想,会发现失败路径被忽略是一个结构性问题,而不是个人懒惰的问题。

写 happy path 有即时反馈——功能跑通了,你能看到它工作。写失败路径的回报是什么?什么都没有发生。你花了半天写了一堆异常处理逻辑,最好的结果是它永远不被触发。这种激励不对等会让所有人——不管多有经验——在时间紧张时本能地跳过失败路径。

而 AI 让这个倾向变得更严重了。因为 AI 进一步压缩了 happy path 的开发时间,让你觉得“功能已经做完了”的时间点来得更早。但失败路径不能被同比压缩——它需要你理解系统的边界条件,需要你被伤过才有真实体感。读十篇 best practice 也不如亲自丢一次数据。


速度创造了一种特殊的债务。

每上线一个新服务,你就签了一份永久运维合同。开发是一次性的,运维是永久性的。AI 把开发速度提了三到五倍,但运维面积也跟着扩大了三到五倍。

区别在于:开发时你有 AI 帮你写代码,兴奋感和进展感是实时的。运维时你一个人,凌晨三点服务挂了没人帮你看,你甚至可能在睡觉。

一天十个 commit 推上去时的那种感觉——“我好高效,我好强大”——实际上掩盖了一个事实:你刚刚给自己制造了一个需要永久维护的东西,而你对它的失败模式一无所知。

公司里有 SRE、有 oncall、有混沌工程帮你兜底。个人项目呢?没有人帮你兜。你就是 SRE,你就是 oncall,你也是唯一的用户。


我从这一周的事故里学到的最有用的一件事,不是“写更多测试”或“加更多监控”。

是这个:自愈优先于监控。

一个人运维的时候,告警是没有用的。告警来了你可能在睡觉,可能在开会,可能在另一个项目的深度工作里。你不可能 24 小时盯着。所以正确的问题不是“怎么更早发现问题”,而是“问题发生时能不能自动恢复”。

进程挂了?与其发通知等你来重启,不如让 systemd 自动拉起来。请求堆积了?与其发通知等你来限流,不如在代码里设好 max inflight,超了直接拒绝。上游不可达?与其发通知等你来排查,不如自动 fallback 到 CLI 调用。

以后给 AI 提运维需求时,默认先问一句:这个能不能做成自愈的?而不是先问怎么监控。


另一个刺痛来自那台 1 核小机器。

番茄后端跑在阿里云一台 1 核 2GB 的 ECS 上。Tomcat 默认线程池 200,HikariCP 默认连接池 10。这些默认值是面向多核服务器设计的——没有哪个框架会在文档里提醒你“如果你是单核机器请把线程数调到 8”。

我从来没改过这些参数。它们在正常情况下确实够用。直到一条慢 SQL 出现,线程全部阻塞,连接池耗尽,客户端重试把问题放大十倍,整个服务雪崩。

这是一个盲区。在公司里有 DBA 和 SRE 帮你做容量评估,你甚至不知道这件事需要有人做。等你自己做项目时,根本不会想到要检查线程池的默认值。

补上这个盲区其实只需要几分钟。单核机器,Web 线程池 4 到 8 个,DB 连接池 3 到 5 个,请求超时 10 到 30 秒。就这么几个数字。把运行参数从“默认没碰过”变成“我看过、我定的”就够了。

默认值不是安全值。这句话值得贴在显示器上。


这周还有一件小事让我警觉。

AI 给番茄后端写了一个 TimeConfig 的修复方案。测试通过了,AI 说“修复完成”。我信了,直接上线。结果发现改了一半。

这件事不大,但它揭示了人和 AI 协作中的一个缝隙:AI 说“完成了”不等于真的完成了。

我当前的工作流是:AI 写代码,AI 跑测试,AI 说完成,我上线。中间没有验收环节。这在 happy path 上没问题,在 edge case 上就会漏。

所以我给自己定了一个规则:以后让 AI 做修复或部署时,在需求最后加一句——修完之后,写一个部署后自动验证脚本,确认修复在线上真的生效。

代码正确性让 AI 验。功能可用性让 AI 验。线上真实性也让 AI 验。人只做最后一件事:判断体验好不好——这个功能用起来顺不顺,这个交互逻辑合不合理,下一步最该做什么。

AI 没有“作为用户使用产品”的真实感受。你作为唯一的真实用户,体验判断是不可替代的。


数据丢了之后我手写 SQL 把六个番茄补录回去了。补录能成功,是因为三个条件碰巧满足:我还记得、数据量小、我会写 SQL。这三个条件任意一个不满足,数据就永久消失。

这让我意识到,我对数据的保护方式是事故驱动的——番茄数据出过事所以备份了,ClawChat 还没出过事所以还没备份。不是设计驱动的。

盘点下来,ClawChat 的对话数据目前是裸奔状态。没有备份,没有恢复演练,一旦出事就是全量丢失。

“有备份”也不等于安全。很多人备份了但从来没恢复过,等真出事才发现备份是坏的。真正的数据安全有三级台阶:有总比没有好,能恢复比有备份好,自治运转比依赖人工好。


写到这里,我意识到这一周真正发生的事情不是“两次事故”。是一次认知升级。

从这些痛里,我提炼出了六份原则性文档。失败路径的三条底线。单核机器的容量基线。自愈优先原则。数据安全防护层次。人机协作验收模型。知识体系的进化机制。

这些文档不是规划出来的。它们是被痛出来的。每一篇都对应一次刺痛。

AI 时代最大的陷阱可能不是“AI 会不会取代你”,而是 AI 让你太快了——快到你来不及建立与速度匹配的判断力。你用一天时间上线一个服务,但你对它的运行环境、失败模式、容量极限的理解还停留在零。

速度是杠杆,但杠杆放大的不只是产出,也是风险。

唯一的解药不是减速——减速是反人性的。解药是在速度之后,主动补上那些被跳过的东西。每个项目进入运营期时,花半天时间过一遍:数据写入路径失败时会怎样?外部依赖有没有超时?关键链路有没有 fallback?运行参数是不是默认值?

半天的检查,能防住几个月的痛。

速度不是问题。不知道自己在负债,才是问题。