7.7 KiB
7.7 KiB
ADR-002-05: Flow 覆盖率技术选型
状态
已接受
日期
2026-02-03
背景
Flow 覆盖率功能需要选择合适的技术方案,满足以下要求:
- 支持查询和统计 Salesforce Flow 的测试覆盖率数据
- 支持按 Flow 名称、类型、命名空间等多维度查询
- 提供覆盖率统计和聚合分析能力
- 与 002-03(测试执行)功能的数据模型兼容
- 与 002-04(代码覆盖率)功能保持架构一致性
- 确保查询性能和数据一致性
需求约束
- 支持分页查询,避免大数据量查询导致性能问题
- 支持多条件筛选(testResultId、flowName、type、namespace、coverage范围)
- 提供总体覆盖率统计功能
- 提供按类型统计功能
- 支持 Flow 覆盖率警告查询
- 与现有技术栈保持一致
决策
决策 1:数据库表策略
选择方案 1:创建独立的 Flow 覆盖率表
- 创建独立的
datai_apex_flow_coverage表存储 Flow 覆盖率数据 - 创建独立的
datai_apex_flow_coverage_warning表存储 Flow 覆盖率警告 - 不与代码覆盖率表合并
理由:
- 数据模型差异:Flow 覆盖率与代码覆盖率的数据模型不同(Flow 使用 numElements 而不是 numLocations)
- 查询独立性:独立的表结构便于针对 Flow 特性进行查询优化
- 扩展性:未来 Flow 覆盖率可能有特有的字段需求,独立表更易于扩展
- 数据隔离:代码覆盖率和 Flow 覆盖率是不同类型的数据,分开存储更清晰
放弃方案 2(复用代码覆盖率表)的理由:
- Flow 覆盖率和代码覆盖率的字段差异较大(numElements vs numLocations)
- 合并会导致表结构复杂,增加空字段
- 查询时需要额外的类型区分逻辑
- 不利于针对 Flow 特性的查询优化
决策 2:Service 层设计策略
选择方案 1:独立 Service 层
- 创建独立的
IApexFlowCoverageService接口和ApexFlowCoverageServiceImpl实现 - 与
ApexCodeCoverageService分离,职责更清晰
理由:
- 单一职责原则:Flow 覆盖率功能与代码覆盖率功能是不同的业务领域
- 可维护性:独立的 Service 层便于维护和扩展
- 可测试性:独立的 Service 层便于单元测试
- 代码清晰度:避免一个 Service 类过于庞大,职责混乱
放弃方案 2(合并到 ApexCodeCoverageService)的理由:
- 虽然都是覆盖率功能,但数据模型和查询逻辑差异较大
- 合并会导致 Service 类过于庞大,职责不清晰
- 不利于针对 Flow 特性的独立扩展
- 与代码覆盖率功能的设计理念冲突(002-04 也是独立的 Service)
决策 3:查询性能优化策略
选择方案 1:数据库索引 + 分页查询
- 使用数据库索引(test_result_id、name、type、namespace)
- 使用 PageHelper 进行物理分页
- 对覆盖率范围筛选在内存中进行(数据量可控)
理由:
- 查询性能:数据库索引确保查询性能
- 内存友好:物理分页避免加载大量数据到内存
- 灵活性:覆盖率范围筛选在内存中进行,避免复杂的 SQL 条件
- 简单性:实现简单,与 002-04 代码覆盖率功能保持一致
- 一致性:与项目其他功能的查询策略保持一致
放弃方案 2(使用 Redis 缓存)的理由:
- Flow 覆盖率数据相对稳定,但查询条件多样,缓存命中率可能不高
- 增加系统复杂度,需要维护缓存一致性
- 当前数据量下,数据库查询性能已经足够
- 可以后续根据实际性能需求再考虑添加缓存
决策 4:覆盖率计算策略
选择方案 1:元素数量加权平均法
- 总体覆盖率 = Σ(numElementsCovered) / Σ(numElements) × 100%
- 按类型统计时,分别计算每种类型的加权平均覆盖率
理由:
- 准确性:基于元素数量的加权平均能准确反映整体覆盖情况
- 公平性:大 Flow(元素多)对总体覆盖率的影响更大,符合实际情况
- 简单性:计算逻辑简单,易于理解和维护
- 一致性:与 Salesforce 官方覆盖率计算逻辑保持一致
放弃方案 2(简单平均法)的理由:
- 简单平均不考虑 Flow 大小差异,可能导致小 Flow 对总体覆盖率影响过大
- 不能准确反映实际测试覆盖情况
- 与 Salesforce 官方计算逻辑不一致
决策 5:权限控制策略
选择方案 1:独立权限标识
- 使用独立的权限标识
apex:flow-coverage:query - 与代码覆盖率权限分离
理由:
- 细粒度控制:支持对 Flow 覆盖率查询和代码覆盖率查询分别授权
- 安全性:某些用户可能只需要查看代码覆盖率,不需要查看 Flow 覆盖率
- 灵活性:便于后续的权限管理扩展
- 符合规范:与若依的权限管理规范一致
放弃方案 2(复用代码覆盖率权限)的理由:
- 权限粒度太粗,无法满足细粒度控制需求
- 不符合最小权限原则
- 不利于后续的权限管理
决策 6:API 设计策略
选择方案 1:独立的 RESTful API 端点
- 提供独立的
/api/apex/flow-coverage端点 - 与代码覆盖率 API 分离
理由:
- 接口清晰:独立的端点使接口职责更清晰
- 版本控制:便于独立版本控制和演进
- 文档清晰:独立的 API 便于文档化和理解
- 权限控制:独立的端点便于权限控制
放弃方案 2(合并到代码覆盖率 API)的理由:
- 合并会导致接口复杂,需要额外的类型参数
- 不利于接口文档化
- 与代码覆盖率的 API 设计理念冲突
后果
正面影响
- 开发效率高:与 002-04 代码覆盖率功能保持一致的架构,减少设计成本
- 维护成本低:独立的 Service 层和数据库表,职责清晰
- 查询性能好:数据库索引 + 分页查询确保性能
- 权限控制灵活:独立的权限标识支持细粒度控制
- 扩展性好:独立的表结构和 Service 层便于后续扩展
- 架构一致性:与代码覆盖率功能保持一致的架构风格
负面影响
- 表数量增加:需要创建 2 张新表(datai_apex_flow_coverage、datai_apex_flow_coverage_warning)
- 代码量增加:需要创建独立的 Service、Controller、Mapper 等类
- 权限配置增加:需要配置独立的权限标识
替代方案
方案 A:与代码覆盖率功能完全复用
- 描述:复用代码覆盖率的数据库表和 Service 层,通过类型字段区分
- 优点:表数量少,代码量少
- 缺点:数据模型不匹配,查询逻辑复杂,不利于扩展
- 适用场景:数据模型高度相似的功能
方案 B:使用 MongoDB 存储
- 描述:使用 MongoDB 存储 Flow 覆盖率数据
- 优点:Schema 灵活,适合非结构化数据
- 缺点:增加系统复杂度,与现有技术栈不一致
- 适用场景:数据结构变化频繁,需要高度灵活性的场景
方案 C:实时查询 Salesforce API
- 描述:不存储数据到本地数据库,每次查询都调用 Salesforce API
- 优点:无数据同步问题,数据始终最新
- 缺点:查询性能差,依赖 Salesforce API 可用性,无法支持复杂统计
- 适用场景:数据量小,实时性要求高的场景