mcpField
P
platform-apex-generate

platform-apex-generate

github.com/forcedotcom开发1.1k7.2k 次安装1 天前更新
代码仓库

关于 platform-apex-generate

platform-apex-generate 按项目规范及安全、批量处理约束指导 Salesforce Apex 类和触发器的编写与审查,面向 Apex 开发者,并要求报告前运行分析器和测试。

主要功能

  1. 01生成 Apex 类和触发器
  2. 02发现项目编码规范
  3. 03遵循安全与治理限制
  4. 04运行代码分析器验证
  5. 05执行 Apex 测试并报告

适用场景

  1. 01构建新的 Apex 服务或触发器
  2. 02重构或审查 Apex 代码
  3. 03报告前验证生成的代码

MCP 相关

该技能要求对生成或更新的 `.cls` 文件调用 MCP `run_code_analyzer`,并允许通过 MCP 执行 Apex 测试。最终报告须记录工具输出或不可用状态。

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/forcedotcom/sf-skills --skill platform-apex-generate

安装后在 Claude Code 中输入/platform-apex-generate确认已加载。

包含的文件

除 SKILL.md 外,安装时一起下载的参考资料和脚本。

assets/
abstract.cls
batch.cls
domain.cls
dto.cls
exception.cls
interface.cls
invocable.cls
queueable.cls
rest-resource.cls
schedulable.cls
selector.cls
service.cls
trigger.cls
utility.cls
references/
AccountDeduplicationBatch.cls
AccountSelector.cls
AccountService.cls

详细介绍

生成 Apex

将此技能用于生产级 Apex:新建类、选择器、服务、异步作业、可调用方法和触发器;以及基于证据审查现有的 .cls 或 .trigger。

必需输入

编写前收集或推断以下信息:

  • 类类型(服务、选择器、领域、批处理、可排队、可调度、可调用、触发器、触发器操作、DTO、工具类、接口、抽象类、异常、REST 资源)
  • 目标对象和业务目标
  • 类名(根据下方命名表推导)
  • 全新开发还是重构/修复;任何组织/API 限制
  • 部署目标(默认为 runSpecifiedTests,并在适用时使用生成的测试)

除非另有说明,默认设置如下:

  • 共享设置:with sharing(见下文各类型的共享规则)
  • 访问级别:public(仅在托管包或 @RestResource 要求时使用 global)
  • API 版本:66.0(最低版本)
  • ApexDoc 注释:是

如果用户提供了明确、完整的请求,请立即生成,无需不必要的来回沟通。


工作流

所有步骤必须按顺序执行。不得跳过、合并或调整顺序。如果遇到阻碍,请停止并询问缺失的上下文。如果不适用,请在报告中标注 N/A,并用一行说明理由。

阶段 1 — 编写
  1. 了解项目惯例

    • 服务-选择器-领域分层、日志记录工具
    • 现有类/触发器及当前使用的触发器框架或处理程序模式
    • 是否已在使用 Trigger Actions Framework (TAF)
  2. 选择最精简且正确的模式(见下文的类型专属指南)

  3. 查阅模板和资源文件

    • 编写前,从 assets/ 中读取匹配的模板(文件映射见类型专属指南)
    • 如果 references/ 中存在该类型的示例,请阅读并将其用作具体的风格指南
    • 对于任何测试类工作,始终阅读并使用 platform-apex-test-generate 技能
  4. 遵循防护规则编写——应用下方规则部分中的每条规则

    • 生成带有 ApexDoc 的 {ClassName}.cls
    • 生成 {ClassName}.cls-meta.xml
  5. 生成测试类——加载 platform-apex-test-generate 技能,以创建 {ClassName}Test.cls 和 {ClassName}Test.cls-meta.xml。部署始终需要生成 Apex 测试。未加载 platform-apex-test-generate 技能生成测试前,不得创建或编辑任何测试文件。

阶段 2 — 验证(报告前必须完成)

写入文件只是中点,并非终点。步骤 6 和 7 均需要调用工具并产生输出,这些输出必须出现在步骤 8 的报告中。两步都运行并捕获输出前,不得总结或提交报告。

  1. 运行代码分析器

    • 对所有生成/更新的 .cls 文件调用 MCP run_code_analyzer。
    • 修复所有 sev0、sev1 和 sev2 违规;重复运行直至检查通过。
    • 在报告中逐字记录最终工具输出。
    • 后备方案:sf code-analyzer run --target <target>。如果两者均不可用,请在报告中记录 run_code_analyzer=unavailable: <error>。
  2. 执行 Apex 测试

    • 通过 sf apex run test 或 MCP 运行组织测试,包括 {ClassName}Test。
    • 将所有测试生成/修复/覆盖率工作交由 platform-apex-test-generate 处理;反复迭代直至测试通过。
    • 在报告中记录通过/失败数量和覆盖率百分比。
    • 如果不可用,请在报告中记录 test_execution=unavailable: <error>。
阶段 3 — 报告
  1. 报告——使用本文档末尾的输出格式。
    • Analyzer 行必须包含步骤 6 的实际工具输出(如果尝试调用后仍不可用,则写入 run_code_analyzer=unavailable: <reason>)。
    • Testing 行必须包含步骤 7 的实际结果(如果尝试调用后仍不可用,则写入 test_execution=unavailable: <reason>)。
    • 缺少任一行的报告均不完整。记录不可用之前,务必先尝试调用工具。

规则

必须强制执行的硬性约束

如果生成的代码会违反任何约束,请停止并先说明问题:

约束原因
所有 SOQL 查询都必须放在循环之外避免触发查询治理限制(100 次查询)
所有 DML 操作都必须放在循环之外避免触发 DML 治理限制(150 条语句)
每个类都必须声明共享关键字防止意外采用 without sharing 默认设置并导致数据泄露
使用自定义元数据/标签/describe 调用,而不是硬编码 ID确保可在不同组织间移植
始终处理异常(记录、重新抛出或恢复)防止静默失败
所有包含用户输入的动态 SOQL 都使用绑定变量防止 SOQL 注入
使用 Apex 原生集合(List、Map、Set),而不是 Java 类型防止编译错误
使用方法前先确认该方法在 Apex 中存在防止依赖不存在的 API
避免在主代码路径中使用 `System.debug()``调试语句即使在未启用日志时也会执行并消耗 CPU。如果主代码路径确实需要日志记录,请使用日志框架
绝不使用 @future 方法使用 Queueable 和 System.Finalizer;@future 无法链式调用、无法从 Batch 调用,也不能接受非原始类型
批量化与治理限制
  • 所有公共 API 都应接受并处理集合;单记录重载应委托给批量方法
  • 在批处理/批量流程中,优先使用部分成功 DML(Database.update(records, false)),并处理 SaveResult 中的错误
  • 使用 Map<Id, SObject> 构造函数,从查询结果中高效地按 ID 查找
  • 使用 Map<Id, List<SObject>> 按父记录对相关子记录分组;在处理前通过单次循环构建映射
  • 使用 Set<Id> 进行去重和成员检查;优先使用 Set.contains(),而不是 List.contains()
  • 同时需要父记录和子记录时,使用关系子查询,通过一条 SOQL 获取两者
  • 使用带有 GROUP BY 的 AggregateResult 进行汇总计算,而不是在 Apex 中查询并计数
  • 仅对实际发生变化的记录执行 DML——将记录添加到更新列表前,先与 Trigger.oldMap 或先前状态进行比较
  • 在复杂事务中使用 Limits.getQueries()、Limits.getDmlStatements()、Limits.getCpuTime() 监控资源消耗
SOQL 优化
  • 使用带有适当 WHERE 子句的选择性查询;过滤条件中尽可能使用索引字段(Id、Name、OwnerId、查找/主从关系字段、ExternalId 字段、自定义索引)
  • SOQL 中不存在 SELECT *——始终明确指定所需字段
  • 使用 LIMIT 子句限制结果集;使用 ORDER BY 确保结果具有确定性
  • 查询自定义元数据类型(对象名称以 __mdt 结尾)时,切勿使用 SOQL——请使用内置方法({CustomMdt__mdt}.getAll().values()、getInstance() 等)
  • API 版本为 67.0 及以上的类中,如果使用 without sharing 关键字,且运行用户没有相应的字段级或对象级安全权限,查询将会抛出异常。如果要升级 API 版本,请确保查询受到适当保护,并相应更新测试。默认情况下,只允许在有明确理由的查询中使用 SYSTEM_MODE 变体。
缓存
  • 对于频繁访问且很少更改的数据,使用 Platform Cache(Cache.Org/Cache.Session);设置 TTL,并始终处理缓存未命中——缓存可能随时被逐出
  • 使用 private static Map 字段作为事务级缓存,以避免在同一执行上下文中重复查询;首次访问时再进行惰性初始化
安全性
  • 默认使用 with sharing;对于 without sharing 或 inherited sharing,应记录理由
  • 在 SOQL 中使用 WITH USER_MODE,在 Database DML 中使用 AccessLevel.USER_MODE,以强制执行 CRUD/FLS——对于 API 版本为 67.0 或更高的所有 Apex 类,这些都是默认设置
  • 通过允许列表或 Schema.describe 验证动态字段名和运算符名
  • 所有外部凭据/API 密钥均使用 Named Credentials
  • 对面向用户的 @AuraEnabled 错误使用 AuraHandledException(不包含内部详细信息)
  • 使用 without sharing 时,必须检查 Custom Permission
  • 将 without sharing 逻辑隔离在专用辅助类中;从 with sharing 入口调用,以限制提升访问权限的范围
  • 通过 Platform Encryption 加密静态存储的 PII/敏感数据;绝不在调试语句、错误消息或 API 响应中暴露 PII
安全验证

完成前,请验证:已强制执行 CRUD/FLS(SOQL + DML)· 每个类都显式指定了 sharing 关键字 · 没有硬编码的机密或记录 ID · 日志和错误消息中不包含 PII · 面向最终用户的错误消息已清理。

错误处理
  • 先捕获特定异常,再捕获通用 Exception;在消息中包含上下文
  • 仅在可能抛出异常的代码(DML、调用、JSON 解析、类型转换)周围使用 try/catch;避免对简单赋值、集合操作或算术运算进行防御性包装
  • 保留异常原因链:new CustomException('message', cause)(不要用拼接的消息替代堆栈跟踪)
  • 在有意义时,为每个服务域提供自定义异常类
  • 在 @AuraEnabled 方法中,捕获异常并重新抛出为 AuraHandledException
  • 后备方案:如果没有有意义的领域异常,则捕获通用 Exception,并选择重新抛出,或将其包装在能保留原始原因的最简自定义异常中。
空值安全
  • 在每个公共方法开头添加空值/空输入保护子句;根据上下文选择合适的方式:在私有方法/触发器处理程序中提前 return,在公共 API 中抛出异常,在验证服务中使用 record.addError()
  • 返回空集合,而不是 null
  • 对链式属性访问使用安全导航(?.)
  • 除非能保证存在,否则绝不直接解引用 map.get(key);应先使用 containsKey、赋值后检查空值,或使用安全导航
  • 使用空值合并运算符(??)提供默认值
  • 优先使用 String.isBlank(value),而不是 value == null || value.trim().isEmpty() 之类的手动检查
常量与字面量
  • 尽可能使用枚举而非字符串常量;枚举值遵循 UPPER_SNAKE_CASE
  • 将重复出现的字符串/数字字面量提取为 private static final 常量,或放入常量类
  • 面向用户的字符串使用 Label. 自定义标签
  • 对可配置值(阈值、映射、功能标志)使用 Custom Metadata
  • 代码中绝不输出 HTML 转义实体(例如 &#39;);在 Apex 字符串字面量中使用单引号 '
命名约定
类型模式示例
服务{SObject}ServiceAccountService
选择器{SObject}SelectorAccountSelector
领域{SObject}DomainOpportunityDomain
批处理{Descriptive}BatchAccountDeduplicationBatch
队列任务{Descriptive}QueueableExternalSyncQueueable
可调度任务{Descriptive}SchedulableDailyCleanupSchedulable
DTO{Descriptive}DTOAccountMergeRequestDTO
包装器{Descriptive}WrapperOpportunityLineWrapper
工具类{Descriptive}UtilStringUtil
接口I{Descriptive}INotificationService
抽象类Abstract{Descriptive}AbstractIntegrationService
异常{Descriptive}ExceptionAccountServiceException
REST 资源{SObject}RestResourceAccountRestResource
触发器{SObject}TriggerAccountTrigger
触发器操作TA_{SObject}_{Action}TA_Account_SetDefaults

其他命名规则:

  • 类:PascalCase
  • 方法:camelCase,以动词开头(get、create、process、validate、is、has、can)
  • 变量:camelCase,使用描述性名词;列表使用复数名词(例如,accounts、relatedContacts);映射使用 {value}By{key}(例如,accountsById);集合使用 {noun}Ids
  • 常量:UPPER_SNAKE_CASE
  • 使用完整且具有描述性的名称,而不是缩写(acc、tks、rec)
ApexDoc
  • 类头以及每个 public/global 方法都必须添加
  • 包括:简要说明、@param、@return、@throws,以及适用时的 @example

类级格式:

/**
 * Provides services for geolocation and address conversion.
 */
public with sharing class GeolocationService { }

方法级格式:

/**
 * @param paramName Description of the parameter
 * @return Description of the return value
 * @example
 * List<Account> results = AccountService.deduplicateAccounts(accountIds);
 */
代码结构与架构
  • 每个类只承担单一职责;最多 500 行——超出时拆分
  • 尽早返回:在方法开头验证前置条件,并立即返回或抛出异常
  • 对超过约 40 行的方法提取私有辅助方法
  • 使用依赖注入(构造函数/方法参数)以便测试
  • 优先采用组合和精简接口,而非深层继承;通过新增实现进行扩展,而不是修改现有实现
  • 跨层时,方法只允许包含单层抽象:
层负责内容不得包含
触发器仅事件路由业务逻辑、编排
处理器/服务流程控制、协调内联 SOQL/DML/HTTP/解析
领域业务规则、验证查询、调用外部服务、持久化细节
数据/集成SOQL、DML、HTTP业务决策
  • 禁止:将编排与内联 SOQL/DML/HTTP 混合的方法;将业务规则与解析内部逻辑混合;在一个方法中同时包含验证、持久化和跨系统连接逻辑

异步决策矩阵

场景默认选项主要特征
标准异步工作Queueable作业 ID、链式调用、非原始类型、可配置延迟(通过 AsyncOptions,最长 10 min)、去重签名
超大型数据集Batch Apex分块处理,最多 5 个并发作业;大范围处理时使用 QueryLocator
现代批处理替代方案CursorStep(Database.Cursor)每块处理 2000 条记录,吞吐量更高,没有 5 个作业的限制
定期计划任务Scheduled Flow(首选)或 SchedulableSchedulable 的作业数上限为 100;仅在需要链接到 Batch 或需要复杂 Apex 逻辑时使用
作业后清理Finalizer(System.Finalizer)无论 Queueable 成功还是失败都会运行
长时间运行的调用Continuation每个事务最多 3 个,并行运行 3 个
延迟超过 10 分钟System.scheduleBatch()在指定的未来时间安排 Batch 作业
传统即发即弃任务@future不要在新代码中使用——请参阅硬性约束;改用 Queueable + Finalizer

特定类型指南

服务
  • 模板:assets/service.cls · 参考:references/AccountService.cls
  • 使用 with sharing;保持无状态——不设 public 字段或可变实例状态;让公共 API 专注于特定用途,并在适当时使用 static
  • 将所有 SOQL 操作委托给 Selectors,将 SObject 行为委托给 Domains
  • 使用自定义异常包装业务错误(例如,AccountServiceException)
Selector
  • 模板:assets/selector.cls · 参考:references/AccountSelector.cls
  • 使用 inherited sharing;每个 SObject 或查询域对应一个 Selector
  • 返回 List<SObject> 或 Map<Id, SObject>;使用共享的基础字段列表常量(不要在内联代码中重复定义)
  • 接受筛选参数;始终包含 WITH USER_MODE
Domain
  • 模板:assets/domain.cls
  • 使用 with sharing;封装字段默认值、派生值和验证逻辑
  • 仅处理内存中的列表;不执行 SOQL/DML(这些操作应放在 Services/Selectors 中)
Batch
  • 模板:assets/batch.cls · 参考:references/AccountDeduplicationBatch.cls
  • 使用 with sharing;实现 Database.Batchable<SObject>(需要跨分块跟踪时,添加 Database.Stateful)
  • start() = 查询定义;execute() = 业务逻辑;finish() = 日志记录/通知
  • 对大型数据集使用 QueryLocator;通过 Database.SaveResult 处理部分失败
  • 通过构造函数接受筛选参数,以便复用
Queueable
  • 模板:assets/queueable.cls
  • 使用 with sharing;实现 Queueable;需要 HTTP callout 时可选实现 Database.AllowsCallouts
  • 通过构造函数接收数据
  • 添加链深度保护,防止无限链式调用
  • 可选实现 Finalizer,用于恢复/清理
  • 使用 AsyncOptions 配置延迟时间(最长 10 min)和去重签名
Schedulable
  • 模板:assets/schedulable.cls
  • 使用 with sharing;execute() 将任务委托给 Queueable 或 Batch
  • 提供 CRON 常量和便捷的 scheduleDaily() 辅助方法
DTO / Wrapper
  • 模板:assets/dto.cls
  • 无需 sharing 关键字(纯数据容器)
  • 使用简单的公共属性;提供无参和带参构造函数;需要排序时实现 Comparable
  • 对参与序列化/反序列化的私有/受保护内部 DTO 使用 @JsonAccess
Utility
  • 模板:assets/utility.cls
  • 无需 sharing 关键字;所有方法均为 public static;使用 private 构造函数
  • 保持纯函数特性,无副作用;不执行 SOQL/DML
Interface
  • 模板:assets/interface.cls
  • 定义清晰的契约,并为每个方法签名编写 ApexDoc
Abstract
  • 模板:assets/abstract.cls
  • 使用 with sharing;通过 virtual 方法提供默认行为
  • 将扩展点标记为 protected virtual 或 protected abstract
  • 在 ApexDoc 中提供一个展示如何扩展此类的具体示例
Custom Exception
  • 模板:assets/exception.cls
  • 无需 sharing 关键字;使用描述性名称扩展 Exception
  • 支持的构造函数:(), ('msg'), (cause), ('msg', cause)
Trigger
  • 模板:assets/trigger.cls
  • 每个对象使用一个触发器;将所有逻辑委托给 handler/TAF action 类
  • 包含所有相关 DML 上下文;使用 TAF 时:new MetadataTriggerHandler().run();
Trigger Action (TAF)
  • 每种关注点和上下文各使用一个类;实现 TriggerAction.{Context}
  • 通过 Trigger_Action__mdt 注册(未注册的 action 均处于非激活状态)
  • 命名格式:TA_{SObject}_{ActionName};递归控制优先使用字段值比较,而非静态布尔值
可调用方法(@InvocableMethod)
  • 模板:assets/invocable.cls
  • 使用 with sharing;内部 Request/Response 类带有 @InvocableVariable
  • 方法必须是 public static;非静态方法或仅接受单个对象的签名无法编译
  • 接受 List<Request>,返回 List<Response>;确保批量化(将 SOQL/DML 放在循环外)
  • 装饰器参数:label(必需——Flow Builder 中显示的名称)、description、category(在 Builder 中对操作分组)、callout=true(方法执行 HTTP 调用时必需)
  • @InvocableVariable 参数:label(必需)、description、required=true/false
  • @InvocableVariable 支持:基本类型、Id、SObject、仅限 List<T>(不支持 Map/Set/Blob);Flow 集合输入/输出请使用 List<Id> 或 List<SObject> 字段
  • 始终在 Response 中包含 isSuccess、errorMessage 和 errorType(e.getTypeName())
  • 在 Response 中返回错误(推荐);抛出异常会触发 Flow Fault 路径,因此仅在无法恢复的故障时使用
REST 资源(@RestResource)
  • 模板:assets/rest-resource.cls
  • 使用 global with sharing;类和方法都必须是 global
  • 使用版本化 URL:@RestResource(urlMapping='/{resource}/v1/*')
  • 根据分支使用适当的 HTTP 状态码(200/201/400/404/422/500);切勿将所有错误都默认为 500
  • 验证输入(Id 格式:Pattern.matches('[a-zA-Z0-9]{15,18}', value));在 SOQL 中绑定所有用户输入
  • 查询中包含 LIMIT/ORDER BY;实现分页(pageSize/offset)
  • 使用标准化的 ApiResponse 包装器(success、message、data/records);使用内部请求/响应 DTO
  • 控制器保持精简:将业务逻辑委托给 Service 类
@AuraEnabled 控制器
  • 使用 with sharing;所有 SOQL 都使用 WITH USER_MODE
  • 仅对只读查询使用 @AuraEnabled(cacheable=true);执行 DML 操作时不设置 cacheable
  • 捕获异常,并使用面向用户的友好消息重新抛出为 AuraHandledException

输出要求

每个类的交付物:

  • {ClassName}.cls
  • {ClassName}.cls-meta.xml(除非另有说明,默认 API 版本为 66.0 或更高)
  • {ClassName}Test.cls(通过 platform-apex-test-generate 技能生成)
  • {ClassName}Test.cls-meta.xml(通过 platform-apex-test-generate 技能生成)

每个触发器的交付物:

  • {TriggerName}.trigger
  • {TriggerName}.trigger-meta.xml(除非另有说明,默认 API 版本为 66.0 或更高)

元数据 XML 模板:

<?xml version="1.0" encoding="UTF-8"?>
<ApexClass xmlns="http://soap.sforce.com/2006/04/metadata">
    <apiVersion>{API_VERSION}</apiVersion>
    <status>Active</status>
</ApexClass>

按以下顺序报告:

Apex work: <summary>
Files: <paths>
Design: <pattern / framework choices>
Workflow: all steps completed (1-8); any N/A justified
Risks: <security, bulkification, async, dependency notes>
Analyzer: <REQUIRED -- paste actual run_code_analyzer output or state "run_code_analyzer=unavailable: <reason>">
Testing: <REQUIRED -- paste actual test execution results (pass/fail, coverage) or state "test_execution=unavailable: <reason>">
Deploy: <dry-run or next step>

跨技能集成

需求委托给
Apex 测试/修复失败platform-apex-test-generate 技能
描述对象/字段元数据技能(如果可用)
部署到组织部署技能(如果可用)
Flow 调用 ApexFlow 技能(如果可用)
LWC 调用 ApexLWC 技能(如果可用)

故障排查范围

此技能仅处理生产环境中的 .cls/.trigger/.apex 问题:编译/解析失败、部署依赖错误、运行时 governor limit 故障。对于测试执行、断言、覆盖率或 sf apex run test 失败,请委托给 platform-apex-test-generate。

评论

支持 Markdown