最近做了个有趣的实验:用AI辅助实现三种不同架构的相同业务(用户管理和订单管理),想看看在AI编程时代,哪种架构更合适。分享一下心得。
AI编程改变了什么
AI生成代码很快,但有明显的局限:
AI擅长的
- 生成模板代码(CRUD)
- 按明确需求实现功能
- 在清晰边界内工作
AI不擅长的
- 理解复杂业务领域
- 处理跨文件的依赖
- 保证全局一致性
这意味着:架构要能限制AI的影响范围,让错误不会扩散。
三种架构是什么
分层架构
最传统的方式,按技术职责分目录:
layered/
├── model/ # 所有数据模型
├── repository/ # 所有数据访问
├── service/ # 所有业务逻辑
├── handler/ # 所有HTTP处理
└── dto/ # 所有传输对象
每一层只依赖下一层,自上而下。
AI编程体验
- ✅ AI很熟悉这种结构,生成代码质量高
- ✅ 提示词简单:"写一个用户管理的service"
- ✅ AI能快速生成完整CRUD流程
- ❌ 改一个字段要改4个文件,AI容易漏改
- ❌ 业务逻辑分散,AI难以维护全局规则
实际案例
我:把用户状态从active/inactive改成enabled/disabled/deleted
AI:好的,我改了model和service...
问题:忘了改handler的返回值和repository的查询条件
分层架构下,AI要同时维护多个文件的一致性,很容易出错。
模块化架构
按业务模块来组织:
modular/
├── user/ # 用户模块的所有东西
│ ├── model.go
│ ├── repository.go
│ ├── service.go
│ └── handler.go
└── order/ # 订单模块的所有东西
├── model.go
├── repository.go
├── service.go
└── handler.go
每个业务模块自成一派,相关代码都在一起。
AI编程体验
- ✅ 模块内聚,AI可以独立处理每个模块
- ✅ 提示词更清晰:"在user模块添加积分功能"
- ✅ AI的影响范围被限制在单个模块
- ✅ 改动都在一个目录,AI不会漏掉
- ❌ 跨模块功能,AI需要人工指导
实际案例
我:在user模块添加用户积分功能
AI:好的,我在user/model.go添加了积分字段,
在user/service.go添加了积分计算逻辑...
成功:所有改动都在user目录下,AI没有漏掉任何地方
模块化架构下,AI的工作范围明确,出错概率低。
DDD架构
按领域驱动设计的四层架构:
ddd/
├── domain/ # 领域层:核心业务逻辑
│ ├── user/entity.go
│ └── order/entity.go
├── infrastructure/ # 基础设施层:技术实现
│ └── persistence/
├── application/ # 应用层:用例编排
│ └── service/
└── interface/ # 接口层:HTTP接口
└── http/
核心理念是把业务和技术完全分开。
AI编程体验
- ✅ 业务逻辑集中在领域层,AI不容易散乱
- ✅ 技术代码和业务代码分离,AI可以分而治之
- ❌ AI很难理解领域驱动设计的概念
- ❌ 需要大量提示词教育AI
实际案例
我:订单金额超过1000元需要审批
AI(分层架构):我在service里加个判断...
问题:其他地方也可能创建订单,规则会被绕过
AI(DDD架构):我在Order实体里加CanApprove()方法...
成功:所有创建订单的地方都要经过实体,规则不会被绕过
核心区别在哪里
业务逻辑放哪儿?
分层架构和模块化架构都是贫血模型,业务逻辑写在Service里:
// service/order.go
func (s *orderService) PayOrder(id uint64, req *PayOrderRequest) error {
order, err := s.orderRepo.GetByID(id)
if err != nil {
return err
}
// 业务规则在Service层判断
if order.Status != OrderStatusPending {
return errors.New("订单状态不允许支付")
}
// 在Service层修改状态
now := time.Now()
order.Status = OrderStatusPaid
order.PaymentMethod = req.PaymentMethod
order.PaymentTime = &now
return s.orderRepo.Update(order)
}
Model只是数据容器,没有行为。
DDD架构是充血模型,业务逻辑在实体内部:
// domain/order/entity.go
type Order struct {
id uint64
orderNo string
status Status
paymentMethod string
paymentTime *time.Time
}
// 实体自己知道能不能支付
func (o *Order) CanPay() bool {
return o.status == StatusPending
}
// 实体自己处理支付逻辑
func (o *Order) Pay(paymentMethod string) error {
if !o.CanPay() {
return errors.New("订单状态不允许支付")
}
now := time.Now()
o.status = StatusPaid
o.paymentMethod = paymentMethod
o.paymentTime = &now
return nil
}
Service只是编排:
// application/service/order_service.go
func (s *orderService) PayOrder(ctx context.Context, id uint64, req *PayOrderRequest) error {
order, err := s.orderRepo.GetByID(ctx, id)
if err != nil {
return err
}
// 业务逻辑都在实体内部,Service只是调用
if err := order.Pay(req.PaymentMethod); err != nil {
return err
}
return s.orderRepo.Update(ctx, order)
}
AI编程视角
- 贫血模型:AI容易理解,但业务规则会散落在各处
- 充血模型:AI需要教育,但业务规则集中,不会漏掉
代码怎么组织?
假设要修改用户功能:
分层架构:改4个目录
- model/user.go
- repository/user.go
- service/user.go
- handler/user.go
改个功能要跳来跳去,AI容易漏改。
模块化架构:改1个目录
- user/model.go
- user/repository.go
- user/service.go
- user/handler.go
相关代码都在user目录下,AI改动集中,不会漏掉。
DDD架构:按层次分散,但逻辑清晰
- domain/user/entity.go(业务规则)
- infrastructure/persistence/user/repository.go(数据存储)
- application/service/user_service.go(用例编排)
- interface/http/user/handler.go(HTTP接口)
虽然文件分散,但每层职责清晰,改业务逻辑只动domain层。
AI编程时代的架构选择
小项目(< 5人)
推荐:分层架构
- AI生成快,结构简单
- 后期可以重构
注意事项
让AI一次生成完整的CRUD,不要分步骤。定期review,防止不一致性积累。
中型项目(5-20人)
推荐:模块化架构
- AI可以按模块工作
- 改动范围可控
- 易于review
最佳实践
让AI工作在模块级别:
"在payment模块添加退款功能"
"在notification模块添加短信发送"
"在user模块修改密码加密方式"
而不是:
"修改系统中的密码逻辑"(AI不知道要改哪些文件)
大型项目(> 20人)
推荐:模块化 + 部分DDD
- 核心业务用DDD,保护关键逻辑
- 周边功能用模块化,提高效率
- 让AI处理技术代码,人处理领域模型
如何让AI更好工作
提示词示例:
这是一个DDD项目。请遵循以下规则:
1. 业务逻辑必须在实体内部,不要写在service
2. 实体要有行为方法,不要只有getter/setter
3. 改业务规则时,先改domain层
现在请在Order实体里添加退款逻辑...
AI编程的架构原则
无论选哪种架构,在AI编程时代都要遵循:
1. 高内聚低耦合
AI理解模块边界比理解分散代码容易得多。
2. 明确的依赖方向
单向依赖让AI知道代码应该往哪里写。
3. 一致的命名规范
AI依赖上下文,一致的命名能让AI推断出正确的模式。
4. 最小化跨模块依赖
AI处理跨模块逻辑时容易出错,尽量让模块独立。
5. 清晰的接口边界
通过接口隔离模块,AI只需要知道接口,不需要知道实现。
几个容易踩的坑
让AI改架构
AI适合改代码,不适合改架构。架构决策要人来定,AI来执行。
过度依赖AI生成
AI生成的代码要review,特别是跨模块的依赖。
不给AI足够的上下文
"添加登录功能" vs "在user模块添加基于JWT的登录功能",后者效果更好。
忽略测试
AI生成的代码更容易有bug,测试是必须的,最好也让AI生成测试。
过度设计
10个接口的项目非要上DDD,那就是自找麻烦。架构是为业务服务的,不是为了炫技。
总结
在AI编程时代,模块化架构是最佳选择:
- 边界清晰,AI不会乱改
- 上下文集中,AI容易理解
- 独立性强,易于并行开发
- Review效率高,改动可追溯
有问题欢迎讨论。