知识卡片

宽松分层架构的陷阱:漂亮的依赖图很容易被"自律"以外的手段突破

普通读书笔记卡

内容

不管选用[[按层封装与按功能封装的对比水平分层无法体现业务领域信息]]里的哪种分层,严格分层要求依赖箭头永远指向下方、每层只依赖相邻下层——这样能画出一张干净漂亮的单向依赖图,但这张图有个致命弱点:只要引入一些不该有的依赖,照样能”合规”地画出这张图。一个真实场景:新员工接到一个订单相关用例的开发任务,急于表现,翻代码发现了OrdersController就把新的Web代码全塞了进去,但这段代码需要查数据库,新人灵机一动——”反正已经有OrdersRepository接口,用依赖注入框架把它接进控制器不就行了”,几分钟后功能跑通了,但结构图上OrdersController已经在某些情况下绕过了OrderService直接访问数据层——这被称为”宽松的分层架构”,允许某层跳过直接相邻的邻居。有时这是刻意为之且合理的(比如遵循CQRS模式),但更多情况下,绕过业务逻辑层是不合理的,尤其是当业务逻辑层本该承担权限控制职责时。这里真正拥有的其实只是一条规范——”Web控制器不应该直接访问数据层”——但规范如何被强制执行才是核心问题:很多团队仅靠”自律”或代码评审来维持,这份自信听起来不错,但预算削减、工期临近时会发生什么,大家都清楚;少部分团队会用静态分析工具(Ndepend、Structure101、Checkstyle)在构建阶段自动检查违规代码(本质是一段正则表达式,如”web包下的类型不允许访问data包下的类型”),这种方式简单粗暴但确实有效——不过这两种方法有个共同短板:容易出错,且反馈循环时间太长,一旦疏于维护,整个代码库很快就会退化成”一团泥巴”,因此更该优先选择能让编译器直接强制执行架构规则的做法。

参考来源

- 位置:《架构整洁之道》第34章《拾遗》"按组件封装"部分中的"宽松的分层架构"讨论(源文件:_epub-src/text/part0015_split_004.html) - 结论依据:原文用新员工绕过OrderService直接把OrdersRepository注入Controller的真实场景说明宽松分层架构的隐患,并对比"自律/代码评审"与"静态分析工具"两种强制手段各自的局限,指出编译器强制执行是更优选择,直接支撑本卡片结论。 - 原始内容:依赖关系箭头依然向下,但是现在OrdersController在某些情况下绕过了OrderService类……这里的核心问题当然是如何强制执行……我遇见的很多团队仅仅通过采用"自律"或者"代码评审"方式来执行……我个人更倾向选择能够让编译器执法的做法。