2 模块数据域划分原则
在多模块 Android 应用中,数据散落于不同模块,若缺少统一的划分准则,必然导致数据归属冲突、同步策略混乱、模块职责边界模糊。本章以业务边界、变更频率、访问模式三个维度为核心,建立一套可量化、可落地、可评审的数据域划分方法论,为后续的跨模块同步策略提供结构化依据。
2.1 划分的必要性
未划分数据域时,各模块直接操作同一张 Room 表或共享同一份 DAO,引发三类典型问题:
- 数据归属冲突——两个模块都认为自己对某张表拥有写权限,导致写覆盖或级联删除不可控;
- 同步策略混乱——高频变更数据与低频变更数据使用同一套同步机制,低效且浪费资源;
- 职责边界模糊——无法确定哪个模块应当对数据一致性负责,异常发生时互相推诿。
核心收益:数据域划分将“全局数据空间”拆解为若干个自治的“数据域”,每个域拥有明确的数据主权、独立的变更策略和标准化的对外契约,为跨模块同步奠定可治理的基础。
2.2 三大划分原则详解
2.2.1 业务边界原则
按业务模块的职责范围划定数据归属。一个数据实体只能属于一个业务域,不允许出现“两个模块同时声明对同一张表的主权”。业务边界是数据域划分的第一性原理,决定了数据域的基本粒度。
| 业务模块 | 所属数据域 | 典型实体 |
|---|---|---|
| 用户模块 | 用户域 | User、UserProfile、UserCredential |
| 商品模块 | 商品域 | Product、ProductVariant、Category |
| 订单模块 | 订单域 | Order、OrderItem、OrderStatus |
| 支付模块 | 支付域 | Payment、Transaction、Refund |
2.2.2 变更频率原则
按数据更新的频次将数据域划分为高频域、中频域、低频域。变更频率直接决定了同步策略的选择:高频域宜采用事件驱动实时同步,低频域可采用定时批量同步或懒加载同步。
| 频率层级 | 典型变化周期 | 推荐同步策略 | 示例数据域 |
|---|---|---|---|
| 高频 | 秒级~分钟级 | 实时事件同步 | 订单域、支付域 |
| 中频 | 小时级 | 定时增量同步 | 商品库存域 |
| 低频 | 天级或更慢 | 懒加载 / 全量刷新 | 用户域、配置域 |
2.2.3 访问模式原则
按数据的读写比例与访问特征将数据域分为读密集域、写密集域、读写均衡域。访问模式影响存储结构与缓存方案的设计:读密集域应引入本地缓存 + 只读副本,写密集域则需要写入队列 + 冲突解决策略。
| 访问模式 | 读写比例 | 存储结构倾向 | 典型数据域 |
|---|---|---|---|
| 读密集 | 读 > 90% | 本地缓存 + 只读 Room 副本 | 用户域、商品域 |
| 写密集 | 写 > 60% | 写入队列 + 异步合并 | 日志域、审计域 |
| 读写均衡 | 40% ~ 60% | 主从分离 / CQRS | 订单域、支付域 |
2.3 数据域划分矩阵
将变更频率(横轴)与访问模式(纵轴)组合,形成一个 2×2 的决策矩阵,业务边界在每个象限内部确定具体的数据域名称。下表的每个单元格代表一类具有相似同步特征的数据域集合。
| 低频变更 | 高频变更 | |
|---|---|---|
| 读密集 | 用户域、商品域(基础资料) | 缓存域、配置域(热配置) |
| 写密集 | 日志域、审计域(归档型) | 订单域、支付域(交易型) |
实战建议:在项目初期,优先按“业务边界”完成第一轮划分,再通过 Git 提交频率分析、SQLite WAL 日志采样等方式量化“变更频率”和“访问模式”,逐步修正矩阵中的位置。
2.4 数据域划分图谱
下图将三大原则整合到一个视图中:业务边界定义每个数据域的名称与归属;变更频率与访问模式构成 2×2 象限,决定同步策略与存储结构选型。图中的箭头表示原则对数据域的驱动关系。
图谱解读:左上象限(蓝)为代表“低频·读密集”的基础资料域,宜采用懒加载 + 本地缓存;右上象限(绿)为“高频·读密集”的热数据域,需要订阅推送 + 内存缓存;左下象限(橙)为“低频·写密集”的归档域,采用定时批量写入即可;右下象限(红)为“高频·写密集”的交易域,必须使用实时事件同步 + 冲突解决机制。
2.5 选型权衡
| 权衡维度 | 选项 A | 选项 B | 推荐场景 |
|---|---|---|---|
| 划分粒度 | 粗粒度(模块级) | 细粒度(实体级) | 初期粗粒度快速落地,中期逐步细化 |
| 同步实时性 | 实时事件驱动 | 定时批量同步 | 高频写密集 → 实时;低频读密集 → 定时 |
| 一致性模型 | 强一致性 | 最终一致性 | 支付域 → 强一致;用户资料 → 最终一致 |
| 存储冗余 | 每个域独立表空间 | 共享表 + 视图隔离 | 业务独立性强 → 独立表;共享基表 → 视图 |
2.6 风险点
- 边界模糊导致数据归属争议——例如“订单快照”既属于订单域又属于用户域。解决方案:确立“主数据源”原则,快照的主数据源归订单域,用户域只持有只读副本。
- 变更频率误判导致同步策略失效——将高频域误判为低频域,造成数据延迟过大。解决方案:上线前进行一周的变更频率采样,使用 Room 的
@Insert(onConflict = REPLACE)计数辅助判断。 - 访问模式变化导致性能退化——原本读密集的域因业务扩展变为读写均衡。解决方案:每个域保留访问模式监控指标,季度复盘调整象限归属。
- 过度划分增加维护成本——数据域颗粒度过细导致域间同步链路数量爆炸。解决方案:控制数据域总数不超过 8~10 个,单个域内实体数不超过 15 个。
关键警告:不要为了“完美划分”而陷入过度设计。数据域划分是渐进演进的,第一次划分只需要做到“80% 正确”,剩余 20% 在迭代中修正。一个可执行的不完美方案远胜于一个无法落地的完美方案。
2.7 落地步骤
- 识别业务边界——绘制模块依赖图,标记每个模块的“数据主权实体”,排除跨模块共享表。
- 评估变更频率——通过 Git 提交日志、SQLite WAL 文件分析或 APM 工具(如 Firebase Performance)采集每个实体的写操作频次。
- 分析访问模式——使用 Room 的
@Query调用计数 + 线上 Trace 统计读写比例,区分读密集与写密集。 - 构建数据域矩阵——将每个实体填入 2×2 象限,同一个业务模块的实体应尽量聚集在同一个或相邻象限。
- 定义域间同步契约——为每个数据域编写同步接口文档,明确数据提供方、消费方、同步触发条件、一致性等级。
- 评审与调整——组织架构评审,邀请各模块负责人确认边界,根据评审结果微调象限归属。
// 变更频率采样示意(仅用于辅助判断,非正式代码)
// 在 DAO 中增加变更计数日志
@Insert(onConflict = OnConflictStrategy.REPLACE)
fun insert(order: Order)
// 配合 AOP 或 Room 的 @Transaction 记录每次写操作时间戳
// 一周后统计:高频域 > 1000 次/天,中频域 100~1000 次/天,低频域 < 100 次/天
2.8 验收标准
| 验收项 | 验收方法 | 通过标准 |
|---|---|---|
| 业务边界完整性 | 遍历所有 Room Entity,逐一确认所属数据域 | 每个 Entity 有且仅有一个数据域归属 |
| 变更频率分级准确 | 对比一周采样数据与分级标签 | 误差 < 20% 的分级偏差可接受,无跨越两级的分级错误 |
| 访问模式假设验证 | 线上 Trace 统计读写比例 | 读密集域读比例 ≥ 85%,写密集域写比例 ≥ 55% |
| 域间同步契约覆盖率 | 检查每个跨域数据流是否有关联的同步契约文档 | 100% 跨域数据流已定义同步策略 |
| 象限稳定性 | 运行两周后复盘象限归属变化 | 数据域象限变动数 ≤ 2 |
验收时机:建议在功能开发完成后的第一个迭代末尾执行验收,此时团队对数据域的理解已初步统一,修复成本最低。验收不通过时,优先调整“变更频率”和“访问模式”的误判项,不要轻易重划业务边界。