跳转到内容

面试专题

面试不是背概念,而是展示你做过取舍、踩过坑、知道什么时候该用什么时候不该用。

DDD 和 MVC / 三层架构有什么区别?

Section titled “DDD 和 MVC / 三层架构有什么区别?”

MVC / 三层架构主要是技术分层,解决代码组织问题;DDD 更关注业务建模,解决复杂业务规则如何表达和维护的问题。传统三层容易让 Service 承载所有业务逻辑,领域对象变成贫血模型。DDD 强调领域对象承载业务规则,应用服务只做流程编排。

看身份。需要唯一 ID,生命周期独立,属性变化后仍是同一个对象,就是实体。不关心身份,只关心值是否相等,通常不可变,就是值对象。例如订单是实体,金额是值对象。

聚合根是聚合对外唯一入口,负责维护聚合内部一致性。外部不能直接修改聚合内部对象,只能通过聚合根的方法执行业务行为。

DAO 通常面向表,提供 CRUD;Repository 面向聚合,负责保存和重建聚合根。Repository 接口属于领域层,实现属于基础设施层,这样领域层不依赖数据库技术。

领域服务和应用服务有什么区别?

Section titled “领域服务和应用服务有什么区别?”

应用服务负责编排用例、事务、权限、调用外部系统;领域服务负责表达不适合放在实体/值对象里的领域规则。一句话:应用服务管流程,领域服务管业务规则。

当一个领域动作完成后,需要通知其他模块或其他聚合继续处理时,可以使用领域事件。例如支付成功后,订单状态更新、账务入账、通知用户不一定都写在支付聚合中,可以发布 PaymentSucceeded 事件解耦。

不一定。领域事件是 DDD 的常见模式,但不是必须。简单场景可以同步调用;跨聚合、跨服务、最终一致场景更适合事件。

  • 学习和设计成本高
  • 对团队建模能力要求高
  • 简单 CRUD 场景可能过度设计
  • 如果只套目录结构,没有真实领域模型,会变成“伪 DDD”

大量订单明细还适合放一个聚合吗?

Section titled “大量订单明细还适合放一个聚合吗?”

不一定。要看一致性要求。如果每次修改订单都必须校验全部明细,那放一起有业务理由,但性能会有问题。如果订单明细可以分批处理,或者只需要最终汇总一致,可以考虑拆成更小聚合,用事件更新订单汇总。

聚合不是越完整越好,边界要同时考虑一致性和性能。

领域事件和事务提交怎么保证一致?

Section titled “领域事件和事务提交怎么保证一致?”

使用 Outbox Pattern:在同一个本地事务中保存业务数据和 outbox 事件表,事务提交后由后台任务或消息 relay 投递 MQ,消费端幂等处理。

避免先提交 DB 再发 MQ(MQ 失败会丢事件),也避免先发 MQ 再提交 DB(消费者可能读不到数据)。

不一定。聚合适合处理命令和状态变更,不适合复杂查询、报表、分页列表。查询可以走 read model、QueryService、DTO projection,甚至直接 SQL,只要不绕过领域规则修改状态即可。

我理解 DDD 的重点不是套概念,而是用领域模型承载核心业务规则。比如支付、业财、交易这类系统,真正复杂的是状态流转、金额规则、幂等、风控、对账和一致性。如果这些规则都写在应用 Service 或 SQL 里,系统会越来越难维护。DDD 的作用是把核心规则沉淀到领域层,让模型表达业务约束。

DDD 的核心是让代码表达业务,而不是只表达数据库表和技术流程。我通常会先识别限界上下文,再找核心聚合和值对象,把状态流转和不变量放到聚合根方法中。应用服务只负责编排事务和调用领域对象,Repository 负责聚合持久化。跨聚合或跨服务协作尽量通过领域事件、Outbox、消息最终一致和幂等补偿来处理。

对于业财、支付、交易这类系统,我认为 DDD 的价值比较明显,因为它们都有复杂状态、金额规则、一致性和审计要求。简单 CRUD 则不一定需要完整 DDD,避免过度设计。