Go项目架构选择:AI编程时代的思考

14 阅读6分钟

最近做了个有趣的实验:用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效率高,改动可追溯

有问题欢迎讨论。