阅读视图

发现新文章,点击刷新页面。
🔲 ☆

AI 编程时代,我挖出了一本 1999 年的“删库跑路”指南

本文永久链接 – https://tonybai.com/2026/04/06/how-to-write-unmaintainable-code

大家好,我是Tony Bai。

在这个由 Claude、GPT、Gemini等大模型定义的 2026 年,我们似乎已经习惯了 AI 那种近乎“洁癖”的编码风格:优雅的接口设计、滴水不漏的错误处理、以及永远对齐的工整格式。

AI 正在用它那冰冷的、毫无感情的逻辑,将软件工程推向一个前所未有的标准化时代。

但就在前几天,我在一个尘封的互联网角落里,挖出了一本写于 1999 年的上古奇文——How To Write Unmaintainable Code》(如何编写不可维护的代码)

这篇文章的作者 Roedy Green,怀着一种极其黑色幽默的极客精神,手把手教导当年的 Java 程序员们,如何写出能让“接盘侠”当场崩溃、从而保证自己“终身就业”的屎山代码。

当我用 AI 时代的眼光,去重新审视这本 27 年前的“反向圣经”时,我感到既荒谬又亲切。它就像一面镜子,照出了在没有 gofmt、没有 AI、没有 Claude Code 的“古法编程”时代,我们曾如何野蛮生长,以及 Go 语言在设计之初,就已经用多么前瞻性的眼光,封印了那些曾经肆虐一时的“魔鬼”。

今天,就让我们开启一场技术考古之旅,用现代 Go 语言,来“复刻”一下这些差点失传的“防御性”编程之术。

底层哲学:把你的同事想象成一个“管中窥豹”的傻子

Roedy Green 在开篇就点明了核心:维护者看代码,就像通过一个卫生纸筒的中心在看世界,视野极其狭窄。

你的任务,就是让他永远无法拼凑出完整的画面。

古法复刻:让同事“提刀来见”的 骚操作

命名之罪

  1. 用 l 冒充 1,用 O 冒充 0:利用字体的模糊性,制造视觉混乱。
    go
    // 古法复刻
    var l int64 = 11 // 这是 11 还是 1l?
    var speed int = O1 // 这是 O1 还是 01?
  2. 创造极其相似的变量名:仅通过大小写或一个不显眼的字母进行区分。
    go
    // 古法复刻
    var swimmer, swimner string // 99% 的 Code Review 都会看走眼
    var hashTable, HashTable *map[string]int
  3. 滥用缩写,且不保持一致:在不同的地方使用同一个单词的不同缩写,让全局搜索彻底失效。
    go
    // 古法复刻
    func GetUserAuth(...) {}
    func GetUsrAuthorization(...) {}
    var athnClient *Client
  4. 使用与业务逻辑无关的变量名:比如,在屏幕上显示“Postal Code”(邮政编码),但在代码里把它命名为 zip。
  5. 在函数名中使用极其抽象的词汇:比如 HandleIt, ProcessData, DoStuff。让调用者永远猜不透这个函数到底干了什么。

注释之罪

  1. 在注释里撒谎:最简单的一招,改了代码,但不更新注释。
  2. 写废话注释:为每一行显而易见的代码配上同样显而易见的注释,用大量的噪音淹没真正有价值的信息。
    go
    // 古法复刻
    i++ // i plus 1
  3. 永远不要注释一个变量:它的单位、取值范围、边界条件,全让维护者自己去猜。

结构之罪

  1. 极限压行:在一行里塞进尽可能多的逻辑,挑战显示器的宽度极限。
  2. 深度嵌套:以能嵌套 10 层以上的 if-else 为荣,坚决不使用 early return或happy path。
  3. 滥用全局变量:永远不要使用局部变量,把一切都提升为包级变量,让并发的 Goroutine 们去为了争夺它而自相残杀。

    // 古法复刻
    var tempResult string // 提升为包级变量
    
    func HandleRequestA() {
        tempResult = "result_from_A"
        // ...
    }
    
    func HandleRequestB() {
        tempResult = "result_from_B"
        // ...
    }
    // 当这两个函数并发执行时,一场血案即将发生。
    
  4. 复制-粘贴-修改:当有相似功能时,坚决不抽象,直接复制粘贴。在一个代码库里埋下 5 份只有细微差别的一模一样的代码,等待日后引爆。
  5. 一个函数只做一件事?不,一个函数必须干三件事! 让一个名为 IsValid() 的函数,在校验的同时,偷偷地把数据写入数据库。

Go 语言的反击

当然原文中,Roedy Green的“骚操作”不止这些。

但其中的一些“防御”手段对今天的Go语言来说,并不生效。

你会发现 Go 语言在设计之初,就已经对这些“手段”进行了“免疫”,比如:

  • 关于缩进与格式:Roedy Green 痛斥当年程序员通过“故意错位”的缩进来制造 if-else 匹配的视觉陷阱。
    • Go 的反击:对不起,我们有 gofmt。在 Go 的世界里,关于代码格式的“圣战”在第一天就结束了。无论你的代码写得多乱,Ctrl+S 的瞬间,一切都会变得整齐划一。
  • 关于花括号:原文建议省略非必须的 {}。
    • Go 的反击:Go 语言强制要求 if, for 后面必须跟 {},从语法层面彻底消灭了这种的“防御”写法。

现代化的“魔鬼”:用 Go 复刻那些更高级的骚操作

当然,Go 也不是万能的。很多源自 Java/C++ 时代的“高级骚操作”,在 Go 里依然可以“继续存在”。

  1. 伪装成构造函数
    go
    // 古法复刻:这个函数名和类型名完全一样,但它不是构造函数!
    type User struct{ name string }
    func User(name string) { /* ... do something evil */ }
  2. 滥用 interface{}:把所有的函数参数都定义成 interface{},然后在函数内部进行大量的类型断言(Type Assertion)。这能完美地把编译时错误,转化为运行时 panic。
  3. 颠倒参数顺序:定义一个 DrawRectangle(height, width int) 函数。在几个版本之后,神不知鬼不觉地把它改成 DrawRectangle(width, height int),但函数名保持不变。
  4. 魔数(Magic Numbers):在代码里硬编码大量的数字 100,但就是不定义一个常量。更高级的玩法是,偶尔用 99 代替 100-1,用 50*2 代替 100。
    go
    // 古法复刻
    if len(users) > 99 { // 这里是 > 99
    // ...
    }
    for i := 0; i < 100; i++ { // 这里是 < 100
    // ...
    }
  5. 迷惑性的函数重载(Go 版本):Go 没有函数重载,但我们可以用“接口”来模拟。
    go
    // 古法复刻
    func Process(input interface{}) {
    switch v := input.(type) {
    case string: // 处理字符串
    case int: // 处理整数,但逻辑和 string 完全不同
    // ...
    }
    }

    当你的同事传入一个他以为是数字的字符串 “123″ 时,他将收获一个意想不到的结果。

小结:在 AI 时代,我们为什么要回顾“屎山”?

重温这本 27 年前的“反向圣经”,在今天这个 AI 编程时代,显得格外有意义。

AI 的出现,正在把“编写可维护代码”的门槛,拉到前所未有的低点。一个初级程序员,在 AI 的辅助下,也能写出格式工整、变量命名规范的代码。

但这是否意味着“屎山”将成为历史?

恰恰相反。AI 在解放我们生产力的同时,也正在“批量化”和“隐蔽化”地制造着“新时代的屎山”。AI 可能会生成一段逻辑上看似完美,但在高并发下会引发严重数据竞争的代码;它也可能会为了实现一个简单功能,引入一个庞大且带有安全漏洞的第三方库。

这本古老的指南提醒我们:技术的进步可以消灭“语法层面”的丑陋,但永远无法替代人类工程师在“架构层面”的审美与抉择。

在 AI 时代,我们不再需要像 Roedy Green 那样,靠着“加密代码”来保住饭碗。但我们比以往任何时候,都更需要理解那些“不可维护代码”背后的设计缺陷,从而在 Code Review 中,扮演好 AI 的“最终质检员”角色。

代码的整洁与混乱,终究是一场关于“责任心”的博弈。无论时代如何变迁,这,或许是软件工程永恒的真理。

当然,如果你真的想了解古法编程时代的更多“骚操作”,可以看看Roedy Green的原文:https://www.doc.ic.ac.uk/%7Esusan/475/unmain.html


今日互动探讨:

在你见过的 Go 项目中,遇到过哪些让你拍案叫绝、或者让你想“提刀来见”的“屎山代码”骚操作?

欢迎在评论区分享你的“开眼”经历!


还在为“复制粘贴喂AI”而烦恼?我的新专栏 AI原生开发工作流实战 将带你:

  • 告别低效,重塑开发范式
  • 驾驭AI Agent(Claude Code),实现工作流自动化
  • 从“AI使用者”进化为规范驱动开发的“工作流指挥家”

扫描下方二维码,开启你的AI原生开发之旅。


你的Go技能,是否也卡在了“熟练”到“精通”的瓶颈期?

  • 想写出更地道、更健壮的Go代码,却总在细节上踩坑?
  • 渴望提升软件设计能力,驾驭复杂Go项目却缺乏章法?
  • 想打造生产级的Go服务,却在工程化实践中屡屡受挫?

继《Go语言第一课》后,我的《Go语言进阶课》终于在极客时间与大家见面了!

我的全新极客时间专栏 《Tony Bai·Go语言进阶课》就是为这样的你量身打造!30+讲硬核内容,带你夯实语法认知,提升设计思维,锻造工程实践能力,更有实战项目串讲。

目标只有一个:助你完成从“Go熟练工”到“Go专家”的蜕变! 现在就加入,让你的Go技能再上一个新台阶!


商务合作方式:撰稿、出书、培训、在线课程、合伙创业、咨询、广告合作。如有需求,请扫描下方公众号二维码,与我私信联系。

© 2026, bigwhite. 版权所有.

🔲 ☆

承认吧,AI 写的代码,平均质量已经超过了 80% 的人类程序员!

本文永久链接 – https://tonybai.com/2026/02/05/ai-code-quality-surpasses-80-percent-of-human-programmers

大家好,我是Tony Bai。

随着 Claude Code、Gemini Cli、OpenCode 等 AI 智能体编程工具的爆火,技术圈里出现了一种流行的论调:

  • “AI 写的代码质量不高,全是 Bug。”
  • “简单的还行,复杂的还得靠人。”
  • “AI 也就是个实习生水平。”

这些批评有道理吗?当然有。AI 确实会产生幻觉,逻辑偶尔会断裂。

但这种批评忽略了一个最基本的事实:我们拿来对比的基准(Baseline),往往是我们心目中“理想的资深工程师”。

请现在、立刻、马上打开你公司的 Github私有库或GitLab,随便点开一个两年前的遗留项目,看看里面的代码:

  • 那些随意的变量命名 tmp, data1;
  • 那些长达 800 行、没有任何注释的上帝函数;
  • 那些为了赶上线而写死的 Magic Number;
  • 那些复制粘贴了 5 遍却忘了改参数的逻辑……
  • … …

这才是人类编码的常态。

如果我们摘下“幸存者偏差”的滤镜,从全局视角的大数定律来看,一个残酷的真相正在浮出水面:

AI 写的代码,虽然缺乏神韵,但其平均质量,可能已经超越了80%的人类程序员。

人类的“熵增” vs. AI 的“基准线”

人类写代码,本质上是一个对抗熵增的过程。而人类在这个过程中充满了弱点:

  • 情绪与疲劳:下午 5 点写的代码,质量通常低于上午 10 点。为了赶着回家,我们会下意识地省略错误处理(catch (e) { // TODO })。
  • 知识盲区:即使是高级工程师,也记不住所有正则表达式的语法,或者某个冷门 API 的最佳实践。
  • 懒惰:没人喜欢写文档,没人喜欢写单元测试。

相比之下,AI 简直就是代码规范的狂热信徒。

  • 标准化:只要你 Prompt 给对了,它生成的代码默认符合 PEP8、Google Style、Effective Go 或任何你指定的规范。
  • 全面性:它不厌其烦地写 Docstring,写类型注解,写样板代码。这些人类最讨厌干的脏活,是 AI 的舒适区。
  • 无情绪:它不会因为被产品经理气到了,就故意写一段晦涩难懂的代码报复社会。

AI 也许写不出 Linux 内核那样的神作(上限),但它绝对不会写出连缩进都乱七八糟的垃圾。它极大地拉高了代码质量的底线。对于商业软件而言,底线的提升,往往比上限的突破更有价值。

自动驾驶的启示:一场“平庸”的胜利

我们可以用自动驾驶来做一个绝佳的类比。

每当特斯拉撞上路桩,媒体都会大肆报道。人们会说:“你看,机器还是不靠谱。”

但我们忽略了,此时此刻,全世界有成千上万的人类司机正在因为酒驾、看手机、打瞌睡、路怒症而制造车祸。

统计数据最终会证明:只要 AI 的故障率低于人类的平均故障率,它就是巨大的进步。

编程也是一样。

AI 编程的终局,不是写出完美无瑕的代码,而是写出比“人类平均水平”更可靠的代码。

当 AI 写的代码自带测试、自带文档、没有低级语法错误时,它就已经赢了。它消灭了“垃圾代码”。这将是一场“平庸的胜利”——软件工程将不再依赖个别天才的灵光一闪,而是依赖工业化、标准化的稳定产出。

范式转移:从“写代码”到“审代码”

如果承认 AI 已经是中级工程师水平,那么人类的角色必须发生根本性的转变。

以前,我们是 Coder(代码作者)。现在,我们被迫成为了 Reviewer(审查者)和 Architect(架构师)。

这其实对人类提出了更高的要求。

  • 阅读理解能力:AI 一秒钟生成 100 行代码,你是否有能力在 10 秒内看出其中的逻辑漏洞?
  • 系统设计能力:既然“搬砖”的工作 AI 做得比你好,你必须去思考“砖头该怎么垒”——系统架构、数据模型、业务边界。

更关键的是“自动化验证”。

既然人类读代码的速度跟不上 AI 写代码的速度,我们就必须建立一套“机器审查机器”的机制。

  • AI 写代码,AI 写测试。
  • AI 写实现,Compiler/Linter 做检查。

未来的软件质量,将不取决于你手写了多少行代码,而取决于你设计了多严密的护栏(Guardrails)和验收标准(Spec)。

小结:拥抱“无人编程”时代

我们可能正在经历软件工程领域的“无人驾驶时刻”。

初期,我们需要“安全员”(人类程序员)手扶方向盘,随时准备接管。

但随着模型能力的迭代(如 GPT-5.2、Gemini 3.0 Pro、Claude 4.5 Opus等),接管的频率会越来越低。

最终,“人类手写代码”可能会被视为一种不安全的行为——就像现在“酒后驾车”一样。

因为人类是不稳定的、不可控的。而经过严格 Prompt 工程和测试约束的 AI,是稳定、可控、可追溯的。

承认 AI 比我们写得好,并不丢人。

这意味着我们可以从繁琐的语法细节中解放出来,去追求那 1% 的“神来之笔”——创造力、同理心和对未来的想象。


你怎么看这个“80%”?

你认同这个残酷的结论吗?在你看来,AI 生成的代码最让你放心的地方在哪里?最让你担心的地方又在哪里?欢迎在评论区开启你的辩论模式!

如果这篇文章戳中了你的“痛点”,别忘了点个【赞】和【在看】,并转发给你的开发伙伴,看看他们敢不敢“承认”!


如何做 AI 的“安全员”?

AI 的代码质量已经超越了大多数初级工程师。作为一个“AI 时代的 Tech Lead”,你该如何建立一套机制,来驾驭这股庞大的算力?

在我的极客时间专栏《AI 原生开发工作流实战》中,我们不谈如何写代码,而是谈如何审代码,如何构建 Test-Driven 的自动化护栏

  • 如何利用 Claude Code 自动生成高覆盖率的测试用例?
  • 如何构建 AI Code Reviewer 来预审代码?
  • 如何用 Spec 约束 AI,防止幻觉?

让我们一起,从“写代码的人”,进化为“定义代码标准的人”。

扫描下方二维码,开启你的进阶之旅。


你的Go技能,是否也卡在了“熟练”到“精通”的瓶颈期?

  • 想写出更地道、更健壮的Go代码,却总在细节上踩坑?
  • 渴望提升软件设计能力,驾驭复杂Go项目却缺乏章法?
  • 想打造生产级的Go服务,却在工程化实践中屡屡受挫?

继《Go语言第一课》后,我的《Go语言进阶课》终于在极客时间与大家见面了!

我的全新极客时间专栏 《Tony Bai·Go语言进阶课》就是为这样的你量身打造!30+讲硬核内容,带你夯实语法认知,提升设计思维,锻造工程实践能力,更有实战项目串讲。

目标只有一个:助你完成从“Go熟练工”到“Go专家”的蜕变! 现在就加入,让你的Go技能再上一个新台阶!


商务合作方式:撰稿、出书、培训、在线课程、合伙创业、咨询、广告合作。如有需求,请扫描下方公众号二维码,与我私信联系。

© 2026, bigwhite. 版权所有.

🔲 ⭐

你的 CLAUDE.md 写错了:为什么指令越多,AI 越笨?

本文永久链接 – https://tonybai.com/2026/01/29/write-a-good-claude-md

大家好,我是Tony Bai。

在使用 Claude Code、Cursor 或 Gemini Cli 等 AI 编程工具时,你是否遇到过这样的情况:

明明在项目根目录写了 CLAUDE.md(或 AGENTS.md),洋洋洒洒列了几十条项目规范:“使用 TypeScript”、“不要用 any”、“单元测试覆盖率要达标”……

但 AI 就像个叛逆的实习生,经常对这些指令视而不见,反复犯同样的低级错误。

是你写的 Prompt 不够严厉吗?还是模型不够聪明?

最近,HumanLayer 团队发布的一篇深度分析文章揭示了真相:

问题恰恰在于你写得太多了。

Claude Code 的内部机制会给模型注入一条系统级提醒:

“IMPORTANT: this context may or may not be relevant to your tasks. You should not respond to this context unless it is highly relevant.”
(重要:此上下文可能与您的任务无关。除非高度相关,否则请忽略。)

这意味着,你的 CLAUDE.md 越臃肿,包含的无关信息越多,它被系统判定为“噪音”并整体忽略的概率就越大。

今天,我们来聊聊如何用工程化的思维,重构你的 AI 上下文管理。

第一性原理:AI 是无状态的“新员工”

要写好 CLAUDE.md,首先要理解 LLM 的本质:它是无状态的(Stateless)

每次你开启一个新的 Session,对于 AI 来说,都是入职第一天。它对你的代码库一无所知。CLAUDE.md 是它唯一的“入职手册”和“长期记忆”。

但这并不意味着你要把公司历史全塞给它。一个优秀的入职手册应该包含什么?

HumanLayer 的文章中 总结了 “The Trinity”(三要素)

  1. WHAT(地图): 技术栈是什么?项目结构是怎样的?(特别是 Monorepo,告诉它哪里是 App,哪里是 Lib)。
  2. WHY(目标): 这个项目的核心价值是什么?核心模块的职责边界在哪里?
  3. HOW(工具): 怎么构建?怎么跑测试?用 npm 还是 bun?

除此之外的任何废话,都是在消耗 AI 宝贵的注意力。

最佳实践一:少即是多 (Less is More)

研究表明,即便是最前沿的推理模型(Thinking Models),能稳定遵循的指令上限也就在 150-200 条左右。而小模型(如 Haiku 或 GPT-4o-mini)的遵循能力随着指令数量增加呈指数级下降

更糟糕的是 “位置偏见(Position Bias)”。LLM 高度关注开头(System Prompt)和结尾(最新对话),夹在中间的 CLAUDE.md 如果过长,极易沦为“被遗忘的中间层”。

因此,请遵循以下黄金法则:

  • 不要试图涵盖所有边缘情况。
  • 将根目录的 CLAUDE.md 控制在 300 行以内,HumanLayer 的生产环境甚至控制在 60 行以内
  • 每一行都要问自己:“如果没有这句话,AI 真的干不了活吗?”

最佳实践二:渐进式披露 (Progressive Disclosure)

如果你确实有很多规范要交代,怎么办?

答案是:不要把所有鸡蛋放在一个篮子里。

想象一下,HR 会在入职第一天把 500 页的《数据库运维手册》扔给一个前端开发吗?不会。

你需要构建一套“渐进式”的文档体系:

1. 建立文档库:

在项目中创建一个 .ai/docs/ 目录,存放特定领域的指南:

  • testing.md:详细的测试编写与运行指南。
  • database.md:Schema 定义与迁移规范。
  • architecture.md:核心架构图与数据流。

2. 建立索引:

在主 CLAUDE.md 中,只保留“触发器”:

  • “编写或运行测试前,请务必阅读 .ai/docs/testing.md。”
  • “涉及数据库变更时,请参考 .ai/docs/database.md。”

这样,当 AI 只是在写一个前端组件时,它的上下文窗口就不会被无关的后端 Schema 污染。保持注意力的纯净,是提升 AI 智商的关键。

最佳实践三:别把 AI 当 Linter 用

这是最常见的资源浪费:在 CLAUDE.md 里写了 50 行关于代码风格的规定——“缩进用 2 个空格”、“花括号不换行”、“变量名用驼峰”……

请记住:LLM 是昂贵的推理引擎,不是廉价的格式化工具。

让 AI 去关注缩进,就像让法拉利去送外卖,既贵又慢。而且,AI 即使知道规则,也经常因为概率性生成而“手滑”。

正确的解法是:Tooling > Prompting。

  1. 配置工具: 使用 Prettier, Biome, ESLint, govet 等确定性工具来处理格式。
  2. 设置 Hook: 配置 Claude Code 的 Stop Hook。如果 AI 生成的代码格式不对,让 Linter 报错,把错误信息喂回给 AI。
    • AI: (生成代码)
    • System: “Lint Error: Missing semicolon.”
    • AI: “Ah, fixing it.”

AI 极其擅长修复报错,但并不擅长凭空遵守“隐形的规则”

小结:杠杆的层级

在 AI 原生开发中,CLAUDE.md 处于“杠杆层级”的顶端。

  • 写错一行代码 = 1 个 Bug。
  • 写错一行 CLAUDE.md = 成百上千次错误的规划、错误的检索、错误的代码。

不要盲目依赖 /init 自动生成的文件,那只是个起点。你需要像维护核心代码一样,精心雕琢你的 CLAUDE.md。

现在,打开你的项目,检查一下那个文件。

删掉那些废话,把长文档拆分,把格式化交给工具。

给你的数字员工减负,它才能跑得更快。

资料链接:https://www.humanlayer.dev/blog/writing-a-good-claude-md


你的 CLAUDE.md 有几行?

读完这篇文章,不妨现在就去检查一下你项目里的 CLAUDE.md。它是清爽的“入职手册”,还是臃肿的“裹脚布”?你目前的行数是多少?

欢迎在评论区晒出你的“瘦身”成果!让我们一起给 AI 减负。

如果这篇文章帮你解决了 AI “不听话”的难题,别忘了点个【赞】和【在看】,并转发给你的团队,规范大家的 Prompt 工程!


构建工程化的 AI 工作流

CLAUDE.md 只是构建 AI 原生工作流的起点。

  • 如何配置 Hooks 来实现自动化代码审查?
  • 如何编写 Sub-Agents 来处理隔离的脏活累活?
  • 如何设计 Slash Commands 来固化团队的 SOP?

如果你想深入掌握 Claude Code 的高阶玩法,不仅仅是写 Prompt,而是构建一套“自动纠错、按需加载”的工程化体系。

欢迎关注我的极客时间专栏AI 原生开发工作流实战

我们不聊虚的,只讲能在生产环境中落地的 AI 工程实践。

扫描下方二维码,开启你的AI原生开发之旅。


你的Go技能,是否也卡在了“熟练”到“精通”的瓶颈期?

  • 想写出更地道、更健壮的Go代码,却总在细节上踩坑?
  • 渴望提升软件设计能力,驾驭复杂Go项目却缺乏章法?
  • 想打造生产级的Go服务,却在工程化实践中屡屡受挫?

继《Go语言第一课》后,我的《Go语言进阶课》终于在极客时间与大家见面了!

我的全新极客时间专栏 《Tony Bai·Go语言进阶课》就是为这样的你量身打造!30+讲硬核内容,带你夯实语法认知,提升设计思维,锻造工程实践能力,更有实战项目串讲。

目标只有一个:助你完成从“Go熟练工”到“Go专家”的蜕变! 现在就加入,让你的Go技能再上一个新台阶!


商务合作方式:撰稿、出书、培训、在线课程、合伙创业、咨询、广告合作。如有需求,请扫描下方公众号二维码,与我私信联系。

© 2026, bigwhite. 版权所有.

❌