来源:抖音 @祥林记
AI 编程中的架构腐烂与依赖方向
让 AI 生成用户注册功能时,它可能在二十行代码内实现所有逻辑,但扩展时整个模块需要大改。AI 倾向于把 HTTP 参数校验、业务规则、数据库写入和邮件通知放进同一个函数。原因是缺乏边界约束,职责无限膨胀。
依赖方向:稳定与易变的取舍
解决这个问题的核心,是理解依赖关系的本质:依赖必须指向稳定的方向。名词本身不重要,重要的是依赖的方向。
软件系统中的代码分为两类。稳定层(内层)包括订单逻辑、退款规则和业务策略,这些核心规则变化频率低,可能数年不变。易变层(外层)包括框架、数据库版本和外部 API,可能每周甚至每天升级或调整。
如果核心业务逻辑直接依赖具体的 ORM(对象关系映射)工具,底层数据库升级后,上层业务代码需要随之重构。这就是架构腐烂。正确做法是依赖反转:外层技术细节适配内层业务接口。数据库变更时,只要接口契约不变,Domain 层不需要修改。
目录结构作为约束
AI 倾向于完成当前任务,忽视未来变化成本。不能用自然语言提示它分层,需要通过物理结构强制约束。
具体做法包括:将项目分为 domain/(纯业务规则)、application/(用例编排)、infra/(基础设施实现)和 api/(HTTP 入口)。目录是编译期护栏,domain 层严禁 import 外部库,infra 层实现 domain 定义的接口。编写 AGENTS.md 固定规则,并用 Lint 工具(如 dependency-cruiser)在 CI 阶段自动拒绝违规导入。
架构的价值:应对变化
软件工程的挑战不只是让代码今天能跑,还要让它明天能改。
在 AI 编程时代,架构原则的价值更大。目录结构和 Lint 规则是 Agent 能读懂并执行的“可执行契约”。架构因此成为确保核心层不被污染的防御机制。
判断标准是核心领域规则是否稳定。长期维护的核心系统值得分层;快速原型或一次性脚本则不需要分层,过度设计增加负担。
检验方式是让 AI 生成依赖图,只看箭头方向。如果出现从内向外指的箭头,就是需要偿还的技术债。
延伸
以下为编辑延伸解读,非原素材内容。
历史背景:从宏观架构到微观依赖
这种对依赖方向的重视,源于面向对象设计中的依赖倒置原则(DIP)和控制反转(IoC)。早期 MVC 模式分离了视图与模型,但复杂后端逻辑中 Service 层常变成“大泥球”。Clean Architecture 和 Hexagonal Architecture 普及后,开发者认识到解耦的关键在于边界清晰和依赖单向。
横向对比:其他架构方案的适用边界
除了视频中提到的分层架构,业界还有几种常见的架构模式:
- 微服务架构:拆分进程或服务,适合超大型团队,但引入分布式复杂性(如网络延迟、数据一致性),不适合单体应用内部分层。
- 事件驱动架构(EDA):用异步消息解耦生产者和消费者,适合高并发、长链路场景,但调用链不可见,调试和维护困难。
- 模块化单体(Modular Monolith):在单体中严格划分模块边界,对多数中型企业应用可能比微服务更经济,其思路与分层架构一致。
局限性与质疑
依赖反转虽被普遍接受,实际应用中常有两个质疑:
- 性能损耗:多层抽象和接口转发是否带来不可忽视开销?现代硬件环境下损耗通常可忽略,除非是极高频交易链路。
- 开发效率:简单 CRUD 页面强制实施 Domain-Driven Design (DDD) 会产生大量样板代码(Boilerplate Code),降低开发速度。架构师需要在过度工程和架构腐烂之间平衡。