Code is not cheap

如何用AI写出好的代码

在 AI 时代,烂代码的代价比以往任何时候都更高

  • 如果代码库难以修改,你就无法充分利用 AI 带来的所有优势
  • AI 在良好的代码库上表现非常出色
  • 因此,好的代码库比以往任何时候都更重要,软件基础原则也比以往任何时候都更重要

失败的解决方案

模式一:AI 没有做你想要的事

症状:头脑中有一个好的想法,但 AI 做了完全不同的事情,或者生成了你不想要的东西。

原因 :你和 AI 之间存在沟通障碍 ,缺乏共享的设计概念(Design Concept)。

概念------设计概念(Design Concept)

出自 Frederick Brooks 的《设计的设计》

当多人共同设计某样东西时,会有一个想法在你们之间飘浮------这就是"设计概念"。它是关于你要构建的东西的无形理论,不是可以放在 markdown 文件中的资产。

解决方案:Grilling Me Skill

markdown 复制代码
Interview me relentlessly about every aspect of this plan 
until we reach a shared understanding. Walk down each branch 
of the design tree, resolving dependencies between decisions, 
one by one.

原理:

  • 让 AI 向你问 40-60 个问题(甚至 100 个),直到达到共享理解
  • 将对话转化为产品需求文档或 issue
  • AFK agent(离线代理)随后接手

建议 :在开始使用工具的默认 Plan 模式之前,先达到共享的设计概念会更好。


模式二:AI 太冗长

症状 :与 AI 交流时感觉不在同一个频道上,它用太多话解释它在做什么。

原因 :开发者与 AI 之间存在语言鸿沟,就像开发者与领域专家之间的鸿沟一样。

概念------统一语言(Ubiquitous Language)

出自领域驱动设计(Domain-Driven Design, DDD)

开发者之间的对话、代码中的表达式、与领域专家的对话,都应源自同一个领域模型。统一语言本质上是一个 markdown 文件,列出了你和 AI 共同拥有的术语列表。

解决方案:Ubiquitous Language Skill

工作流程:

  1. 扫描代码库,识别术语
  2. 创建 markdown 文件,包含术语的表格
  3. 将这个文件传递给 AI
  4. 在与 AI 协作时始终保持打开参考

效果:

  • 改善规划质量
  • 让 AI 以更简洁的方式思考
  • 实现更符合计划精神的代码

模式三:AI 构建了正确的东西但不工作

症状:AI 理解了需求并构建了正确的东西,但代码不工作。

解决:建立反馈循环

  • 使用静态类型(TypeScript 强烈推荐)
  • 让 LLM 访问浏览器以便探索
  • 自动化测试

模式四:LLM 过度超前(Outrunning Your Headlights)

症状 :AI 一次做太多事情,产生大量代码后才发现类型错误或测试失败。

概念------超越你的车灯(Outrunning Your Headlights)

出自《实用程序员》

反馈的速度就是你的速度极限。你应该边做边测试,采取小而谨慎的步骤。AI 默认情况下非常不擅长这一点。

解决方案:测试驱动开发(TDD)

TDD 强制 LLM 采取小步骤:

  1. 先创建测试
  2. 让测试通过
  3. 重构代码以改善设计

为什么测试很难

编写测试需要做出许多相互依赖的决策:

  • 要测试多大的单元?
  • 要 mock 什么?
  • 首先要测试什么行为?

关键 :好的代码库 = 易于测试的代码库


模式五:代码能工作但大脑跟不上

症状:反馈循环运行良好,代码产出比以往任何时候都多,但大脑疲惫不堪。

原因:代码库让 AI 和你都需要在脑中同时处理太多信息。

解决方案:设计接口,委托实现

将深模块视为**灰盒**:

  • 设计好接口
  • 不需要深入审查实现细节
  • 用测试从外部验证

注意:对于金融等关键模块不能这样做,但对于应用中许多其他模块可以。

效果 :节省脑力,专注于战略层面的设计。


软件基础原则

1. 软件熵(Software Entropy)

出自《实用程序员》

熵是事物趋向灾难和崩溃的倾向。每次你修改代码库时,如果只考虑那个变更而不考虑整个系统的设计,你的代码库会变得越来越糟糕。

教训:spec-to-code 的做法只会让代码越来越差。

2. 深度模块化(Deep Modules)

出自 John Ousterhout 的《软件设计的哲学》

类型 特点 示例
深度模块 大量功能隐藏在简单接口后面 ✅ 隐藏复杂性,按需查看内部
浅层模块 功能不多,接口却很复杂 ❌ AI 需要在大量小模块间导航,难以理解

架构改造技能:Improved Codebase Architecture

将浅层模块代码库改造为深层模块:

  1. 探索代码库
  2. 寻找相关的代码
  3. 将它们包装在一个深模块中
  4. 在接口处进行测试

3. 统一语言(Ubiquitous Language)

核心原则:

  • 代码、对话、文档使用相同的术语
  • 确保术语与实际含义一致
  • 术语需要成为 ubiquitous language 的一部分

4. 投资系统设计

来自 Kent Beck

每天都要投资于系统的设计。

spec-to-code 的问题:不是在投资系统设计,而是在撤资。


架构视图对比

浅层模块架构

复制代码
┌─────┐ ┌─────┐ ┌─────┐ ┌─────┐ ┌─────┐
│ 模块 │ │ 模块 │ │ 模块 │ │ 模块 │ │ 模块 │
└──┬──┘ └──┬──┘ └──┬──┘ └──┬──┘ └──┬──┘
   │       │       │       │       │
   ▼       ▼       ▼       ▼       ▼
(大量小 blob,AI 需要逐一导航)

深层模块架构

复制代码
        ┌─────────────────────────────┐
        │         接口层              │
        │  ┌─────────┐  ┌─────────┐  │
        │  │ 接口 A  │  │ 接口 B  │  │
        │  └────┬────┘  └────┬────┘  │
        └───────┼───────────┼───────┘
                ▼           ▼
        ┌─────────────┐ ┌─────────────┐
        │  深模块实现  │ │  深模块实现  │
        │  (可委托)  │ │  (可委托)  │
        └─────────────┘ └─────────────┘

AI 协作中的角色分工

角色 职责
AI 地面战术级程序员,执行具体的代码变更
人类 战略级思考者,负责设计、架构、决策

AI 是一个出色的战术级程序员,但需要人类在上面进行战略层面的思考。这正是软件基础技能的价值所在。


参考文献: github.com/mattpocock/skills

相关书籍

书名 作者 核心概念
《软件设计的哲学》 John Ousterhout 深度模块、代码复杂性
《实用程序员》 David Thomas, Andrew Hunt 软件熵、TDD
《设计的设计》 Frederick Brooks 设计概念
《领域驱动设计》 Eric Evans 统一语言(Ubiquitous Language)
相关推荐
limuyang23 小时前
我在 2核2G 云主机上跑 OpenViking:一次关于云主机、模型选型与长期成本的真实复盘
人工智能·开源·ai编程
Shulex5 小时前
跨境电商 AI Agent 核心架构解析:从只读问答到自主执行的工程落地
人工智能·架构·智能客服·跨境电商
Java后端的Ai之路5 小时前
CAS并发控制-从CPU指令到企业级乐观锁
vue.js·人工智能·python·cas·乐观锁
情 九5 小时前
MCP 实战 06:把 HTTP 接口接成工具,让 AI 帮你查数据
人工智能·网络协议·http·mcp
码农小旋风6 小时前
Ray分布式计算引擎介绍
人工智能·架构
火山引擎和TA的超级拍档们6 小时前
产品情报局 08 | AI 内容助手:全网热点驱动,一站式打通内容生产全链路
人工智能
Binovate缤江数智6 小时前
水泵远程开关之后,还需要管什么?数智开关在无人值守泵站中的监测、保护与能耗分析
人工智能·物联网
素男6 小时前
两个月不是六十天
人工智能·agent·self-becoming·ai长期记忆·ai自我介绍
byte轻骑兵6 小时前
【LMP】规范精讲[10]: 语音专线开线记——SCO 固定占座与 eSCO 限时重传
人工智能·人机交互·lmp·蓝牙链路管理·蓝牙外设