模块拆分边界识别:业务边界、技术边界、复用边界、变化频率边界

单一职责在模块设计中的核心是边界划分。如果边界不清,模块就会膨胀、职责混杂、耦合加深。实践中存在四条关键边界,它们分别从不同维度约束模块的粒度和职责。只有同时识别并协调这四条边界,才能达到“高内聚、低耦合”的设计目标。

1. 边界定义与对比

边界类型 定义 划分依据 典型模块示例
业务边界 基于业务领域或功能域拆分的边界 用户故事、领域模型、业务用例 支付模块、订单模块、用户模块
技术边界 基于技术栈、底层平台或基础设施的边界 框架选择、SDK版本、编译目标 网络层模块、数据库ORM模块、相机模块
复用边界 基于代码复用潜力的边界 是否被多个业务模块依赖、是否独立于业务 通用工具库、UI组件库、基础网络库
变化频率边界 基于需求变更速度和迭代节奏的边界 特性演变周期、技术演进路线、团队迭代频率 配置模块(高频变更)、支付渠道插件(低频变更)
关键原则:四种边界并非孤立存在——业务边界决定模块「做什么」,技术边界决定「用什么」,复用边界决定「被谁用」,变化频率边界决定「多久改一次」。模块的最终边界是这四个维度的交集或协商结果。

2. 分层模型与组件职责

基于四边界,Android模块通常组织为三层:业务层(由业务边界主导)、技术层(由技术边界主导)、复用层(由复用边界主导),而变化频率边界则作为动态调节因子,在每层内部进一步细分模块粒度。

  • 业务层模块:承担完整业务逻辑,包含UI、ViewModel、UseCase等。变化频率中等偏高,受产品需求驱动。
  • 技术层模块:封装底层能力(网络、存储、日志)。变化频率较低,受SDK升级或架构演进影响。
  • 复用层模块:提供无业务语义的通用能力(工具类、自定义View、注解处理器)。变化频率最低。
  • 变化频率边界在每层内部指导“是否应拆出独立模块” —— 例如在业务层中,配置模块(高频变更)与核心业务模块(低频变更)应分属不同模块,避免高频变更波及稳定业务。

3. 数据流 / 控制流 / 信任链路

边界决定了模块间的依赖方向和通信契约:

  • 数据流:复用层 → 技术层 → 业务层(单向依赖);业务层之间通过事件或接口交互,禁止直接依赖。
  • 控制流:变化频率高的模块(如配置模块)应通过接口回调或观察者模式通知变化,避免高频模块反向依赖稳定模块。
  • 信任链路:边界越稳定,越应作为跨模块的信任锚点。例如通用工具库提供的DateUtil接口被所有业务模块信任,而支付模块的PaymentCallback只在业务层内部被信任。

4. 选型权衡

权衡点 侧重业务边界 侧重技术边界 侧重复用边界 侧重变化频率边界
模块粒度 较粗(按功能域) 中等(按技术栈) 较细(按复用场景) 动态决定
耦合风险 业务模块间易耦合 技术模块与业务逻辑耦合 过度抽象导致接口膨胀 频繁变更模块污染稳定模块
维护成本 业务变更影响面大 技术升级需同时改多个业务模块 复用模块版本管理复杂 需持续审计变化频率
推荐场景 中大型App稳定业务 跨平台或混合架构项目 组件化程度高的项目 快速迭代的创业期产品
平衡建议:以业务边界为主框架,用技术边界隔离基础设施,用复用边界提取共性,用变化频率边界做动态拆分。例如在settings.gradle中按此原则组织模块:
// settings.gradle.kts —— 按四边界组织模块
include(":app")
// 业务边界模块
include(":feature:payment")
include(":feature:order")
include(":feature:user")
// 技术边界模块
include(":libraries:network")          // 网络层(Retrofit + OkHttp)
include(":libraries:storage")          // 存储层(Room)
// 复用边界模块
include(":libraries:common-ui")        // 通用UI组件
include(":libraries:core-util")        // 工具库
// 变化频率边界 —— 独立拆分配置模块,高频变更不影响核心
include(":libraries:remote-config")    // 远程配置模块(Firebase / 自研)

5. 风险点

  • 过度拆分:追求单一职责而拆分出过多微型模块,导致编译链延长、依赖复杂度上升,尤其容易发生在复用边界和变化频率边界上。
  • 边界冲突:业务边界要求模块完整,但技术边界要求模块独立,例如支付模块需要同时依赖多个网络库 -> 解决之道是引入防腐层。
  • 变化频率误判:将低频变更模块与高频变更模块放在同一模块中,导致每次配置修改都要重建整个模块及其依赖方。
  • 信任链断裂:高频模块直接依赖低频模块的私有类,破坏封装 -> 应通过接口隔离。

6. 落地步骤

  1. 识别:用DDD事件风暴找出业务边界;梳理技术栈依赖确定技术边界;分析依赖图找出复用热点;统计版本发布历史识别变化频率。
  2. 评估:对候选边界用依赖度 + 变更频率矩阵打分,优先拆分高变更高依赖的模块。
  3. 验证:原型验证模块间接口是否自然、编译是否独立、测试是否容易。
  4. 调整:根据实际迭代反馈收敛或扩展边界,每季度重新审视变化频率。

7. 验收标准

  • 独立构建:每个模块可在不依赖其他业务模块的情况下单独编译并通过单元测试。
  • 最小影响面:修改高频模块(如配置模块)无需重编低频模块。
  • 无循环依赖:模块依赖图不存在方向循环,且业务层→技术层→复用层流向清晰。
  • 接口契约可测试:所有跨模块接口都有mock实现,能独立验证。
  • 变化频率可度量:模块的git commit频率在相邻迭代周期间保持稳定(差异小于20%)。
模块拆分边界识别四象限图 单一职责 业务模块 业务边界 支付模块 技术边界 网络层模块 复用边界 通用工具库 变化频率边界 配置模块 四种边界共同约束模块粒度和职责,单一职责是它们的交汇点
常见陷阱:团队常片面强调“业务边界”而忽略变化频率边界,导致高变更模块与稳定业务模块耦合。建议在模块命名或目录结构上显式标注变化频率等级(例如 :feature:payment-stable 与 :feature:payment-experiment),从命名上强制提醒。