Huzzah:一种用 AI 编程的新范式
文章摘要
作者 Daniel Vaughn(自 2009 年起做前端工程)说 2026 年头几个月对工程师来说「难以置信」——编码 agent 突然好到不需要手写代码了;但蜜月期结束后他撞了墙:到了 8 月,他感到「彻底疲惫」,厌倦了为每一处改动都写长篇英文,同时又不想回到全手写代码的乏味里。他的论证链条是三条具体的抱怨,而不是笼统的「AI 不好」:
(1)没有可靠的人类意图记录。 prompt 用完就丢,代码到底是不是 AI 生成的也无从判断——那个「表达人类想让机器做什么」的中心权威消失了。(2)聊天式 prompt 是命令式的、逐步的,描述的是「对应用做的改动」而不是「应用本身」,因此指令在开发过程中被反复重述、反复消耗 token,效率低下。(3)自然语言里很大一部分是为社交功能存在的,不是为传递信息,平均一句话的真实信息量很稀薄,用这种方式对机器说话很累赘。
针对这三点,他做了个实验性编辑器 Huzzah,把 prompt 的三个属性整体翻转:coding agent 的 prompt 是「长篇 + 命令式 + 一次性」,Huzzah 的 prompt 是「伪代码 + 声明式 + 持久化」。工作流是:新建一个 fizz_buzz.hz 文件,用你自己喜欢的方式写伪代码(他给的写法大意是 fizz_buzz() 下面缩进写 loop 100、modulo 3 ? "fizz"、5 ? "buzz"、both ? "fizz buzz");保存时编辑器自动生成真实代码。要改需求时直接改文件——比如把 loop 100 改成参数化的 fizz_buzz(n) / loop n——保存时 Huzzah 捕获 diff 并把 diff 当作 prompt,只重新生成受影响的源码。他还给了购物车(list cart / add_item(id) / checkout() 返回 cart.sum(item by price) 并格式化成价格)和 Todo List(含带类型的 Todo 结构、toggle_todo 里 todo.completed = NOT .completed)两个例子。
他列出的好处:伪代码比长篇 prompt 简洁可读得多;写它时你的脑子是投入的,感觉像在「设计代码的形状」;详略程度完全由你控制;因为是人写的,它天然就是开发文档;还可以写语言无关的伪代码,作为多语言/多环境目标的共同基础(他举的例子是 CRDT 这类复杂算法)。他也诚实列了 caveats:这套做法在大规模场景下可能有问题;更适合新项目而非既有代码库;如果你缺少领域专长,自然语言反而更好用;跨文件依赖这类东西可能难以可靠表达;LSP 类功能会失效(虽然理论上也能生成)。项目目前只是概念验证(web app,跑在 localhost:5173),源码在 github.com/danielvaughn/hz。他在 HN 自述里补充了一个文章里没强调的关键点:编辑器会持久化伪代码与生成代码之间的 source map,任何一行生成代码都能追溯回产生它的那行伪代码。
HN 评论精华
这条 Show HN 有 379 分、209 条评论,作者本人几乎逐条回复,讨论质量很高。主线是三问:这跟已有的东西(spec-driven development、字面编程、UML、commit message、PDL)有什么区别?伪代码这层抽象是不是「用 LLM 当编译器」的倒退?以及扩展到多文件/模块级还行不行? 另有一条相当长的哲学支线跑到了「agent 时代还算不算编程」上。
- smicallef 的框架被多人接受:大家(被 LLM 赋能的工程师)其实是在找合适的抽象层级——写长句子加偶尔审阅「太远」,让 LLM 在 IDE 里贴着你干「太近」;他觉得这个方案还是偏向旧的低层做法,但比上面两者好。floatrock 把它总结为「创建一个自定义 DSL,只是 LLM 的灵活性让这个 DSL 可以是临时的」,并追问:什么时候会需要正式的刚性语法?还是「没有刚性语法」本身就是重点?能塞进多少「信息噪声」才会让这个「DSL 编译器」犯糊涂?他还指出规模问题:伪代码适合写函数,但写模块呢——「如果你要写一整段话来改一个函数的行为,你就没充分利用 LLM;段落最适合用来规定模块」。作者承认模块/目录层级完全未经测试,他猜想写
use some_fn from $repo/some/path之类 LLM 大概能推断出来,但得实测。 - quasarj 一句尖锐的质疑:「我糊涂了,你不就是发明了一门更简洁的新语言,只是现在编译要花钱?」kennywinker 回护说其实没有语言(伪代码怎么写都行),而且「你 prompt LLM 本来就在花钱,只是换成了散文」。dcchambers 补刀:「严格说所有编译都要花钱(电费),这只是……低效的编译。」作者回答:正是如此,只是这门「语言」现在零约束,可以是你意图的完美提炼——代码是语法上完美,因为它必须完美(编译器容不下多少歧义),但那不等于它完美表达了你的想法;语言设计的很大一部分是为编译器服务,不是为作者。Kinrany 给出这条支线最精炼的反驳:「如果伪代码是精确的,你想要的是编译器;如果不精确,那 LLM 还是在替你做决定。」
- r0ze-at-hn 最不客气:「没有可靠的人类意图记录」——他带过的每个工程师都上过「怎么写好 commit message」这一课,这就是那个东西;Huzzah 看着像在重新发明「给代码写文档」。他推测作者刚毕业或没在有良好工程实践的团队待过。kennywinker 反驳(贴出作者 2009 年起做前端的自述)说「不喜欢这个方案就直说,不必贬低人」。作者的回应是有分量的:好的 commit message 不是人类意图的记录,而是人类意图变化的记录;你能读 changelog 看到代码库的演化,但在 AI 之前源码本身是那个「直接表达软件当前预期行为」的单一制品,AI 之后这个制品还在,但它不再是人类意图的真实记录了。r0ze-at-hn 再回:重点是好的 commit message 会比这个提案活得更久;这类想法有很长的历史——字面编程、UML 建模、DSL 热潮,现在是 LLM 生成的抽象——它们总以和「给代码加注释」相同的方式失败,甚至可以说单元测试也是这个问题的近亲,而且为什么 Huzzah 比直接用 property test 更好?
- madrox 说「把伪代码和生成代码放在一起持久化」就是重新发明了 Jira/Linear 工单和 PR 描述。作者的回答同上:那些追踪的是代码的变化,不是代码本身。wccrawford 提出更实际的担忧:它会像注释一样快速过期——很多代码改得很快,之后伪代码基本就没用了,除非你去更新,而那是一份全新的工作量。
- leobg 问了个「笨问题」:为什么不直接在 harness 的 system prompt 里写「如果我给你伪代码,就把我的意图展开、写成真实代码并测试」?作者说完全可以,Claude Code 火起来之前他用 Cursor 就是这么干的——写点伪代码、选中、说「make it real」,效果很好。问题是在很大或很复杂的代码库里,你会忘记哪些是 AI 生成的、哪些是人写的,而且 AI 生成的代码极其难读,于是你的自然倾向变成让 agent 帮你总结,那又有一堆问题。zahrevsky 的建议被作者认可:为什么不做成一种「模糊语言」+ CLI「build」命令,让
.hz文件住在代码库里、在你喜欢的编辑器和 shell 里用,而不是逼人开 localhost:5173 的 Web UI?作者说下一步正是做成能访问文件系统的桌面应用;之所以现在要自己控制整个 UI,一是伪代码的语法高亮「难得离谱」(他很惊讶居然能跑起来),二是 source map 生成目前放在自控环境里容易得多。 - cpeterso 给出了最有价值的历史对照:这让他想起 Steve McConnell《Code Complete》(1993)里的 PDL(Program Design Language)——先用 PDL 伪代码写,别人可以先评审你的 PDL 再写实现,最后把 PDL 留作代码注释。maxwg 则指出概念上很像 HN 上的 codespeak 项目,作者说 codespeak 看着不错,正是在做 source map 那一步。
- avaer 提出了反方向的诉求(并获得不少支持):更重要的是逆向——把一个巨大复杂的代码库分解成简短伪代码,然后你编辑伪代码、再编译回系统。因为大项目上的工程师本来就这么工作:先在自己能理解的层级上摸清系统状态,再在简化表示上提改动,最后整体更新到可运行格式。mym1990 讽刺「你觉得这不特别难,让我怀疑这句话之后的一切」。andai 给了真实的失败数据:他做过一个叫 cleanroom 的 LLM 原型,把程序转成 spec 再转回程序,结果「令人作呕」——spec 会把各种无关的实现细节编码进去,新版本再忠实地重新实现一遍,膨胀到原来的 3 倍,正好是他想要的反面;他的结论是 LLM 和人有同一个毛病,它不知道原始意图是什么,也分不清什么是本质、什么是偶然。作者说这基本就是他的经验,也是做这个项目的动机之一——他在公司让 LLM 从一个大而复杂的代码库生成产品文档,几乎没帮上忙,于是得出结论:代码库里需要有一条硬边界,团队约定只有人手可以碰它,否则整个仓库在「探明意图」这件事上就不可信了。
- saejox 说全行业都在解决「怎么读懂 AI 生成的代码库」这个问题,而这就是 spec-driven development,只是把用例和需求换成了伪代码;他自己试 spec-driven 失败了,猜这个方案也会栽在「一大堆没人想读的文字」上。作者回答自己也试过 spec-driven 并且也失败了:他不想读那堆文字,而且 spec 会和代码脱节,于是工程师最后让 LLM 去更新 spec——现在 spec 不但是一大堆文字,还是 LLM 生成的,你完全不知道它是否反映真实意图。他强调 Huzzah 的差别在于逐行 mapping 和「因为是代码所以简洁」。
- ryanisnan 提了一个对 fizzbuzz 例子的锐利批评:作者的伪代码里点名用了 modulo,也就是说你必须已经知道怎么实现 fizzbuzz;而传统 agent 那段 prompt 里除了「Create a function that…」这点命令式语言外,其余是声明式的状态描述,不要求特定编程语法和语义知识。他自己的做法是给验收标准一个更正式的位置和语法,再用它生成测试和实现。
- markiannucci 提出了调试时的隐患:以后别人读你的伪代码时会隐含假设代码被正确翻译了——如果翻译错了,那个人是不是每次都会漏掉这个 bug?他建议 Huzzah 应该有个守卫来识别有两种解释的伪代码并要求人类澄清。作者承认真正的版本需要这类安全机制和错误处理,因为你很容易写出 LLM 根本没法实现的东西。
- lofties 和 globular-toast 都提到自己早已在做类似的事:写好完全带类型注解的函数签名、加一句注释说明期望行为、返回空,然后让 LLM 填实现;后者说这是他 LLM 之前就偏好的自上而下写法(先接口和测试、后实现),出自 SICP,「愿望驱动编程」。作者说这正是这个编辑器要做的,区别在于你最初写的版本被保留下来并 source-map 到它生成的代码。
- 哲学支线由 reticulates 引爆,是全场最长的一条:他认为作者搞错了疲惫的来源——问题不是写英文,而是变化的速率;编程是冥想式的、是思考过程,你输出的代码是思考的产物;agent 开发里没有思考、没有冥想,你把思考外包给机器,只是没完没了地对它吼你想要什么。他的结论是「要么当程序员写代码,要么当委派者去委派,别试图骗自己说你在编程」。darthcircuit(自称不是全职开发)反驳说思考并没有消失,只是「新的编程语言就是你的母语」,AI 是终极的橡皮鸭,让他能实现搁置多年的想法。bah9 反驳这句:工程关乎实现而非结果,「现在的『思考』只是在检查模型有没有理解你想要什么」,我们更接近一个动手试新产品、给工程师反馈的产品经理;他还说这句「AI 打开了全新世界」他总是恰好从「不是全职开发」的人那里听到——这确实为不写代码的人打开了新世界,同时为热爱写代码的人摧毁了旧世界。fzeindl 引了一句他从 agentic SDLC 讲座里听到的话作为总结:「检查工作和做工作不是一回事。」——有人爱写代码但不爱审代码,反之亦然;而且认知负荷不同,检查一个成品程序或算法可能比在产出过程中把它想通更难。
- pizzly 提供了另一个角度:agent 开发意味着更多思考,只是像基层管理者那样思考——更多时间做架构决策、UI 决策、协调自己和 agent 的时间;对很多入行时并不擅长这些的人来说,这确实极其累人。jsjsjdjdjdb 强烈反对这个类比:他在这行快二十年,从没见过工程经理做架构决策(那是他或 tech lead 的活)或 UX 决策(那是 Product 的活),「等我的 LLM agent 开始请病假和轮值 on-call 了,我再来听这套『你是管理者』的鬼话」。
- a2ff6eeb0 是最激进的乐观派,多处出现:他认为「深入理解基本功」已经不再必要,只需要浅层理解加大量手工测试;架构决策应该几乎全部交给 agent,因为它见过的架构比你一辈子能见到的多;「AI 的进步一直快于人们能处理的项目复杂度的增长,两条线很快就要交叉」。作者对此的回应划出了边界:在一定复杂度范围内(比如 AI 之前很多 web 开发者在做的普通 SaaS CRUD)这基本成立,但过了某个规模/复杂度点就会迅速崩掉,而如果你只靠 agent 走到那个点,你会陷入大麻烦,因为很难回溯。vdombr 则从职责角度反对:手工测试本来有 QA、塑造业务需求本来有 BA 和 PO,现在开发要三合一?
- tamimio 给了一个尖锐的反向类比:这套做法像「招了个 10x 超级工程师,然后用一堆没用的流程、会议和团建把他的工作卡死」——用几十亿参数的模型的意义就是不要用你有限的知识去限制它。
- qarl2 的一句话点出了评论区的气氛:「发这种东西需要很大勇气。评论区里满是从没用 agent 写过代码、却非常确定这是他们见过最蠢的东西的人。干得好。」
- luciana1u 留下了最漂亮的一句反讽:终局是一个团队的 git 历史全是生成的 commit,而唯一真正记录了意图的那份简短文本,没人想到要提交。