DDD领域建模中聚合根识别及SharedMarkers边界设计咨询
你之前把User作为全局唯一聚合根的设计问题,本质是违背了聚合边界必须和业务事务强一致性边界完全对齐的核心规则:好友关系、自有Marker、共享权限这三类数据不仅没有数量上限,还分属完全独立的业务操作场景,硬塞进User聚合内部必然出现跨实体直接引用、并发写冲突、聚合体积无限膨胀的问题,完全不符合DDD聚合设计要求。
最终聚合划分方案
所有跨聚合关联全部用ID值对象实现,禁止持有其他聚合的直接对象引用,四个核心业务流程和聚合一一对应:
- User 聚合(聚合根:User)
承接Authentication流程,仅负责用户注册、登录认证、基础个人信息维护。聚合内部仅存和用户自身强一致的属性:UserId(值对象)、账号认证凭证、昵称、头像等基础资料,不要挂载好友列表、Marker列表这类无上限的关联数据。 - Friendship 聚合(聚合根:Friendship)
承接Friendship流程,负责好友申请发送、通过、关系解除、好友列表查询。聚合核心属性为三个值对象:RequesterId(申请人UserId)、ReceiverId(接收人UserId)、RelationStatus(待确认/已生效状态)。查询某用户的全量好友时,直接检索所有关联该UserId、状态为已生效的Friendship实例即可,不需要把好友ID列表冗余存到User实体下,天然支持无上限好友数量。 - Marker 聚合(聚合根:Marker)
承接Marker Management流程,负责个人Marker的创建、编辑、删除、自有Marker查询。聚合核心属性包含:OwnerId(所有者UserId,值对象)、Marker地理位置、内容标签、创建时间等Marker本身的固有属性。Marker实体不需要持有任何共享关系相关的字段——修改Marker内容、删除Marker的操作完全不需要联动修改共享权限,二者没有强事务绑定关系。 - MarkerShare 聚合(聚合根:MarkerShare)
承接Marker Sharing流程,就是你之前纠结找不到归属的SharedMarkers对应的业务载体,本身就是独立聚合根,不需要依附User或者Marker存在。聚合核心属性为三个值对象:MarkerId(被共享的Marker ID)、OwnerId(Marker所有者ID)、SharedToUserId(共享目标好友ID),可按需扩展共享权限、共享有效期这类属性。
SharedMarkers 的定位说明
你之前找不到SharedMarkers的合理归属,核心误区是把Marker共享关系错当成了Marker或者User的附属属性,实际上共享关系是完全独立的业务对象:
- 事务边界完全独立:给好友授予/取消Marker共享权限的操作,不需要锁定Marker本身,也不需要修改双方的用户数据、好友关系数据,仅操作MarkerShare实例即可完成,完全满足聚合的事务独立性要求。
- 天然兼容私有Marker场景:不存在对应MarkerShare记录的Marker,默认就是仅所有者可见的私有Marker,不需要给Marker额外加空的共享列表字段承载语义。查询「我收到的好友共享Marker」时,直接检索所有SharedToUserId为当前用户ID的MarkerShare记录,再关联对应Marker内容即可;查询「我的私有Marker」时,直接检索OwnerId为当前用户ID、且无对应有效MarkerShare记录的Marker即可,逻辑链路非常清晰。
- 性能和扩展性友好:独立的MarkerShare聚合天然支持无上限的共享关系存储,不会出现单聚合体积过大的问题,后续如果要加共享分组、共享操作日志这类能力,直接在该聚合上扩展即可,不会侵入原有User、Marker的核心逻辑。
设计校验参考:所有核心业务操作都能在单个聚合内完成事务提交,不需要跨聚合做强一致写:
- 注册、改密码、修改个人资料:仅操作User聚合
- 发好友申请、通过好友、删除好友:仅操作Friendship聚合
- 新建Marker、修改Marker位置/内容、删除Marker:仅操作Marker聚合
- 共享Marker给好友、取消共享、修改共享权限:仅操作MarkerShare聚合
内容的提问来源于stack exchange,提问作者adrianMoskal
相关产品推荐
相关产品推荐

