关于 ddd-anti-patterns
ddd-anti-patterns 是面向开发者的 DDD 参考技能,适用于领域模型评审和重构。它整理常见设计异味及其症状、问题原因,并链接到相关模式技能以供查找修正方向。
主要功能
- 01常见 DDD 反模式目录
- 02各类异味的症状与原因
- 03相关模式技能链接
- 04选择重构目标的判断要点
- 05避免过度套用 DDD 的建议
适用场景
- 01评审代码中的领域模型异味
- 02根据发现的异味确定重构方向
- 03向团队成员说明 DDD 常见问题
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ yonatankarp/ software-design-skills --skill ddd-anti-patterns安装后在 Claude Code 中输入/ddd-anti-patterns确认已加载。
详细介绍
一句话摘要
最常见的 DDD 反模式参考目录,每项都列出症状,并链接到说明修复方法的模式技能。
何时使用此技能
- 代码审查(
ddd-review会在每项发现中引用此目录)。 - 重构时发现异味(
ddd-refactor会将此目录用作异味到目标形态的对照表)。 - 讨论“这真的算 DDD,还是只是套用了模式名称的 CRUD”。
- 帮助团队成员入门——用一个页面列出应避免的事项。
何时不使用此技能
- 你已经知道适用哪个模式——直接使用该模式。
- 问题是要构建什么,而不是不该构建什么 → 使用
ddd-design。
核心内容
目录。每项包括:名称、症状、错误原因、修复方法。
贫血领域模型。 实体只是数据包——只有字段、getter 和 setter,没有行为。所有逻辑都放在 *Service 类中。错误原因:模型不承载领域知识;服务变成了针对 DTO 的事务脚本。修复方法:将行为移到实体上。参见 ddd-entity、ddd-domain-service。
基本类型偏执。 用原始的 String、Long、BigDecimal 等表示领域概念——例如 String customerId、Long amount、String currency。错误原因:无法强制执行不变量;共享同一种基本类型的两个概念会变得可以互换;操作也会散落在静态辅助方法中。修复方法:提取值对象。参见 ddd-value-object。
巨型聚合。 一个聚合拥有模型的一半。症状:加载它会拉取数百行数据;锁竞争激增;事务变得难以管理。错误原因:聚合边界应当是事务边界。修复方法:按必须一起变更的内容拆分。参见 ddd-aggregate。
泄漏持久化细节的仓储。 仓储暴露持久化类型(Query、Predicate、EntityManager、框架的 JpaRepository)。错误原因:领域层因此依赖持久化相关事项,无法独立测试。修复方法:在领域层接口上定义领域语言方法,并在基础设施层实现。参见 ddd-repository。
伪装成 DDD 的事务脚本。 服务中充斥着针对数据 DTO 的过程式逻辑,类名却是 *Manager、*Helper、*Processor。错误原因:实际上没有领域层——这些名称制造了 DDD 的假象。修复方法:将行为放到实体上;仅在确实无状态且跨越多个聚合时使用 *Service。参见 ddd-domain-service。
智能 UI。 业务规则嵌入在控制器、视图或前端代码中。“领域”就是数据库里碰巧存着的内容。错误原因:除 UI 外的任何部分都无法访问这些规则。修复方法:提取真正的领域层。参见 ddd-design。
泥球。 完全没有边界,所有内容都能访问其他所有内容。错误原因:无法将变更限制在局部。修复方法:先绘制上下文映射;通过防腐层与泥球集成;不要扩展它。参见 ddd-bounded-context、ddd-context-mapping。
跨聚合对象引用。 Order 持有 Customer 对象引用(而不只是 ID)。错误原因:这会强制进行急切加载,使两个聚合的生命周期相互绑定,并破坏事务边界。修复方法:只保存 ID,需要时通过仓储查找。参见 ddd-aggregate。
Manager / Service / Helper 后缀综合征。 OrderManager、PaymentHelper、AccountProcessor 之类的名称,用技术噪声掩盖了领域动词。错误原因:通用语言应该体现在代码中。修复方法:使用业务所用的动词命名。参见 ddd-ubiquitous-language、ddd-domain-service。
决策启发式
- 如果你能指出一种坏味道,却说不出目标模式,那么问题确实存在,但修复方向尚不明确。先与团队讨论并确定目标形态,再进行重构。
- 严重程度取决于影响范围:被十个调用方触及的泄漏式抽象,比只在一处出现的同类问题更严重。
- 某些反模式在通用子域中是可以接受的(对配置表执行 CRUD,不需要丰富的模型)。不要一概套用 DDD 的全部仪式。参见
ddd-subdomain-classification。
反模式相关的反模式
- 把每个长类都视为贫血模型——贫血关乎行为,而非长度。
- 为了追求模式而追求模式,而不是考虑是否适合实际用途。
- 因为代码不符合教科书式布局,就把可用且经过充分测试的代码称为“错误”。
- 把
Manager重命名为Service,然后称之为重构。
另请参阅
ddd-core中的每个模式技能——每种坏味道都关联到一个或多个模式。ddd-review——将此目录用作检查清单。ddd-refactor——将此目录用作从坏味道查找目标模式的索引。
参考资料
- Evans,《领域驱动设计》(2003 年),第二部分和第三部分。
- Fowler,《贫血领域模型》(2003 年随笔)——对这一反模式的经典论述。