mcpField
D
ddd-anti-patterns

ddd-anti-patterns

github.com/yonatankarp开发143 次安装23 周前更新
代码仓库

关于 ddd-anti-patterns

ddd-anti-patterns 是面向开发者的 DDD 参考技能,适用于领域模型评审和重构。它整理常见设计异味及其症状、问题原因,并链接到相关模式技能以供查找修正方向。

主要功能

  1. 01常见 DDD 反模式目录
  2. 02各类异味的症状与原因
  3. 03相关模式技能链接
  4. 04选择重构目标的判断要点
  5. 05避免过度套用 DDD 的建议

适用场景

  1. 01评审代码中的领域模型异味
  2. 02根据发现的异味确定重构方向
  3. 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 年随笔)——对这一反模式的经典论述。

评论

支持 Markdown