go中没有ddd框架,需通过封装、构造约束和方法控制实现聚合根;真分层看import方向,domain不得依赖基础设施;领域事件由聚合方法返回,应用层协调发布;跨聚合仅存id,避免强一致性陷阱。

Go 里没有 DDD 框架,别找 ddd.NewAggregate() 这种东西。想靠引入一个库就“实现 DDD”,只会让代码更难懂、测试更难写、团队更难对齐。
聚合根怎么定义?不是继承,是封装 + 构造约束
Go 没有 class 继承,也不该用嵌入(embedding)假装“父类聚合根”。聚合根的本质是:唯一标识 + 不变量校验 + 状态变更入口统一。
-
NewOrder()必须校验必要字段(如customerID、items非空),失败直接返回 error,不构造出非法实例 - 所有状态变更走方法,比如
order.Confirm()里检查order.Status == "draft",否则 panic 或 return error - 内部字段声明为小写(如
status string),禁止外部直接赋值;只暴露方法控制流转 - 聚合内其他实体/值对象(如
OrderItem)不暴露构造函数,只允许由聚合根创建或修改
分层怎么才算真分层?看 import 方向,不是看目录名
建个 domain/ 目录不等于分层成功。真正塌方的信号是:domain/ 包里 import 了 infrastructure/ 或 database/sql。
Colly 是一个用于 Go 语言的快速开源爬取和爬虫框架。它适用于从简单的页面提取到异步爬虫处理大量页面集合,支持请求回调和结构化解析。
-
domain/只能依赖标准库(errors、time)和其他domain/*子包 -
application/定义接口,例如type OrderRepository interface { Save(Order) error } -
infrastructure/实现该接口,用*sql.DB或 ORM,但绝不反向 importapplication/ - 用
go list -f '{{.ImportPath}} -> {{join .Imports "\n"}}' ./domain快速扫一遍,发现任何基础设施路径就立刻重构
领域事件怎么发?别用全局 pub/sub,用方法返回 + 应用层协调
Go 里没有内置事件总线,硬接 github.com/ThreeDotsLabs/watermill 或自己写 channel 路由,容易把领域逻辑和消息协议耦死。
- 聚合方法返回事件切片,例如
order.Confirm() ([]DomainEvent, error) - 应用服务(
application.PlaceOrder)调用聚合后,拿到事件,再交给专门的event.Publisher发送(Kafka / NATS / 本地 channel) - 事件结构体放在
domain/event/,字段全小写,不带业务逻辑方法,只做数据载体 - 避免在聚合内直接调用
publisher.Publish()—— 那会让领域层依赖基础设施
跨聚合引用怎么处理?只存 ID,不存结构体或指针
订单要关联客户,但 Order 里不能有 Customer *domain.Customer 字段。这不是为了“解耦”而解耦,而是防止隐式强一致性陷阱。
-
Order结构体里只放customerID string,查询客户信息由应用层或仓储层按需加载 - 如果需要客户姓名等轻量字段,可定义只读副本(如
CustomerRef值对象),但禁止用于变更逻辑 - 聚合间交互走最终一致性:订单确认后发
OrderConfirmed事件,客户服务监听并更新自己的积分 - 别为了“查得快”在订单里冗余客户邮箱——那会制造数据不一致风险,且违反限界上下文边界
真正的难点不在语法,而在每次写 func (o *Order) Cancel() 时,得停下来问一句:这个操作是否破坏了业务不变量?它是否该由另一个聚合来触发?这些判断没法被工具检查,只能靠团队对通用语言的持续对齐。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!










