错误的衡量标准
关于 AI 生成代码质量的大多数讨论都聚焦于生成时的正确性。输出能编译吗?能通过测试吗?符合规格说明吗?
这些只是基本门槛。它们无法告诉你真正的成本。
真正的衡量标准是可替换性:当需求变化时,你能以多低的成本删除这个 module 并在相同的 contract 背后重新实现它?
如果答案是”轻而易举”,那么 AI 的速度优势会持续累积。如果答案是”我们需要先追踪六个隐式依赖”,你已经失去了你以为自己在获取的速度优势。
为什么 AI 代码倾向于耦合
大语言模型针对当前请求进行优化,而不会为未来的变更进行优化。
当你提示生成一个登录流程时,你得到的是一个能工作的登录流程。你得到的不是一个位于认证 interface 背后、可以在不触碰任何消费它的页面的情况下从 Firebase 切换到 Supabase 再到自定义 JWT 服务的登录流程。
这不是模型的失败,而是上下文的缺失。模型没有被要求针对可替换性优化,所以它没有这样做。
结果是:AI 生成的代码默认倾向于紧密耦合。不是因为模型能力不足,而是因为隔离从来不是下一个 token 预测器的阻力最小路径。
可替换性是一个架构决策
可替换性不会自然发生。它是一个刻意的结构选择:
- 每个外部依赖都位于应用自有的 interface 背后。
- 每个生成的 module 暴露的是 contract,而非实现细节。
- 每个可选能力都是注入的,绝不直接导入。
- 每个组合决策都集中在一个 composition root 中,而非分散在五十个文件里。
这并不新鲜。这是基本的依赖反转。新鲜的是,AI 生成代码让违反这些原则变得毫不费力,且在你需要改动之前完全不可见。
复合效应
当每个 module 都是可替换的:
- 糟糕的生成结果只花费几分钟,而非几天。
- 供应商变更只是 interface 替换,而非 rewrite。
- AI 的速度优势在迭代中保持线性增长,而非对数衰减。
- 团队可以说”在相同 contract 背后重新生成这个”并且真的做到。
当 module 互相纠缠时:
- 每次变更都需要理解完整的依赖图。
- 每次 AI 辅助的 refactor 都有破坏无关系统的风险。
- 团队逐渐不再信任 AI 输出,因为影响范围不可预测。
- 速度退回到 AI 之前的水平,但现在有更多代码需要维护。
实践检验
在将任何 AI 生成的 module 纳入 codebase 之前,应用一个测试:
我能否删除这个文件并从头重新实现它,仅使用它暴露的 interface,而无需修改任何消费方?
如果能,发布。如果不能,在发布之前修正边界。
这很容易执行。一个 composition root 加上 interface 优先的设计在结构上就能给你这个特性。你不需要复杂的治理流程。你需要的是一条架构规则的持续贯彻。
与 AI-Native 架构的关联
我在斯坦福 CS146S 对 AI 编程的判断是对的——缺失的主题是架构中写过这个更广泛的问题。可替换性原则是使 AI-native codebase 在第一版之后仍能存活的具体机制。
斯坦福正在教开发者如何有效使用 AI 工具。这很重要。但没有可替换性的工具熟练度是一个陷阱:你发布得更快,直到 codebase 变得改动成本高昂,然后你的发布速度比从未使用 AI 的团队还慢。
纪律不在于”更好地提示”。纪律在于”架构设计使得提示错误的撤销成本很低”。
常见问题
对 AI 生成代码而言,“可替换架构”意味着什么?
可替换架构意味着每个 AI 生成的 module 都位于一个 interface 背后,系统的其余部分依赖的是这个 interface,而非实现本身。当需求变更或生成结果有误时,你可以删除该 module 并重新实现,而无需触碰消费方。
如何在 AI 生成的 codebase 中执行可替换性?
三个机制:由应用(而非依赖项)拥有的 interface、一个将所有实现连接在一起的 composition root,以及一个在任何 module 直接导入另一个 module 内部实现时使构建失败的 CI 检查。
可替换性会拖慢初始开发速度吗?
不会。在生成实现之前定义一个 interface 只需几秒钟。不这样做的代价会在几周后显现——当供应商切换或 refactor 变成完整的 rewrite 时。
这和依赖注入是一回事吗?
依赖注入是实现可替换性的一种机制,但不是全貌。可替换性还需要 contract tests、边界验证和 composition root——不仅仅是构造函数参数。