主页 当编程变得不再有趣
Post
Cancel

当编程变得不再有趣

我刚才用 dyld 的 __DATA,靠 __interpose 机制拦截了 malloc/calloc/realloc 及 malloc_zone_* 全家,现场编了一个动态库挂到你的 app 上。一旦进程内出现 FAIL_NOW 环境变量,所有 ≥100MB 的分配请求直接返回错误,配合一个 mock server 完整重现了你收到的崩溃栈。我现在有 100% 信心确认这个问题并给出修复 ── Fable 5 (xHigh effort)

面对一个我觉得如此棘手的问题时,Fable 5 在五分钟内轻而易举地使出一招偷天换日,留我独自在黑夜中瑟瑟发抖。这一刻,我仿佛看到了传说中的“神之一手”。

我从小是听着很多有关编程的故事长大的:比尔盖茨如何把 QDOS 改造成 MS-DOS,求伯君如何一个人用汇编写出 WPS,Linus Torvalds 又如何把一个“只是爱好”的内核丢到新闻组里,最后让它长成了支撑半个现代互联网的 Linux。这些故事都充满了魔力。

这种魔力一直陪伴着我,让我认为编程是一件非常“具有魔法”的事情:从 ASCII 字符组成的咒文开始,经过编译器隐秘而精密的舞蹈,它们被拆解、重排、优化,最后变成一串机器能够理解的指令。那些指令并不只是抽象的符号,而是天赐的精灵,它们落到寄存器里,落到内存地址上,落到总线和缓存之间,变成一次次精准的搬运、跳转和比较。而在这表面之下,电路里的电子遵循优美的数学设计和严格的物理定律,沿着既定的路径奔跑,一个个晶体管随之在高低电平之间翻飞。无数个微小到几乎不可感知的状态变化,在时钟信号的节拍里排成队列,最终合奏出一个像素、一段音乐、一次网络请求,或者游戏世界里的一次次日升月落和一段段英雄传说。程序员就是魔法师:他们坐在键盘前,写下几行看似朴素的文字,然后某种不可见的力量就开始运转,机器按照人的意志苏醒,和这个世界说声你好,然后通过数据流奔向宇宙。

我本来以为这种体验会一直继续下去,直到我敲下生命中最后一行代码。但是最近,我却渐渐感觉这一切已经不再有趣,甚至让我对编程这件事产生了一些迷茫。我想,让我产生这种感觉的源头就是 AI,或者确切地说,是 Fable 5。

其实从去年年中在软件开发中高强度使用 agent 开始,于我而言,编程的乐趣就已经在一点点被剥夺了。大概是因为我不再亲自施法,那种实际解决具体问题的体验从生命中消失了;取而代之的是越来越多的事前规划和事后审阅,这让人非常疲惫。

当然,并不是说整个创造的乐趣不见了:创造本身依然让人兴奋,但是创造过程却被 agent 代劳,整个过程中我的参与和得到的回报都不可避免地变少了。

如果说过去一年,这种乐趣只是被稀释,我好歹还能在编程的副驾位置上混一混,那么 Fable 5 的出现,更像是有人干脆把我的整个驾驶室都端走了。

文章开头那段话,就是它对我说的。事情起因于 Kingfisher 的一个 issue:iOS 26.5 上出现了一类新的崩溃,崩溃栈死在 Data 拷贝的深处,一看就知道和大块内存的分配失败有关。这类问题最折磨人的地方在于复现:崩溃只在用户设备内存吃紧时发生,而你的开发机永远内存充裕,岁月静好。按以前的经验,我大概要搭进去一个周末:翻 crash log,读汇编,想办法搭一个内存压力的测试床,再祈祷运气站在我这边。我把 issue 丢给 Fable 5,本意只是让它先分析一下几种可能性。五分钟后,它回给我开头那段话:它现场编了一个动态库,用 dyld 的 interpose 机制让 malloc 全家“说谎”,凡是超过 100MB 的分配一律拒绝,再配上一个 mock server 喂出一个巨大的下载,让那个崩溃栈一字不差地出现在了屏幕上。

以前的模型面对这种问题,通常会礼貌地给我列出三五个“可能的原因”,外加一张详尽的排查清单,然后由我去跑腿验证。而 Fable 跳过了猜测这个环节,直接去拿了证据。

真正让我彻底绝望的是另一件事。前阵子我让它给 Kingfisher 的内存缓存加一个统计功能,算算缓存眼下到底占了多少字节,一个很小的活。它做完之后顺口提了一句:这里有个 bug。MemoryStorage 里用一个 Set 记录着所有缓存的键,而 NSCache 在内存吃紧时会自己悄悄清理对象,清完并不打招呼,于是那个 Set 里就留下了一批“亡灵键”。我去翻了 git blame:这段代码写于 2018 年 10 月,出自我本人之手。七年多过去,夫妻之间都该痒完了,而这期间 Kingfisher 跑在世界各地不知道多少台 iPhone 上,两千多条 issue 里无数双眼睛(也包括我自己的)从这几行代码上扫过,谁都没有看见它。而这一切发生的时候,没有人要求它去找 bug。它只是路过,看见了,顺手写了一个确定性的测试把正确行为钉死,然后继续去干手头的活,仿佛什么都没有发生。就像一位来家里做客的朋友,进门时随手把那扇吱呀了七年的门轴修好了,还没打算跟你提。

那几天我的心情说不上好。李世石宣布退役的时候说过,“即使自己成为第一人,也有一个永远无法战胜的存在”。2019 年读到这条新闻时,我只当它是围棋圈的一声叹息;如今轮到自己站在棋盘前,才真的明白这句话里的各种滋味。写了二十年代码,“能亲手解决困难的问题”曾经是我确认自己的方式之一。现在这个位置上坐着别人了,而且它不用睡觉,不会烦躁,也不需要成就感,只需要一点电力和两百美金。

在情绪慢慢褪去之后,我又开始想一些别的事情。编程确实被拿走了,可创作并不只有编程。我当然一直知道,软件从无到有,产品走向伟大,写代码仅仅只是中间那一段:在它之前,你要想清楚这东西为什么应该存在,给谁用,做成什么样子;在它之后,你要给它起名字,写下第一段介绍,看着第一个陌生用户提来第一个 issue。这些事 AI 都能帮忙,但拿主意的还得是人。今年做 Prowl 的时候,代码几乎没有一行出自我手,可是“一个终端应该如何对应一群并行的 agent”这个问题,是我趴在自己的工作流上一点点磨出来的。回想起来,那种快乐,和当年调通第一个 shader 时或者是学会 ARC 到底如何使用其实并没有本质区别,只是它们的来源从指尖挪到了别处。

工作里,我的位置也在跟着挪。从今年起,我的重心渐渐从一线面向用户的功能开发,转向了帮助团队进行 AI 建设:替同事搭建 agent 工作流,把 agent 关进沙盒里,让踩过的坑能被文档和 skill 填上,琢磨怎么让评审、开发、测试、发布这些环节都能吃到模型的红利,并把它们有机整合起来。说来有趣,这活儿的本质竟然还是编程,只不过调试对象从内存和线程,换成了流程、习惯和人心。机器听懂一句话只要几毫秒,而人接受一种新的工作方式,往往要几个月。这大概是眼下 AI 还替代不了的少数事情之一。

所以,编程于我确实不再有趣了,像是一场散了的宴席,桌上只留了几块鸡肋。但回头再看开头那个比喻,我却发现魔法其实一直都在那里:电子依然在电路里奔跑,晶体管依然在高低电平之间翻飞,时钟信号还是一拍一拍地孜孜不倦数着这个世界。变化的是念咒的人:我从魔法师退到了祈愿者的位置上,那施法用的华丽舞台倏忽一变,成了庙里投币的水池。我要做的只是瞄准池底的蛤蟆,然后用工程化的方法让蛤蟆们能“稳稳接住”我的硬币,然后吐出那些“最靠谱,最不绕弯的回答”。而说实话,想清楚自己要许什么愿,并不比背熟咒语来得容易(至少现在,还不是那么容易的事情)。

我的孩子们今后听到的编程故事里,大概不会再有求伯君和他的汇编了。但我想,他们会有属于自己的传说:也许是某个人带着一群 agent,在某个深夜里造出了谁也没想到的东西。魔力换了一种讲法,故事还在继续。这样想着,我好像又有点期待明天早晨,给猫娘们布置新任务的那一刻了。

该博客文章由作者通过 CC BY 4.0 进行授权。

sim-use - 给 agent 装上眼睛和手,让 mobile 开发跟上 AI 时代

-