std::fs::write 是先截断、再写的。
一句话,出现在一篇 DEV 帖子的评论区。
发帖的是 Jessica Doering,在新罕布什尔念 IT,写的是「我用 AI 造东西的时候到底学到了什么」。评论区一个后端负责人 Pierre-Laurent Medori 去读了她编辑器仓库 Slate 的代码,读完回了这么一句:write_text 走的就是 std::fs::write,写到一半崩了,用户文档就是个残本。
我点进去之前以为又是「AI 让我变笨了」那种怅惘文学。不是。
现场不长,我给你摆一下。Slate 的保存有竞态:用户在写盘过程中接着敲字,盘上落的是旧内容,编辑器里是新内容。这时候把「未保存」那个小圆点清掉——等于跟用户说都存好了。
撒谎。
她的解法是记 revision:这次保存从哪个文档版本起手,写完发现版本变了,就继续标脏。那条测试叫 edits_during_a_save_keep_the_document_dirty。起得比大多数事故复盘的标题诚实。
她自己写得很清楚:AI 十分钟就能把这套 revision 逻辑实现完,她点两下保存按钮测一测也就过去了。她说那叫 miss the point。
我同意,但我想说得更难听点——那不叫错过一次学习机会。
那叫把一颗雷埋进保存按钮底下。
保存按钮是用户唯一会无条件相信的东西。接口报 500 他会刷新重试,弹个红框他会截图来问,唯独那个小圆点一清,他就去干别的了。他信的不是代码,是那个按钮。
这种班我值过太多次。真正让人半夜爬起来骂人的从来不是抛异常那次,是静默那次——盘上文件少了一半,界面上写着「已保存」,用户第二天来问文档怎么变成这样了,日志里干干净净。
补一刀:值班最怕的从来不是 500,是 200。
Medori 干的那件事,才是值班该干的事。他没问「这段为什么这么写」,也没在评论区跟楼主辩风格。他直接去看 write_text 到底调了什么。然后发现仓库里早就躺着 write_atomic——临时文件加 rename——只用在 settings 那个 JSON 上。
正确的那条路径已经在仓库里了。就差一次调用。
这个剧本我看过。新写的代码路径不复用老的、已经踩过坑的那条,跟 AI 一点关系都没有,十年前在「配置文件原子写、用户数据 fopen("w")」的项目里就是同一个德行。
换皮而已。
但他也没吹。他说原子替换用户文件得处理权限、软链接、硬链接,rename 之前还得 fsync,顺手把 Vim 的 backupcopy 拎出来当先例——意思是这事有代价,别以为换个 API 就完了。
这是老手说话的口气:知道补丁在哪儿,也知道补丁要花什么。
然后他自己扔出来一个:一个 API 确认删除成功,下一次读又把删掉的那条返回来了。同一个病,静默说谎。你看,连一眼能看出 std::fs::write 的人,也能随手拎出一个同款的静默 bug。
这类 bug 现在 AI 写得出来,也能给你解释得头头是道——截断和写入不是一次原子操作,等等等等。它唯一不会做的是觉得这有什么不对。
它不会在半夜想起那个小圆点。因为从来没人在它面前丢过文档。
她文中列的那几个可迁移的模式,我认。「异步操作在用户改动之后才完成」「性能问题其实是启动问题」「能算出来的状态却被存下来」——这三条比大多数架构分享实在。本地模型那 30 秒,到底是加载权重还是推理?跑第二次会不会更快?这个问法是对的,因为答案直接决定你该缓存什么、该在哪儿放 spinner。
但实话讲,多数人不会去量。多数人会问 AI 一句「为什么这么慢」,AI 编一个听着合理的答案,然后大家照着那个答案去优化错的地方。
两周后再来一次。这次问的还是「为什么这么慢」。
她自己划的边界也基本合理:按钮 padding、样板代码、干过很多遍的活,扔给 AI;不熟的地界、以后要自己维护的代码,自己下手,先猜一下改动会有什么效果再跑。不算新鲜,但她是自己想出来的,不是转述的。
让我把前面的话推翻一点:她承认自己也不总这么干,有时候磨了两个小时,拿到一个能跑的方案就收工了。
整篇里最可信的就是这句。能承认这个的人,比那些张口就「我有一套方法论」的靠谱。
扯远了,拉回来。
真正让我半夜想写这篇的,不是她学到什么,是这套做法搬到生产上之后,学费谁交。
她是个学生,自己写编辑器,账自己付。同样的动作放到线上系统,付账的是值班那帮冤种——功能一层层往上叠,最后你有一个能跑的应用,你只有模糊的理解。她自己那句话说得挺准:出货量被当成了学习。
这句该印在每一份「AI 提效」的 PPT 第一页。
怎么验?评论区两个人给的办法比任何「AI 学习法」都实用。一个说,隔几天不看解释,自己做个小变体——比如两次保存反序完成,未保存标记该显示什么?答不上来就是没学会。另一个说,用自己的话写一行注释,讲清这行解决什么问题;写不出来,说明你懂的是那段解释,不是那段代码。
他自己在做 IDE,把这种注释挂在行上——有点产品心,但方法干净。
我现在的规矩很简单:凡是「存盘」「删除」「发出去」这三类动作,代码里只要有一处先截断再写、或者先返回成功再落库,我不管它是谁写的,先当 Sev2 处理。
至于 AI 那段解释对不对——看它,不如看它到底写了什么。
