salesforce-apex-quality
Salesforce開発におけるApexコードの品質管理を担うスキルです。ループ内でのSOQL/DML実行禁止などのガバナー制限対策、共有モデルの適用、CRUD/FLSセキュリティ、SOQLインジェクション防止、陽性・陰性・バルクを網羅したPNBテストカバレッジ、そして最新のApexイディオムを強制します。Apexクラス、トリガーハンドラー、バッチジョブ、テストクラスのレビューや生成時に使用することで、デプロイ前にガバナー制限リスク・セキュリティの脆弱性・品質上の問題を検出できます。
description の原文を見る
Apex code quality guardrails for Salesforce development. Enforces bulk-safety rules (no SOQL/DML in loops), sharing model requirements, CRUD/FLS security, SOQL injection prevention, PNB test coverage (Positive / Negative / Bulk), and modern Apex idioms. Use this skill when reviewing or generating Apex classes, trigger handlers, batch jobs, or test classes to catch governor limit risks, security gaps, and quality issues before deployment.
SKILL.md 本文
Salesforce Apex Quality Guardrails
記述または確認するすべての Apex クラス、トリガー、およびテストファイルにこれらのチェックを適用します。
Step 1 — Governor Limit Safety Check
Apex ファイルを許容可能と宣言する前に、以下のパターンをスキャンしてください。
SOQL と DML のループ内使用 — 自動不可
// ❌ NEVER — causes LimitException at scale
for (Account a : accounts) {
List<Contact> contacts = [SELECT Id FROM Contact WHERE AccountId = :a.Id]; // SOQL in loop
update a; // DML in loop
}
// ✅ ALWAYS — collect, then query/update once
Set<Id> accountIds = new Map<Id, Account>(accounts).keySet();
Map<Id, List<Contact>> contactsByAccount = new Map<Id, List<Contact>>();
for (Contact c : [SELECT Id, AccountId FROM Contact WHERE AccountId IN :accountIds]) {
if (!contactsByAccount.containsKey(c.AccountId)) {
contactsByAccount.put(c.AccountId, new List<Contact>());
}
contactsByAccount.get(c.AccountId).add(c);
}
update accounts; // DML once, outside the loop
ルール: [SELECT または Database.query、insert、update、delete、upsert、merge が for ループ本体内に見つかった場合は、処理を進める前にリファクタリングしてください。
Step 2 — Sharing Model Verification
すべてのクラスは、その sharing intent を明示的に宣言する必要があります。宣言されていない sharing は呼び出し元から継承されます。これは予測不可能な動作につながります。
| 宣言 | 使用時期 |
|---|---|
public with sharing class Foo | すべてのサービス、ハンドラー、セレクター、およびコントローラークラスのデフォルト |
public without sharing class Foo | クラスが昇格された権限で実行される必要がある場合のみ(例: システムレベルのロギング、トリガーのバイパス)。理由を説明するコードコメントが必須 |
public inherited sharing class Foo | 呼び出し元の sharing コンテキストを尊重すべきフレームワークのエントリーポイント |
クラスがこれら 3 つのいずれかの宣言を持たない場合は、他の処理を進める前に追加してください。
Step 3 — CRUD / FLS Enforcement
ユーザーに代わってレコードを読み取りまたは書き込む Apex コードは、オブジェクトおよびフィールドアクセスを検証する必要があります。プラットフォームは Apex で FLS または CRUD を自動的には適用しません。
// Check before querying a field
if (!Schema.sObjectType.Contact.fields.Email.isAccessible()) {
throw new System.NoAccessException();
}
// Or use WITH USER_MODE in SOQL (API 56.0+)
List<Contact> contacts = [SELECT Id, Email FROM Contact WHERE AccountId = :accId WITH USER_MODE];
// Or use Database.query with AccessLevel
List<Contact> contacts = Database.query('SELECT Id, Email FROM Contact', AccessLevel.USER_MODE);
ルール: UI コンポーネント、REST エンドポイント、または @InvocableMethod から呼び出し可能な Apex メソッドは、必ず CRUD/FLS を適用する必要があります。信頼されたコンテキストからのみ呼び出される内部サービスメソッドは、with sharing を代わりに使用できます。
Step 4 — SOQL Injection Prevention
// ❌ NEVER — concatenates user input into SOQL string
String soql = 'SELECT Id FROM Account WHERE Name = \'' + userInput + '\'';
// ✅ ALWAYS — bind variable
String soql = [SELECT Id FROM Account WHERE Name = :userInput];
// ✅ For dynamic SOQL with user-controlled field names — validate against a whitelist
Set<String> allowedFields = new Set<String>{'Name', 'Industry', 'AnnualRevenue'};
if (!allowedFields.contains(userInput)) {
throw new IllegalArgumentException('Field not permitted: ' + userInput);
}
Step 5 — Modern Apex Idioms
現在の言語機能(API 62.0 / Winter '25 以降)を優先的に使用します:
| 古いパターン | 最新の置き換え |
|---|---|
if (obj != null) { x = obj.Field__c; } | x = obj?.Field__c; |
x = (y != null) ? y : defaultVal; | x = y ?? defaultVal; |
System.assertEquals(expected, actual) | Assert.areEqual(expected, actual) |
System.assert(condition) | Assert.isTrue(condition) |
[SELECT ... WHERE ...] with no sharing context | [SELECT ... WHERE ... WITH USER_MODE] |
Step 6 — PNB Test Coverage Checklist
すべての機能は 3 つのパス全体でテストする必要があります。いずれか 1 つが不足している場合は品質不良です:
Positive Path
- 期待された入力 → 期待された出力。
- 例外がスローされたことだけではなく、正確なフィールド値、レコード数、または戻り値をアサート してください。
Negative Path
- 無効な入力、null 値、空のコレクション、およびエラー条件。
- 例外が正しい型とメッセージでスロー されることをアサートしてください。
- 操作がクリーンに失敗するべきときに、レコードが変更されなかったことをアサートしてください。
Bulk Path
- 1 つのテストトランザクションで 200–251 レコードを insert/update/delete してください。
- すべてのレコードが正しく処理されたことをアサートしてください。governor limit による部分的な失敗はありません。
- 非同期作業の governor limit カウンターを分離するために
Test.startTest()/Test.stopTest()を使用してください。
Test Class Rules
@isTest(SeeAllData=false) // Required — no exceptions without a documented reason
private class AccountServiceTest {
@TestSetup
static void makeData() {
// Create all test data here — use a factory if one exists in the project
}
@isTest
static void givenValidInput_whenProcessAccounts_thenFieldsUpdated() {
// Positive path
List<Account> accounts = [SELECT Id FROM Account LIMIT 10];
Test.startTest();
AccountService.processAccounts(accounts);
Test.stopTest();
// Assert meaningful outcomes — not just no exception
List<Account> updated = [SELECT Status__c FROM Account WHERE Id IN :accounts];
Assert.areEqual('Processed', updated[0].Status__c, 'Status should be Processed');
}
}
Step 7 — Trigger Architecture Checklist
- オブジェクトごとに 1 つのトリガー。2 番目のトリガーが存在する場合は、ハンドラーに統合してください。
- トリガー本体には、コンテキストチェック、ハンドラー呼び出し、およびルーティングロジックのみが含まれます。
- ビジネスロジック、SOQL、または DML がトリガー本体に直接含まれていません。
- トリガーフレームワーク(Trigger Actions Framework、ff-apex-common、カスタムベースクラス)が既に使用中の場合は、それを拡張してください。並行パターンを作成しないでください。
- ハンドラークラスは
with sharingです。トリガーが昇格されたアクセスを必要としない限り。
Quick Reference — Hardcoded Anti-Patterns Summary
| パターン | アクション |
|---|---|
for ループ内の SOQL | リファクタリング: ループの前にクエリ、コレクションで操作 |
for ループ内の DML | リファクタリング: 変更を収集、ループ後に DML を 1 度 |
| sharing 宣言がないクラス | with sharing を追加(または without sharing の理由を記載) |
ユーザーデータの escape="false"(VF) | 削除 — 自動エスケープが XSS 防止を適用 |
空の catch ブロック | ロギングを追加し、適切に再スロー またはエラーハンドリング |
| ユーザー入力との文字列連結 SOQL | バインド変数またはホワイトリスト検証で置き換え |
| アサートなしのテスト | 有意な Assert.* 呼び出しを追加 |
System.assert / System.assertEquals スタイル | Assert.isTrue / Assert.areEqual にアップグレード |
ハードコーディングされたレコード ID ('001...') | クエリされたまたは挿入されたテストレコード ID で置き換え |
ライセンス: MIT(寛容ライセンスのため全文を引用しています) · 原本リポジトリ
詳細情報
- 作者
- github
- ライセンス
- MIT
- 最終更新
- 不明
Source: https://github.com/github/awesome-copilot / ライセンス: MIT
関連スキル
agent-browser
AI エージェント向けのブラウザ自動化 CLI です。ウェブサイトとの対話が必要な場合に使用します。ページ遷移、フォーム入力、ボタンクリック、スクリーンショット取得、データ抽出、ウェブアプリのテスト、ブラウザ操作の自動化など、あらゆるブラウザタスクに対応できます。「ウェブサイトを開く」「フォームに記入する」「ボタンをクリックする」「スクリーンショットを取得する」「ページからデータを抽出する」「このウェブアプリをテストする」「サイトにログインする」「ブラウザ操作を自動化する」といった要求や、プログラマティックなウェブ操作が必要なタスクで起動します。
anyskill
AnySkill — あなたのプライベート・スキルクラウド。GitHubを基盤としたリポジトリからエージェントスキルを管理、同期、動的にロードできます。自然言語でクラウドスキルを検索し、オンデマンドでプロンプトを自動ロード、カスタムスキルのアップロードと共有、スキルバンドルの一括インストールが可能です。OpenClaw、Antigravity、Claude Code、Cursorに対応しています。
engram
AIエージェント向けの永続的なメモリシステムです。バグ修正、意思決定、発見、設定変更の後はmem_saveを使用してください。ユーザーが「覚えている」「記憶している」と言及した場合、または以前のセッションと重複する作業を開始する際はmem_searchを使用します。セッション終了前にmem_session_summaryを使用して、コンテキストを保持してください。
skyvern
AI駆動のブラウザ自動化により、任意のウェブサイトを自動化できます。フォーム入力、データ抽出、ファイルダウンロード、ログイン、複数ステップのワークフロー実行など、ユーザーがウェブサイトと連携する必要があるときに使用します。Skyvernは、LLMとコンピュータビジョンを活用して、未知のサイトも自動操作可能です。Python SDK、TypeScript SDK、REST API、MCPサーバー、またはCLIを通じて統合できます。
pinchbench
PinchBenchベンチマークを実行して、OpenClawエージェントの実世界タスクにおけるパフォーマンスを評価できます。モデルの機能テスト、モデル間の比較、ベンチマーク結果のリーダーボード提出、またはOpenClawのセットアップがカレンダー、メール、リサーチ、コーディング、複数ステップのワークフローにどの程度対応しているかを確認する際に使用します。
openui
OpenUIとOpenUI Langを使用してジェネレーティブUIアプリを構築できます。これらはLLM生成インターフェースのためのトークン効率的なオープン標準です。OpenUI、@openuidev、ジェネレーティブUI、LLMからのストリーミングUI、AI向けコンポーネントライブラリ、またはjson-render/A2UIの置き換えについて述べる際に使用します。スキャフォルディング、defineComponent、システムプロンプト、Renderer、およびOpenUI Lang出力のデバッグに対応しています。