go语言如何用ddd设计_go语言领域驱动设计教程【必看】

Go 里没有抽象类、没有“DDD 框架”、也不需要照搬 Java 的分层接口模板——硬套只会让代码变重、测试失灵、IDE 跳转失效。DDD 在 Go 中能落地,靠的是包路径约束、窄接口、显式依赖和结构体组合,不是靠生成器或泛型包装。

domain 层为什么不能 import database/sql 或 gin

领域模型(如 Order、Customer)一旦引入 database/sql 或 HTTP 框架,就等于把存储细节和传输协议泄漏进业务核心。这会导致:

无法离线单元测试:一跑 TestOrder_ApplyDiscount 就 panic,因为缺 DB 连接重构成本飙升:想把 MySQL 换成 SQLite?得改遍所有 *sql.DB 依赖的 domain 文件IDE 失去语义:Ctrl+Click Order.Save() 跳到的不是业务逻辑,而是某个 infra 包里的 SQL 拼接

正确做法是让 Order 只关心“满减不能和优惠券同用”,校验逻辑写在 Order.Validate() 里;而“存到哪、怎么存”,交给 OrderRepository 接口,实现放在 infrastructure/mysql/order_repo.go。

Repository 接口该定义在 domain 还是 infra

必须定义在 domain/ 下,比如 domain/order/repository.go:

立即学习“go语言免费学习笔记(深入)”;

type OrderRepository interface { Save(ctx context.Context, o *Order) error FindByID(ctx context.Context, id OrderID) (*Order, error)}

原因很直接:

领域层要表达“我需要能存、能查”,这是它的协作契约,不是 infra 的实现细节application 层(如 application/place_order.go)才能同时持有 *Order 和 OrderRepository,完成“校验 → 创建 → 存储”闭环infra 层实现时 import domain 包是合法的;反过来,domain import infra 就彻底破防

别写 mysql.OrderRepository 这种类型——它会诱使你在 domain 里直接 new 它,绕过接口抽象。

聚合根事件为什么不能用 channel 异步发布

常见错误是这样写 order.Cancel():

func (o *Order) Cancel() { o.status = StatusCancelled go func() { eventbus.Publish(OrderCancelled{ID: o.ID}) }() // ❌ 危险!}

问题有三个:

panic 丢失:goroutine 里 publish 失败,主流程完全不知情事务不一致:DB 事务还没 commit,下游 event handler 就去查订单,查不到测试不可控:你没法断言“这次 Cancel 是否发了事件”,因为它是异步的、无返回值的

正确模式是同步返回事件切片:

func (o *Order) Cancel() []Event { o.status = StatusCancelled return []Event{OrderCancelled{ID: o.ID}}}

然后由 application 层在事务提交后统一处理:

if err := repo.Save(ctx, order); err != nil { return err}eventbus.Publish(orderEvents…) // ✅ 显式、可测、可控

go:generate 能省什么,又绝不能碰什么

生成代码只该干两件事:数据搬运 + 基础校验。

✅ 推荐生成:Scan()/Value()(用 entgen)、ToDTO()(用 stringer 或自定义模板)、Validate() 入参(配合 go-playground/validator 标签)❌ 绝对禁止生成:Order.IsValid() 里的业务规则(如“预售订单不能取消”)、Apply() 中的状态流转逻辑、任何含 if/else 判断的领域行为

生成代码必须进 internal/gen/,永远不进 domain/ —— 否则 PR 里全是 Scan() 方法字段顺序调整 这类噪音,团队很快就会关掉生成逻辑。

声明:本站所有文章,如无特殊说明或标注,均为本站原创发布。任何个人或组织,在未征得本站同意时,禁止复制、盗用、采集、发布本站内容到任何网站、书籍等各类媒体平台。如若本站内容侵犯了原著者的合法权益,可联系我们进行处理。