垂直切片架构是否违背DRY原则?如何协调与解决?
垂直切片架构的核心目标是隔离业务上下文,避免跨切片的强耦合,而非完全杜绝代码复用。你提到的认证信息复用问题,本质是如何在保持切片独立性的前提下,合理落地DRY原则,核心思路是区分「可复用的通用能力」和「需隔离的业务逻辑」,以下是具体解决方案:
1. 提取无业务逻辑的基础设施组件
将获取认证信息的纯技术逻辑(比如解析JWT令牌、从请求上下文提取用户标识)封装为独立的基础设施服务/工具类,这类组件不属于任何业务切片,仅提供通用技术能力。
例如,编写一个全局的AuthUtility类:
public static class AuthUtility { public static Guid GetCurrentUserId(HttpContext context) { // 从请求头/上下文解析JWT,提取用户ID的逻辑 var token = context.Request.Headers["Authorization"].FirstOrDefault()?.Split(" ").Last(); var claims = new JwtSecurityTokenHandler().ReadJwtToken(token).Claims; return Guid.Parse(claims.First(c => c.Type == "userId").Value); } }
所有业务切片都可以直接调用这个工具类,既避免了重复代码,又不会让切片依赖其他业务切片的逻辑——因为这个工具类是纯技术实现,不包含任何Auth切片的业务规则(比如权限校验、用户注册逻辑)。
2. 用事件驱动实现业务数据的异步同步
如果需要复用的是Auth切片的业务数据(比如用户角色、权限配置),而非纯技术标识,建议采用发布-订阅模式:
- Auth切片在用户认证、权限变更等关键事件发生时,发布领域事件(如
UserRoleUpdated); - 其他业务切片订阅这些事件,将所需的业务数据同步到自身的存储或缓存中;
- 后续业务处理时,直接使用本地存储的数据,无需调用Auth切片的API或查询其数据库。
这种方式既保证了切片的独立性(无需直接依赖Auth切片的数据源),又避免了重复获取数据的逻辑,同时还能应对Auth切片业务规则变更的场景——只要事件契约不变,其他切片无需修改。
3. 共享纯数据结构(DTO/值对象)
对于多个切片都需要用到的纯数据载体(比如用户ID、用户名这类无业务逻辑的字段),可以定义共享的DTO或值对象,例如:
public record UserIdentity(Guid UserId, string Username);
这个对象仅包含数据字段,没有任何业务方法,所有切片都可以引用它,不会造成业务耦合。但需要注意:这类共享对象绝对不能包含任何业务规则(比如密码加密、权限校验逻辑),否则会引入跨切片的业务依赖。
4. 警惕“伪重复”:区分业务独立实现与无意义重复
有时候看似重复的代码,实则是不同业务上下文的独立需求,这类场景下无需强行复用。例如:
- 订单切片需要用户ID来标记订单归属,日志切片需要用户ID来记录操作人——这类需求本质一致,应该复用;
- 订单切片需要校验用户是否有创建订单的权限,报表切片需要校验用户是否有查看报表的权限——这两个权限逻辑属于不同业务规则,即使代码结构相似,也应该各自实现,因为未来它们可能会有不同的变更(比如订单权限新增VIP限制,报表权限新增部门限制)。
总结
垂直切片架构与DRY原则并不冲突,核心是在正确的层级复用:
- 复用基础设施层的通用技术能力,避免无意义的代码重复;
- 隔离业务层的逻辑,避免为了复用而引入跨切片的业务耦合;
- 通过事件驱动、共享纯数据结构等方式,在保持切片独立性的前提下,实现合理的复用。
内容的提问来源于stack exchange,提问作者せいゆう

