You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

DDD聚合设计需遵循哪些规则?附家庭预算项目设计问题

DDD聚合设计落地步骤与家庭预算场景问题解法

聚合设计的标准执行流程

  • 第一步:从事件风暴产出中筛选所有必须在单事务内成立的核心业务不变式,严格区分“体验层面的校验规则”和“不满足就会产生核心业务错误的强规则”,禁止将非核心规则纳入强一致范畴。
  • 第二步:围绕每一条核心强一致不变式,圈定完成该校验所需的最小关联实体集合,集合内仅包含校验必需的属性,不额外放入仅用于查询、无强校验关联的实体。
  • 第三步:对初步圈定的实体集合做边界校验,符合以下任意一条的集合必须拆分:
    • 集合内实体不存在生命周期绑定:某一实体删除/归档后,其余实体仍具备独立业务意义
    • 集合内实体操作频率不匹配:某类实体的写入/更新频率比其余实体高2个数量级及以上
    • 集合存在无限制膨胀风险:集合内包含随业务运行持续追加、无明确上限的子实体列表
  • 第四步:为拆分后的每个独立实体集合选定聚合根,聚合根是集合内唯一允许被外部直接引用的实体,跨聚合关联仅允许通过聚合根ID实现,禁止直接持有其他聚合的内部实体引用。
  • 第五步:为拆分后无法在单聚合内完成校验的非核心规则,逐一匹配最终一致性实现方案,禁止为了满足非核心规则的强一致要求破坏聚合边界。

家庭预算规划场景的具体落地方案

“支出不可归属到早于支出日期就已停用的分类”属于典型的体验类校验规则,不属于必须保证事务强一致的核心不变式,完全可以在不破坏聚合边界的前提下实现,不需要将支出记录与支出分类放入同一聚合:

  • 首先划定三个独立聚合,符合聚合设计规则:
    1. 支出分类组聚合:聚合根为ExpenseCategoryGroup,仅包含组基础属性、组内分类ID列表,负责分类组增删改、组内分类排序逻辑
    2. 支出分类聚合:聚合根为ExpenseCategory,包含分类名称、所属组ID、启用/停用状态、停用时间戳属性,负责分类增删改、停用/启用逻辑
    3. 支出记录聚合:聚合根为Expense,包含支出金额、支出时间、关联分类ID、交易备注属性,负责支出记录增删改、金额合法性校验逻辑
  • 针对分类停用时间的校验规则,用三层机制覆盖即可,一致性体验完全满足个人记账场景需求:
    1. 提交前置校验:用户提交新支出记录时,应用层先查询关联分类的状态与停用时间,若分类已停用且停用时间早于支出时间,直接返回前端提示阻止提交,覆盖99.9%的正常操作场景
    2. 操作触发校验:执行分类停用操作时,触发异步任务扫描所有关联该分类、且支出时间晚于分类停用时间的支出记录,标记异常状态并推送提醒给用户修正
    3. 定期巡检校验:每日运行定时任务扫描全量支出记录,校验关联分类的状态与停用时间,对漏处理的异常记录推送修正提醒

极端并发场景下(用户提交支出的同一秒分类被停用)可能产生极少量异常数据,最多延迟24小时就会被巡检发现,不会对预算统计、支出分析的核心逻辑产生不可逆影响,完全在个人副业项目的可接受范围内。

共性问题解答

  • 不存在“聚合精简合规+所有规则强一致”的完美设计。聚合设计的本质是业务权衡:涉及资金、交易确权的核心规则必须保证强一致,非核心的体验类规则全部用最终一致性实现,为了追求100%事务强一致把聚合做成无边界的大集合,是典型的设计反模式。
  • 初级开发者占比高的团队确实可能出现DDD架构退化,但问题核心不是DDD本身,而是缺乏边界评审机制。如果允许开发者随意跨聚合持有引用、在应用层散落业务逻辑,无论采用什么架构都会出现腐化。反过来,清晰的聚合边界反而能降低初级开发者的犯错成本——开发者只需要在指定聚合边界内实现逻辑,不需要感知全量业务关联。
  • DDD的额外设计成本仅存在于项目初期。聚合边界划定完成后,后续开发效率反而高于传统三层架构:业务逻辑全部内聚在聚合内,不需要排查散落的校验规则;规则变动时只需要定位影响的聚合范围,不会出现改一处牵全身的问题。对个人副业项目来说,初期投入1-2天明确聚合边界,后续迭代的维护成本会大幅降低。

内容的提问来源于stack exchange,提问作者Bladositto

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.29 16:03:31