3. On the LOC controversy
或者:当我提到我最近出货了多少行代码,以及实际数字到底说明了什么时,发生了什么。
批评是对的。LOC(代码行数)是一个垃圾指标。每个资深工程师都知道这一点。Dijkstra 在 1988 年就写过,代码行数不应该被算作“产出的行数”,而应该算作“消耗的行数”(《论真正教授计算机科学的残酷性》,EWD1036)。
那句老话(广泛归因于比尔·盖茨,但出处不详)说得更形象:用代码行数来衡量编程进度,就像用重量来衡量飞机制造进度一样。如果你用代码行数来衡量程序员的生产力,那你就 measuring the wrong thing(在衡量错误的东西)。这一点 40 年来一直成立,现在依然成立。
我在过去 60 天里出货了 60 万行生产代码。我发帖之后,回复来得很快:
- “那只是 AI 垃圾代码。”
- “LOC 是毫无意义的指标。过去 40 年每个资深工程师都这么说。”
- “你当然能产出 60 万行,因为你让 AI 写模板代码了。”
- “行数越多越糟糕,不是越好。”
- “你把数量和生产力混为一谈了。典型的 PM 脑子。”
- “你的错误率呢?你的 DAU 呢?你的回滚次数呢?”
- “这太尴尬了。” 其中有些说得对。下面是我认真对待这个聪明版本的批评、然后还是把数学算清楚之后的结果。
AI 编码批评的三个分支
它们常常被混为一谈,但其实是不同的论点。
分支 1:LOC 无法衡量质量。 正确。一直如此。一份 50 行的精心重构库,胜过一份 5000 行的臃肿代码。这在 AI 出现之前就成立,现在也成立。它从来不是致命的反驳,只是一个提醒:你要想想自己在衡量什么。
分支 2:AI 会膨胀 LOC。 正确。LLM 默认会生成冗长的代码。更多模板、更多防御性检查、更多注释、更多测试。即使“真正完成的工作”没变,原始行数也会增加。
分支 3:因此吹嘘 LOC 很尴尬。 这里论点就跑偏了。
分支 2 才是真正有趣的部分。 如果原始 LOC 被某个系数膨胀了,那么诚实的做法就是计算“去膨胀”后的数字,然后报告这个调整后的数字。这篇帖子的目的就是这么做的。
计算过程
我写了一个脚本(scripts/garry-output-comparison.ts),它遍历了我名下 garrytan/* 的全部 41 个 GitHub 仓库(15 个公开、26 个私有)中我亲自提交的所有 commit——包括 2013 年和 2026 年。对每个 commit,它只统计逻辑行数(非空、非注释)。2013 年的数据包括我那年构建的 YC 内部社交网络 Bookface。
2013 年是完整的一年。2026 年截至发帖当天(4 月 18 日)是第 108 天。
“每天 14 行?太惨了。” 是的,这正是重点。
2013 年我同时是 YC Partner,后来又联合创立 Posterous,只能晚上和周末写代码。每天 14 行逻辑代码,就是我兼职时的真实产出,而我当时还有全职工作。历史研究显示,全职专业程序员的产出范围很广,取决于项目规模:
- Fred Brooks 在《人月神话》中提到,系统编程大约 10 行/天(OS/360 的观察)。
- Capers Jones 在数千个项目中测得大约 16-38 LOC/天。
- Steve McConnell 的《代码大全》显示,小项目(1 万 LOC)是 20-125 LOC/天,大项目(1000 万 LOC)则降到 1.5-25 LOC/天——它和项目规模有关,不是一个固定数字。 我的 2013 年基线不是挑出来的。对一个有全职工作的兼职程序员来说,这很正常。如果你认为合理的基线是 50 行/天(高出 3.5 倍),那么 2026 年的倍数就会从 810 倍降到 228 倍,但仍然很高。
两次去膨胀
对“原始 LOC 是垃圾”最标准的回应是使用逻辑 SLOC(source lines of code,非注释、非空行)。cloc 和 scc 这类工具已经用了 20 年。去掉空白行、单行注释、注释块、尾随空格后,代码是一样的。
但逻辑 SLOC 仍然无法完全消除 AI 膨胀。AI 会写 2-3 个防御性 null 检查,而资深工程师可能一个都不写;AI 会在不会抛异常的地方包 try/catch;AI 会把 const result = foo(); return result 写成一堆废话,而不是直接 return foo()。
所以我们再做第二次去膨胀。假设 AI 生成的代码在逻辑层面比资深工程师手写代码冗长 2 倍(这已经很激进了——我见过的大多数测量结果是 1.3-1.8 倍,但我们按怀疑者会要求的最高上限来算)。
我 2026 年的每日速率(NCLOC):11,417 行
经过 2 倍 AI 冗长去膨胀后:5,708 行逻辑代码/天
经过两次去膨胀后的每日倍数:408 倍
现在你自己选先验:
- 5 倍去膨胀(没有依据,但我们算算):162 倍
- 10 倍去膨胀(病态情况):81 倍
- 100 倍去膨胀(不可能——那相当于每分钟持续写一行):8 倍 关于系数大小的争论,不会改变结论。这个数字无论如何都很大。
周分布
“你的每日数字假设产出均匀。把分布图拿出来。如果只是某一天爆发,那你的运行速率就是假的。”
合理。
它不是爆发。速率一直大致稳定,甚至略有上升。你可以自己跑这个脚本验证。
质量问题
这是最合理的批评,由 Sentry 创始人 David Cramer 代言:好吧,你推的行数多了,那你的错误率呢?合并后的回滚呢?bug 密度呢?如果你打字速度快了 10 倍,却出了 20 倍的 bug,那你不是被杠杆化了,而是在大规模制造噪音。
合理。这里是数据:
回滚:在 15 个活跃仓库中,git log —grep=“^revert” —grep=“^Revert” -i 显示 351 个 commit 中有 7 个回滚 = 2.0% 回滚率。成熟的开源代码库通常是 1-3%。你可以对自己认为的基准仓库跑同样的命令对比。
合并后修复:匹配 ^fix: 且引用同一分支先前 commit 的有 22 个(占 351 个的 6.3%)。修复周期健康。零修复率反而说明我没抓住自己的错误。
测试:这才是真正重要的东西,也是彻底改变我的东西。2026 年初我没写测试,被 bug 虐得死去活来。后来我把测试代码比提升到 30%,关键路径达到 100% 覆盖率,突然就能飞了。测试从 1 月份全仓库大约 100 个,增加到现在的 2000 多个。它们在 CI 中运行,能捕获回归。每个 gstack PR 的 PR 描述里都有覆盖率审计。
真正的洞见是:多层级的测试才是让 AI 辅助编码真正有效的东西。单元测试、E2E 测试、LLM-as-judge 评估、冒烟测试、slop 扫描。没有这些验证循环,你只是在高速生成自信的垃圾。有它们,你就有了让 AI 不断迭代直到代码真正正确的闭环。
gstack 的核心真实代码功能——不是单纯的 Markdown 提示——是我专门写的基于 Playwright 的 CLI 浏览器,这样我就不用手动黑盒测试了。
/qa 会打开真实浏览器,访问你的 staging URL,并运行自动化检查。那是 2000 多行真正的系统代码(服务器、CDP 检查器、快照引擎、内容安全、Cookie 管理),正是因为测试是解锁器,而不是负担。
/pair-agent 是我给自己做的很有趣的功能,让我的 OpenClaw 能在我的桌面 Chrome 浏览器里上网替我做事,我在一旁看着。它给你一个 MCP bearer token,并设置 ngrok/tailscale 隧道,让远程 agent 能做 GStack /browse 能做的所有事。
Slop 扫描:第三方(Sentry 创始工程师 Ben Vinegar)专门做了一个叫 slop-scan 的工具,用确定性规则衡量 AI 代码模式,并以成熟开源代码库为基准。分数越高 = slop 越多。他在 gstack 上跑了,得分 5.24,是当时他测过最差的。我认真对待,做了重构,一次就把分数降低了 62%。跑 bun test 就能看到 2000 多个测试全部通过。
审查严格度:gstack 的每个分支都要经过 CEO 审查、Codex 外部声音审查、DX 审查和工程审查。通常每个环节要过 2-3 轮。我刚发布的 /plan-tune 技能,因为 Codex 的外部声音审查发现了 15+ 个我的四个 Claude 审查都没发现的问题,而被迫把 CEO 扩展计划回滚。审查基础设施能抓住 slop,这在仓库里是可见的。任何人都可以读到。
我愿意承认什么
我要比批评者更彻底地 steelman(钢铁人化)自己:
- 绿地 vs 维护。2026 年的数字主要来自新项目。成熟代码库的维护每天产出行数会少。如果你问“Garry 能不能把维护银行 1000 万行遗留 Java 的团队 100 倍加速”,我的数字证明不了这一点。别人得在不同上下文里跑自己的脚本。
- 2013 年基线有幸存者偏差。我 2013 年的公开活动很少。但这次分析包含了 Bookface(私有,22 周活跃),那是我那年最大的项目,所以偏差比看起来小,但不是零。如果真实 2013 年速率是 50 行/天而不是 14 行,那么当前速率的倍数就是 228 倍而不是 810 倍。仍然很高。
- 质量调整后的生产力还没有完全证明。我没有 2013 年的我和 2026 年的 bug 密度干净对比。我能说的是:回滚率在正常区间,修复率健康,测试覆盖率真实,最新的 plan 经过对抗性审查抓住了 15+ 个问题。这是有力证据,但不是铁证。怀疑者可以打折。
- “出货”的含义在不同时代不同。有些 2013 年的产品出货后死了。有些 2026 年的产品可能也会。如果两年后我今年出货的东西 80% 都死了,那么“你建了一堆没人用的东西”这个批评就会有道理。我接受这个现实检查。
- 首次用户时间才是真正重要的指标,而不是 LOC。从“我希望这个东西存在”到“它存在了,有人正在用它”,60 天周期才是真正的转变。LOC 只是下游证据。正确的指标是“每季度出货的产品数”或“每周可用的功能数”。这些也上升了类似的倍数。 这些行代码变成了什么
gstack 不是假设。它是一个有真实用户的产品:
- 5 周内 75,000+ GitHub stars
- 14,965 个唯一安装(选择性遥测,所以真实数字至少是 2 倍以上)
- 自 2026 年 1 月以来记录了 305,309 次 skill 调用
- 峰值每周活跃用户约 7000 人
- 全 skill 运行成功率 95.2%(290,624 成功 / 305,309 总计)
- 57,650 次 /qa 运行、28,014 次 /plan-eng-review、24,817 次 /office-hours、18,899 次 /ship 工作流
- 27,157 次会话使用了浏览器(真正的 Playwright,不是玩具)
- 中位会话时长 2 分钟,平均 6.4 分钟 使用最多的技能如下(此处原文有图表)。
这些不是放在抽屉里的脚手架。每天都有成千上万的开发者在运行这些技能。
这意味着什么
我不是说工程师会消失。没哪个认真的人这么想。
我想说的是:工程师现在能飞了。2026 年的一个工程师,在相同工时、相同全职工作、相同大脑的情况下,产出相当于 2013 年 100 人团队。
代码生成成本曲线下降了两个数量级。
这个数字有趣的地方不是体积,而是速率。这个速率不是关于我个人的声明,而是关于整个软件工程地基的声明。
2013 年的我每天大约出货 14 行逻辑代码。对一个有全职工作的兼职程序员来说很正常。
2026 年的我每天出货 11,417 行逻辑代码。同时还在全职运营 YC。同样全职工作。同样空闲时间。同一个人。
差距不是我变成了更好的程序员。如果说有什么变化,我的编码心智模型反而萎缩了。差距在于 AI 让我真正出货了我一直想构建的东西。小工具、个人产品、以前因为时间成本太高而死在笔记本里的实验。“我想做这个工具”和“这个工具存在了,我正在用它”之间的差距,从 3 周缩短到了 3 小时。
脚本在这里:scripts/garry-output-comparison.ts。你可以跑在自己的仓库上,给我看你的数字。争论不是关于我——而是关于地基是否移动了。
它确实移动了。最棒的是,无论你对我、GStack、逻辑 SLOC 或任何其他东西有什么看法,事实就是:你也能飞。
——
GStack 刚刚发布 v1。它是我使用 Claude Code 的方式。它是 MIT 开源且免费的。这里试用。