datai/datai-scenes/datai-scene-salesforce/docs/retros/2026-02-06-003-08-retro.md

214 lines
10 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 复盘文档 - 描述和列出元数据
## 元数据
- 需求编号003-08
- 需求名称:描述和列出元数据
- 创建时间2026-02-06
- 创建人AI Assistant
- 状态:已完成
## 复盘概述
本次复盘对"描述和列出元数据"功能的开发过程进行了全面回顾。该功能是 Metadata API 模块的核心功能之一,提供了对 Salesforce Org 中所有元数据类型的描述能力和对指定类型元数据成员的列表查询能力。通过复盘,我们总结了成功经验、识别了改进点、分析了问题,并制定了行动计划,旨在提高后续开发过程的效率和质量。
## 目标与实际产出对比
### 目标
- 实现 Salesforce Metadata API 的 describeMetadata 功能
- 实现 Salesforce Metadata API 的 listMetadata 功能
- 支持分批处理 listMetadata 查询Salesforce API 限制每次最多 3 个查询)
- 实现查询历史记录功能,支持审计和追溯
- 遵循 SSOT 流程,确保所有开发活动都有文档依据
- 生成符合项目规范的代码,包含单元测试
### 实际产出
- ✅ 成功实现了 describeMetadata 功能,获取 Org 支持的所有元数据类型
- ✅ 成功实现了 listMetadata 功能,支持分批处理(自动拆分超过 3 个的查询)
- ✅ 提供了 3 个 REST API 接口(描述元数据、列出元数据、查询历史)
- ✅ 创建了 1 个数据库表datai_metadata_describe包含 3 个索引
- ✅ 生成了 18 个代码文件14 个代码生成器生成 + 4 个手动实现)
- ✅ 定义了 8 个标准错误码,覆盖各种异常场景
- ✅ 严格按照 SSOT 流程执行,完成了阶段 1-8 的所有文档
- ✅ 编写了 12 个单元测试用例,覆盖成功、失败、分批和边界场景
## 成功经验
### 1. 分批处理机制的设计
**经验描述**:针对 Salesforce API 每次 listMetadata 调用最多支持 3 个查询的限制,设计了自动分批处理机制,对用户透明,简化了调用方的使用。
**具体案例**
```java
@Override
@Transactional(rollbackFor = Exception.class)
public ListMetadataResult[] listMetadata(ListMetadataQuery[] queries) {
// 分批处理查询
List<ListMetadataResult> allResults = new ArrayList<>();
for (int i = 0; i < queries.length; i += MAX_QUERIES_PER_CALL) {
// 计算当前批次的结束索引
int end = Math.min(i + MAX_QUERIES_PER_CALL, queries.length);
// 提取当前批次的查询
ListMetadataQuery[] batch = Arrays.copyOfRange(queries, i, end);
// 调用 Salesforce API
ListMetadataResult[] batchResults = connection.listMetadata(batch);
// 合并结果
if (batchResults != null) {
allResults.addAll(Arrays.asList(batchResults));
}
}
return allResults.toArray(new ListMetadataResult[0]);
}
```
**推广建议**:对于有限制的外部 API 调用,应在 Service 层封装分批处理逻辑,对外提供统一的接口,降低调用方的复杂度。
### 2. 代码复用和依赖管理
**经验描述**充分利用了项目中已有的基础设施MetadataConnectionFactory、通用异常类、常量类等减少了重复代码提高了代码的一致性和可维护性。
**具体案例**
- 复用了 `datai-salesforce-auth` 模块的 `MetadataConnectionFactory` 获取连接
- 复用了 `datai-salesforce-common` 模块的 `SalesforceAuthException``SalesforceOperationException`
- 复用了 `datai-salesforce-common` 模块的 `SalesforceConstants` 常量
**推广建议**:在开发新功能前,先梳理项目中已有的基础设施和公共组件,优先复用现有代码,避免重复造轮子。
### 3. 详细的单元测试覆盖
**经验描述**:为 Service 层编写了 12 个单元测试用例覆盖了正常流程、分批流程3 个、4 个、7 个查询)、空查询、参数校验失败、连接异常等各种场景。
**具体案例**
```java
@Test
void testListMetadata_Success_Batch_4Queries() throws ConnectionException {
// 准备测试数据4 个查询)
ListMetadataQuery[] queries = new ListMetadataQuery[4];
// ... 设置查询参数
// 第一批结果3 个)
ListMetadataResult[] mockResults1 = new ListMetadataResult[3];
// ... 设置第一批结果
// 第二批结果1 个)
ListMetadataResult[] mockResults2 = new ListMetadataResult[1];
// ... 设置第二批结果
// 模拟 Salesforce API 调用
when(metadataConnection.listMetadata(batch1)).thenReturn(mockResults1);
when(metadataConnection.listMetadata(batch2)).thenReturn(mockResults2);
// 执行测试
ListMetadataResult[] results = describeService.listMetadata(queries);
// 验证结果
assertNotNull(results);
assertEquals(4, results.length);
// 验证调用了两次 API
verify(metadataConnection, times(1)).listMetadata(batch1);
verify(metadataConnection, times(1)).listMetadata(batch2);
}
```
**推广建议**:对于涉及外部 API 调用的功能,单元测试应重点验证分批逻辑、异常处理和边界条件,使用 Mockito 模拟外部依赖。
## 改进点
### 1. 错误码的语义化可以更强
**改进描述**当前错误码DESCRIBE_001 ~ DESCRIBE_008虽然覆盖了主要场景但部分错误码的语义可以更具体便于问题定位。
**具体建议**
- 将 DESCRIBE_003参数校验失败细化为 DESCRIBE_003A查询列表为空、DESCRIBE_003B元数据类型为空、DESCRIBE_003C无效的操作类型
- 增加 DESCRIBE_009分批处理失败用于记录分批处理过程中的异常
### 2. API 响应格式可以统一
**改进描述**:当前 API 响应直接返回 Salesforce 的原生对象DescribeMetadataResult、ListMetadataResult[]),前端需要了解 Salesforce 的对象结构。
**具体建议**
- 考虑增加 DTO 层,将 Salesforce 原生对象转换为项目内部的标准响应格式
- 统一响应字段命名规范(如使用驼峰命名)
- 增加响应数据的校验和清洗逻辑
### 3. 查询历史的性能优化
**改进描述**:当前查询历史功能直接查询数据库,当数据量增大时可能影响性能。
**具体建议**
- 考虑增加缓存机制(如 Redis缓存近期的查询历史
- 增加分页查询支持,避免一次性返回大量数据
- 增加查询条件的索引,提高查询效率
## 问题分析
### 问题 1分批处理时的部分失败处理
**问题描述**:在 listMetadata 分批处理过程中,如果某一批次失败,当前实现会抛出异常,导致整个操作失败,之前成功的批次结果也会丢失。
**根因分析**
- 分批处理逻辑中没有考虑部分失败的情况
- 事务管理导致一旦失败就回滚所有操作
**解决方案**
- 考虑增加部分失败处理机制,记录失败的批次,返回部分成功的结果
- 或者增加重试机制,对失败的批次进行重试
- 在错误信息中明确指出哪些批次失败
### 问题 2单元测试中的 Mock 设置复杂
**问题描述**:由于 listMetadata 的分批处理逻辑涉及多次 API 调用,单元测试中的 Mock 设置较为复杂,需要为每个批次分别设置 Mock 结果。
**根因分析**
- 分批处理逻辑与 API 调用耦合较紧
- 单元测试需要了解内部分批逻辑才能正确设置 Mock
**解决方案**
- 考虑将分批处理逻辑抽取为独立的工具类或方法,便于单独测试
- 或者使用参数化测试,减少重复代码
## 行动计划
| 序号 | 行动项 | 责任人 | 优先级 | 计划时间 |
|------|--------|--------|--------|----------|
| 1 | 细化错误码,增加更具体的错误分类 | AI Assistant | 中 | 下一个迭代 |
| 2 | 评估增加 DTO 层的必要性,统一 API 响应格式 | 项目团队 | 低 | 后续迭代 |
| 3 | 为查询历史增加分页查询支持 | AI Assistant | 中 | 下一个迭代 |
| 4 | 优化分批处理的部分失败处理机制 | AI Assistant | 高 | 下一个迭代 |
| 5 | 重构单元测试,简化 Mock 设置 | AI Assistant | 中 | 下一个迭代 |
## 提取模式
### 有效的 Prompt 技巧
1. **明确指定分批处理逻辑**:在提示词中明确要求处理外部 API 的限制(如 Salesforce 每次最多 3 个查询),可以确保生成的代码包含正确的分批处理逻辑。
2. **强调代码复用**:在提示词中明确要求复用项目中已有的基础设施(如 MetadataConnectionFactory、通用异常类可以减少重复代码提高代码一致性。
3. **详细的测试场景要求**:在提示词中明确要求覆盖分批处理、空查询、参数校验失败等场景,可以确保生成的单元测试更加全面。
### 避免的坑
1. **不要忽略外部 API 的限制**:在设计和实现涉及外部 API 的功能时,必须充分了解 API 的限制(如调用频率、参数数量等),避免在运行时出现问题。
2. **不要过度依赖代码生成器**代码生成器适合生成基础代码Entity、Mapper、基础 Service但涉及复杂业务逻辑的部分如分批处理、事务管理需要手动实现和仔细测试。
3. **不要忽视部分失败的处理**:在设计分批处理逻辑时,必须考虑部分失败的情况,避免一旦某一批次失败就导致整个操作失败。
## 模板迭代
经过本次复盘,发现当前的提示词模板在以下方面可以改进:
1. **增加外部 API 限制处理的要求**:在提示词模板中增加明确要求处理外部 API 限制的章节,确保生成的代码包含正确的限制处理逻辑。
2. **增加部分失败处理的要求**:在提示词模板中增加明确要求处理部分失败场景的章节,确保生成的代码具有更好的健壮性。
3. **增加性能优化的要求**:在提示词模板中增加明确要求考虑性能优化的章节(如缓存、分页、索引等),确保生成的代码具有良好的性能。
计划在下一个迭代中更新提示词模板,增加上述要求。
## 相关文档
- [需求文档](../requirements/sub/2026-01-28-003-08-描述和列出元数据.md)
- [设计文档](../design/2026-02-03-003-08-描述和列出元数据-设计.md)
- [决策记录](../decisions/2026-02-03-003-08-ADR-描述和列出元数据技术选型.md)
- [变更日志](../changelog/2026-02-06-003-08-changelog.md)
- [API 文档](../api-docs/2026-02-06-003-08-api.md)
- [会话记录](../sessions/2026-02-03-003-08-session.md)