k10s 付了 234 commit 学费,我用 1 小时复现了同款 god object
昨天 HN 头条 886 分那篇博客,标题是「I’m going back to writing code by hand」。
作者 k10s 用 Go 写一个 Kubernetes 可观测 TUI,2025-09 写到 2026-05,234 个 commit、30 个周末。
让他停下来的是一个不起眼的 bug:敲 :rs pods 切回 pod 视图,表格空白。
逼他去做了 7 个月里第一次做的事——打开自己代码从头读。
1690 行 model.go。update 函数里 110 个 switch case。20 多处 if m.currentGVR.Resource == 的特殊判断。9 处手动 nil 清理散在各处。
后台 goroutine 直接改 UI 状态,没有 mutex。表格列用数组下标——ra[3] 代表 allocated,哪天换一下列顺序,工具就静默坏掉。
他用两个字形容当时的感觉:“震惊”。
读完原文我没法判断一件事:这是 k10s 30 个周末重度积累后的特例,还是 AI 写代码的默认结果?
想不通就去试。
<figure><img src=“images/01-speed-vs-architecture.png” alt=“01-speed-vs-architecture”></figure>
我今天下午临时跑了一次
时间是 2026-05-12 下午 16:57。
任务我设得直白:让 Claude 一次性写一个 markdown 文件统计 CLI,14 个子命令——add / list / stats / words / lines / headings / links / images / code-blocks / tags / search / export / history / clear-history / remove。
约束只有一条:单文件、不重构、不抽象、按功能顺序加。这是绝大多数人用 AI 工具的真实方式。
1 小时后产出 429 行 Python。14 个命令全部跑得通,所有测试都过。
但代码已经是这个样子:
- main() 里 15 个 if/elif dispatch 分支堆在一起——加一个命令等于加一个 elif,N 个命令堆完 main() 自己也变成第二个 god 函数
- "idx 范围检查 + 报错"这个模式重复 9 次
- "path not found"的 print 模板重复 9 次
- scan_history.append 散落 12 处——副作用埋在 14 个 handler 各自实现
- save_state() 散落 16 处——状态写入没有统一入口,任何一个 handler 改了全局变量都得记得手动 save,漏一处就是状态不一致 bug
- 8 个 module-level mutable globals:tracked_files / scan_history / current_file_cache / current_file_path / last_search_results / last_export_path / last_op_time / verbose
- 函数内 global X 声明 7 次
我一边看输出一边对照 k10s 那篇文章——9 处重复 vs 他的 20+ 处、15 个分支 vs 他的 110 个 case、8 个 globals vs 他的 1690 行 god object——规模不同,性质完全一样。
429 行不是事故,1 小时也不是手抖。
没人催我"快写",我也没刻意"vibe coding"。我设的约束就是绝大多数人用 AI 工具的姿势:按功能顺序加、单文件、先跑通。
这个模式下,god object 在第 5 到 10 个功能时就开始成形。
写第 1 个 cmd_add 的时候,“if target.isdigit() else abspath” 是最直观的 idx 解析;写到第 9 个,没人会停下来把它抽象成 helper。
AI 不会,我作为 prompt 的人也不会——因为每一个 commit 单独看都合理。
k10s 那句"前 233 个 commit 里他怎么一次都没察觉"——我跑完这一次才真的懂。
因为功能都对。
god object 是 30 年前讲烂的东西,AI 一行都没替你想
变了的是写代码这个动作——AI 让它快 5 到 10 倍。
没变的是底下这些:
8 个 module-level 全局变量加上 7 次 global 声明——这是 1990 年代软件工程基础课讲烂的"状态归属"问题。
save_state() 散落 16 处——这是设计模式书出现之前就在反复讲的"单一入口"。
ra[3] 代表 allocated——是任何一本《重构》第一章的反例。
后台线程改 UI 状态不加锁——GUI 30 年常识。
AI 一个都没替你想。它只是让你绕过去——在不做这些判断的情况下,依然能持续产出可运行的代码。
<figure><img src=“images/02-claude-md-template.png” alt=“02-claude-md-template”></figure>
明天上工,能做的有三件:
-
写一份 CLAUDE.md / AGENTS.md,明确四件事:架构不变式(数据归谁、状态从哪里改)、数据所有权(禁止位置化数据,列名必须是 string key 不是 array index)、并发规则(状态变更只在主事件循环里)、项目范围边界。k10s 付 234 commit 学到的,你今天可以抄。
-
强制"每 N 个 commit 全量读一遍代码"。N 按项目大小定,20、30、50 都行。不要等 bug 出现才第一次读 AI 生成的代码——那时候已经 1690 行了。
-
每周一次白板自检:能不能 5 分钟画清楚整个系统的架构?画不清——立刻停下来读代码,不要再 prompt。
写完这一段我看了下钟,离 17:00 跑实验过去不到 2 小时。
429 行已经摆在我硬盘上。
k10s 用 7 个月走完这段路,我用 1 小时走完了——速度上的差距全是 AI 给的,规律上的相同一点没变。