AI编码代理擅长做出每个局部合理的决策——添缓存、建服务、加重试——但几周后系统整体变差:业务规则重复、依赖混乱、无人知晓职责归属。这是架构问题,AI加速了它。
AI 编程助手非常擅长做出小的决策。
把这个逻辑移到一个辅助函数里。
为那个功能创建一个服务。
再加一层抽象。
引入一个新的依赖。
每个决策看起来都完全合理。
这恰恰是问题所在。
一个系统可以在每个局部决策都看似正确的情况下变差。
这其实不是 AI 的问题。
这是架构问题,而 AI 现在能让它加速。
想象一下这种情况持续几周:
Task 1 → Add validation
Task 2 → Extract helper
Task 3 → Add cache
Task 4 → Add service
Task 5 → Add retry logic
Task 6 → Refactor module
Task 7 → Add another integration
每个 Pull Request 都通过了。
每次变更看起来都很干净。
两个服务现在拥有同一个业务规则 validation 存在于三个地方 缓存策略不一致 依赖关系双向指向 没人知道哪一层该负责什么 一个"简单"的变更涉及八个文件
没有单个 commit 摧毁了架构。
系统是漂移到那里的。
这是核心思想。
AI 助手通常只处理眼前的任务。
它找到最简单合理的地方添加重试逻辑。
它提取出一个辅助函数。
"清理这个模块。"
它引入了一个新的抽象层。
每个答案对于那个 prompt 来说可能都是正确的。
但架构不仅仅是局部正确选择的集合。
架构是关于这些选择在时间维度上如何相互作用的。
开发者有不同的职责。
如何成功完成这个任务?
开发者应该问:
这个变更对整个系统有什么影响?
这不是同一个问题。
AI 可能会优化:
更快的实现
系统实际上可能需要:
刻意的重复
一个局部优雅的变更仍然可能在全局有害。
假设你有这个:
calculateInvoiceTotal()
后来另一个功能需要类似的行为。
Move it into shared/utils.
再后来另一个模块导入了它。
然后有人添加了客户特定的逻辑。
然后是折扣行为。
现在你的"共享辅助函数"包含了整个系统都在使用的业务逻辑。
当时看起来没有任何不合理的。
但架构静悄悄地改变了。
Invoice owns invoice logic
Everyone depends on shared/utils
这就是架构漂移(architecture drift)。
在 AI 之前,引入五个新抽象需要努力。
现在这可以在几分钟内发生。
这改变了经济学。
开发者生成代码的速度:
快到他们来不及评估这些东西是否应该存在。
风险不在于 AI 生成了明显糟糕的架构。
更有意思的风险是:
它生成看似合理的架构的速度比团队维护一个连贯设计的速度还快。
你的测试套件可能会说:
系统正在变好。
但它们通常捕捉不到:
不必要的抽象
重复的业务规则
100% tests passing
而代码库却每周都变得更难改变。
审阅者一次只看一个 Pull Request。
Diff 看起来是合理的。
但架构问题通常只在许多变更之后才变得可见。
PR 3 添加了另一个依赖。
PR 4 重用了那个辅助函数。
PR 5 绕过了那个服务。
这就是为什么只审查当前的 diff 并不总是足够的。
当审查 AI 生成的代码时,问自己:
如果我们把这个模式重复 20 次,系统会变成什么样?
这个问题出奇地有用。
如果每个功能都添加:
另一个共享辅助函数
那么这个模式本身可能就是错的。
架构往往关乎当一个决策被重复时会发生什么。
减少漂移最简单的方法之一是明确所有权。
Payments owns payment rules.
Orders owns order lifecycle.
Users owns identity.
Notifications only sends messages.
不要把业务规则跨这些边界移动,除非明确要求。
这比为模型每次从头决定架构所有权要好。
Refactor this to make it cleaner.
Refactor this module.
Constraints:
- preserve current architectural boundaries
- do not introduce new dependencies
- do not create new shared abstractions
- keep business logic in the existing domain
- propose changes before implementing
目标不是让 AI 变得没那么有用。
而是阻止每个任务都变成一次小型架构重新设计。
在实现之前,尝试:
Before changing code, explain:
1. Which architectural boundary this touches.
2. Which modules will depend on the change.
3. Whether this introduces a new abstraction.
4. Whether this creates a new dependency.
5. Whether similar logic already exists.
6. How this affects future changes.
这把讨论强制提升到语法层面之上。
我关注的一个信号是依赖方向。
健康的系统通常有清晰的关系。
Controller
↓
Service
↓
Repository
Repository
↓
Utility
↓
Service
现在各层开始以奇怪的方式相互依赖。
每个 import 都能编译。
但系统变得更难理解了。
如果依赖方向变得不清晰,架构通常正在漂移。
AI 经常试图消除重复。
这通常是对的。
但有时候两段代码只是今天看起来相似。
calculateSellerFee()
calculateCreatorFee()
AI 可能把它们合并成:
calculateFee(type)
但如果卖家和创作者的规则演化方向不同,你现在就有了一个承载两个独立概念的抽象。
一点重复可能比错误的抽象更划算。
这是人类仍然需要仔细判断的事情。
我认为重度使用 AI 的团队需要明确的架构规则。
不是几百页的文档。
只是几件必须保持为真的事情。
- Controllers contain no business logic.
- Domains cannot access each other's database tables directly.
- Shared utilities cannot contain business rules.
- External APIs go through adapters.
- Background jobs call services instead of repositories directly.
现在人类和 AI 都有具体的东西可以检查。
这些是架构不变量(architecture invariants)。
AI 也可以帮助发现它造成的问题。
Review this codebase for architecture drift.
Look for:
- duplicated responsibilities
- unclear module ownership
- circular dependencies
- new abstractions with little value
- shared utilities containing business logic
- inconsistent patterns
- dependency direction violations
Do not refactor anything yet.
Rank the findings by impact.
这可以是一次非常有用的审查。
不要急着重构任何东西。
危险的话是:
"这只是一次小变更。"
小变更重复数百次就成了架构。
每一次小变更都在教代码库一个模式。
如果这个模式很弱,AI 可以极其快速地复制它。
这就是为什么局部质量是不够的。
在合并 AI 生成的变更之前,问:
这是否引入了一个新的抽象?
如果是,我们真的需要它吗?
这是否移动了职责?
如果是,新的所有者正确吗?
这是否添加了另一个依赖?
现有的边界能否处理它?
类似的逻辑已经存在吗?
避免竞争的模式。
如果我们把这个方法重复 20 次会怎样?
这个问题能捕获很多。
变更之后系统更容易解释了吗?
如果不是,"更干净的代码"可能实际上并不更干净。
AI 不需要做出明显糟糕的决策才能损害架构。
它只需要在缺乏足够的系统级协调的情况下做出数千个合理的决策。
这是令人不安的部分。
代码库很少因为有人故意设计得很糟糕而变得难以维护。
它通常变得难以维护是通过:
数百个在当时看起来合理的决策。
AI 现在可以更快地生成那些决策。
AI 非常擅长回答:
这个任务的合理解决方案是什么?
但软件架构需要另一个问题:
如果我们继续做这样的决策,系统会变成什么样?
这是不同层次的推理。
这就是为什么开发者仍然需要保护更大的图景。
每个局部决策都可能看起来合理,而系统却在慢慢变差。
AI 负责任务。
你仍然负责架构。