ddd-refactor
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseOne-line summary
一句话总结
Sequence a refactor toward DDD: identify the smell, name the target pattern, propose small behavior-preserving steps in order.
按顺序推进面向 DDD 的重构:识别代码异味,命名目标 pattern,提出保持行为不变的小步骤。
When to use this skill
何时使用此 skill
- Existing code that the user already considers a problem.
- The user knows roughly which direction to refactor in.
- Migration of a legacy module toward a DDD model.
- 用户已经认为现有代码存在问题的场景。
- 用户大致知道希望朝哪个方向重构。
- 将遗留模块迁移到 DDD 模型。
When NOT to use this skill
何时不应使用此 skill
- The user just wants a review and isn't ready to refactor → route to .
ddd-review - The user is starting a new domain model from scratch → route to .
ddd-design
- 用户只是希望进行 review,尚未准备重构 → 转到 。
ddd-review - 用户正在从零开始设计新的 domain model → 转到 。
ddd-design
Core content
核心内容
The general pattern: name the smell, name the target shape, write small steps that preserve behavior, run tests between each step, commit after each.
Common refactors and their step sequences:
Anemic model → behavioral entity. (1) Pick one operation currently done by a service. (2) Move it onto the entity, keeping the same signature. (3) Have the service delegate to the new entity method. (4) Inline the service call where it is the only caller. Repeat per operation.
Primitive obsession → value object. (1) Introduce the new value object type with a private constructor and a validating factory. (2) Add a single conversion point at the boundary (input parsing). (3) Replace one usage at a time, deepest-first. (4) Stop allowing the primitive at the public API. See .
ddd-value-objectGod aggregate → multiple aggregates. (1) List the entities currently inside it. (2) For each pair, ask "must these change in the same transaction?" — group by yes-answers. (3) Identify the root of each group. (4) Replace cross-group object references with ID references. (5) Move cross-group consistency to events. See .
ddd-aggregateLeaky repository → domain repository interface. (1) Define a domain-layer interface with methods named in the ubiquitous language. (2) Implement it in the infra layer, wrapping the existing persistence. (3) Switch one caller at a time. (4) Delete the leaked types from the domain layer. See .
ddd-repositoryBig ball of mud → first bounded context. (1) Pick the most painful seam. (2) Draw the intended boundary on paper. (3) Introduce an anticorruption layer at the seam. (4) Move code across the seam one type at a time. See for the seam's pattern.
ddd-context-mapping通用 pattern:识别代码异味,命名目标形态,编写保持行为不变的小步骤,在每一步之间运行测试,并在每一步完成后 commit。
常见重构及其步骤顺序:
Anemic model(贫血模型)→ behavioral entity(行为实体)。(1)选择当前由 service 执行的一项操作。(2)将该操作移到 entity 上,并保持相同的 signature。(3)让 service 委托给新的 entity 方法。(4)如果某个 service 调用只有一个调用方,则将其内联。对每个操作重复此过程。
Primitive obsession(基本类型偏执)→ value object(值对象)。(1)引入新的 value object 类型,设置私有 constructor 和负责校验的 factory。(2)在边界处添加一个统一的转换点(输入解析)。(3)从最深层开始,一次替换一个使用点。(4)不再允许 primitive 出现在 public API 中。参见 。
ddd-value-objectGod aggregate(上帝聚合)→ multiple aggregates(多个 aggregate)。(1)列出当前包含在其中的 entities。(2)逐一比较每对 entity,并询问“它们是否必须在同一个 transaction 中变更?”——根据肯定答案进行分组。(3)确定每组的 root。(4)用 ID references 替换跨组的对象引用。(5)通过 events 管理跨组一致性。参见 。
ddd-aggregateLeaky repository(泄漏仓储)→ domain repository interface(领域仓储接口)。(1)定义 domain-layer interface,并使用 ubiquitous language 命名其中的 methods。(2)在 infra layer 中实现该 interface,封装现有 persistence。(3)一次切换一个调用方。(4)从 domain layer 中删除泄漏的类型。参见 。
ddd-repositoryBig ball of mud(大泥球)→ first bounded context(第一个 bounded context)。(1)选择最棘手的 seam。(2)在纸上画出预期的边界。(3)在 seam 处引入 anticorruption layer。(4)一次将一个 type 移过该边界。有关 seam 的 pattern,参见 。
ddd-context-mappingDecision heuristics
决策启发式
- Never combine a refactor commit with a feature commit. They review separately, they revert separately.
- Each step must keep behavior identical. The test suite is your seatbelt; if it doesn't exist, write characterization tests first.
- Stop after each step long enough to run tests and commit.
- Big-bang rewrites lose users' trust and almost always grow scope. Prefer ten small refactors over one large one.
- 绝不要将 refactor commit 与 feature commit 合并。两者应分开 review,也应分开 revert。
- 每一步都必须保持行为完全一致。test suite 是你的安全带;如果它尚不存在,应先编写 characterization tests。
- 每完成一步,都应停下来运行测试并 commit,然后再继续。
- Big-bang rewrite 会失去用户的信任,并且几乎总会扩大范围。相比一次大型重构,应优先采用十次小型重构。
Anti-patterns
反模式
- Big-bang rewrite with no incremental milestones.
- Refactoring without a test net.
- Renaming classes "to sound DDD" without changing their structure or responsibilities.
- Refactoring and adding features in the same change.
- 没有 incremental milestones 的 big-bang rewrite。
- 没有 test net 的重构。
- 只是重命名 classes 以“听起来更 DDD”,却没有改变其结构或职责。
- 在同一次变更中同时进行重构和添加功能。
See also
另请参见
- — the smells that motivate each refactor.
ddd-anti-patterns - ,
ddd-aggregate,ddd-value-object,ddd-bounded-context— target shapes.ddd-repository - — what to do after the obvious refactors are done.
ddd-deeper-insight
- ——推动各项重构的代码异味。
ddd-anti-patterns - 、
ddd-aggregate、ddd-value-object、ddd-bounded-context——目标形态。ddd-repository - ——完成显而易见的重构之后应采取的步骤。
ddd-deeper-insight
References
参考资料
- Evans, Domain-Driven Design (2003), Part III (Chs 8–13).
- Evans,Domain-Driven Design(2003),第三部分(第 8–13 章)。