整洁架构下用户关注场景的聚合设计问题咨询
你当前的实现大方向符合整洁架构下的领域驱动设计思路,针对三个问题具体说明如下:
问题1:如何保障每个用户最多对应一个Follower聚合根实例
首先你当前的Follower聚合设计有个冗余点:不需要给Follower分配独立的Id主键,Follower的唯一标识天然就是绑定的UserId,从根源上减少同一个用户生成多个Follower实例的可能。
具体保障机制分两层,缺一不可:
- 领域层约束:不要暴露
Follower的公共构造函数,通过工厂方法或者仓储获取Follower实例:查询时先根据UserId查是否已有对应Follower记录,存在就返回已有实例,不存在才初始化新的实例,从代码逻辑上避免重复创建。 - 存储层兜底:在数据库层面给
Follower表的UserId字段加唯一索引,这是防并发、防代码bug的最终屏障——高并发场景下,两个请求同时查询发现没有对应Follower再同时创建的情况,光靠代码层校验兜不住,必须靠数据库唯一约束做最终一致性保障。
问题2:聚合拆分边界怎么划定?新建独立Gallery聚合的认知是否正确
聚合边界的核心判定原则非常简单,就两条:
- 聚合是业务一致性的最小单元:修改聚合内的任意数据时,必须把整个聚合加载到内存,在同一个事务里完成提交,保证聚合内的所有业务规则都被满足;
- 聚合尽量做小:不要把没有强一致性要求的实体塞到同一个聚合里,聚合之间只通过ID关联,不要直接持有其他聚合的对象引用。
按照这个原则判断,你给用户发图片功能新建独立Gallery聚合的认知完全正确。
你可以反过来验证:修改用户昵称、头像这些核心信息的时候,根本不需要加载用户发过的所有图片数据;反过来给用户相册加图片、删图片的时候,也不会改动用户本身的核心属性,两者没有强一致的事务要求,拆成独立聚合是最优选择,能避免User聚合无限膨胀导致的性能问题。
顺便说一句,你现在把Follower从User聚合里拆出来的思路也是对的——修改关注列表和修改用户核心信息本来就是两个独立的业务场景,不需要放在同一个聚合里。
问题3:Follow类没有业务逻辑,是否应该设计为值对象
结论是:就你当前的业务场景来说,Follow完全可以设计为值对象,不需要作为子实体存在。
判断是实体还是值对象的核心标准从来不是有没有业务逻辑,而是两个点:
- 有没有独立的唯一标识:实体靠唯一ID区分,哪怕两个实体所有属性都一样,ID不同就是不同的对象;值对象没有独立ID,只要所有属性完全相等,就认为是同一个对象。
- 有没有可变的状态:实体允许在生命周期内修改自身属性;值对象是不可变的,创建之后就不能修改,要变更只能整体替换。
回到Follow类:你现在给它加的独立Id完全是多余的——判断两条关注记录是不是同一个,只需要看「关注者ID+被关注者ID」的组合是否一致就行,根本不需要额外的ID。而且关注记录一旦创建,既不会修改关注时间,也不会修改被关注人,要取消关注直接删除对应记录即可,没有独立的状态变更需求,完全符合值对象的特征。
当然如果后续业务迭代,要给关注关系加备注、分组、特别关心标记这类需要单独修改的属性,你也可以再把它升级为子实体,设计本来就是跟着业务走的,不用一开始就做过度设计。
内容的提问来源于stack exchange,提问作者Hervé

