salesforce-developer について
salesforce-developerは、Salesforceソリューションの構築とデプロイを支援する開発スキルです。Apex、Lightning Web Components、SOQL、連携、ガバナ制限を踏まえた設計、テスト、Salesforce DXのワークフローを扱います。
主な機能
- 01Apexクラス、トリガー、非同期処理パターン
- 02Lightning Web Componentsの開発
- 03SOQLとSOSLのクエリ実践
- 04一括処理とガバナ制限の確認
- 05テストクラスと一括処理テスト
- 06Salesforce DXとメタデータのデプロイ
活用シーン
- 01Apexトリガーとバッチ処理の構築
- 02Lightning Web Componentsの作成
- 03プラットフォーム制限内でのデータクエリ最適化
- 04Salesforceメタデータのテストとデプロイ
インストール
コマンドをコピーしてターミナルで実行します。
$
npx skills add https:/ / github.com/ jeffallan/ claude-skills --skill salesforce-developerインストール後、Claude Code で/salesforce-developerを入力して読み込まれたか確認します。
同梱ファイル
SKILL.md と一緒にインストールされる参考資料やスクリプト。
references/apex-development.mddeployment-devops.mdintegration-patterns.mdlightning-web-components.mdsoql-sosl.md詳細
Salesforce Developer
コアワークフロー
- 要件を分析する - ビジネスニーズ、データモデル、ガバナー制限、スケーラビリティを把握します
- ソリューションを設計する - 宣言型とプログラム型のどちらを使うか選択し、一括処理を計画して、インテグレーションを設計します
- 実装する - ベストプラクティスに沿って、Apex クラス、LWC コンポーネント、SOQL クエリを作成します
- ガバナー制限を検証する - 次に進む前に、SOQL/DML の回数、ヒープサイズ、CPU 時間がプラットフォームの制限内に収まっていることを確認します
- 十分にテストする - 90% 以上のカバレッジを持つテストクラスを作成し、一括処理シナリオ(200 レコードのバッチ)をテストします
- デプロイする - Salesforce DX、スクラッチ組織、CI/CD を使用してメタデータをデプロイします
リファレンスガイド
状況に応じて詳細なガイダンスを読み込みます。
| トピック | リファレンス | 読み込むタイミング |
|---|---|---|
| Apex 開発 | references/apex-development.md | クラス、トリガー、非同期パターン、バッチ処理 |
| Lightning Web Components | references/lightning-web-components.md | LWC フレームワーク、コンポーネント設計、イベント、wire サービス |
| SOQL/SOSL | references/soql-sosl.md | クエリの最適化、リレーションシップ、ガバナー制限 |
| インテグレーションパターン | references/integration-patterns.md | REST/SOAP API、プラットフォームイベント、外部サービス |
| デプロイと DevOps | references/deployment-devops.md | Salesforce DX、CI/CD、スクラッチ組織、メタデータ API |
制約
必ず行うこと
- Apex コードを一括処理に対応させます — ループの前に ID/レコードを収集し、ループの外でクエリ/DML を実行します
- 一括処理シナリオを含め、最低 90% のコードカバレッジを持つテストクラスを作成します
- インデックス付きフィールドを使用した選択性の高い SOQL クエリを使い、リレーションシップクエリを活用します
- 長時間かかる処理には適切な非同期処理(バッチ、キューアブル、future)を使用します
- 適切なエラー処理とログ記録を実装します。部分的な成功には
Database.update(scope, false)を使用します - ソース駆動型の開発とメタデータのデプロイには Salesforce DX を使用します
必ず避けること
- ループ内で SOQL/DML を実行します(ガバナー制限違反 — 以下の一括処理対応トリガーパターンを参照)
- コード内に ID や認証情報をハードコードします
- 保護策なしに再帰的なトリガーを作成します
- 項目レベルのセキュリティと共有ルールのチェックを省略します
- 非推奨の Salesforce API やコンポーネントを使用します
コードパターン
一括処理対応トリガー(正しいパターン)
// CORRECT: collect IDs, query once outside the loop
trigger AccountTrigger on Account (before insert, before update) {
AccountTriggerHandler.handleBeforeInsert(Trigger.new);
}
public class AccountTriggerHandler {
public static void handleBeforeInsert(List<Account> newAccounts) {
Set<Id> parentIds = new Set<Id>();
for (Account acc : newAccounts) {
if (acc.ParentId != null) parentIds.add(acc.ParentId);
}
Map<Id, Account> parentMap = new Map<Id, Account>(
[SELECT Id, Name FROM Account WHERE Id IN :parentIds]
);
for (Account acc : newAccounts) {
if (acc.ParentId != null && parentMap.containsKey(acc.ParentId)) {
acc.Description = 'Child of: ' + parentMap.get(acc.ParentId).Name;
}
}
}
}
// INCORRECT: SOQL inside loop — governor limit violation
trigger AccountTrigger on Account (before insert) {
for (Account acc : Trigger.new) {
Account parent = [SELECT Id, Name FROM Account WHERE Id = :acc.ParentId]; // BAD
acc.Description = 'Child of: ' + parent.Name;
}
}
Batch Apex
public class ContactBatchUpdate implements Database.Batchable<SObject> {
public Database.QueryLocator start(Database.BatchableContext bc) {
return Database.getQueryLocator([SELECT Id, Email FROM Contact WHERE Email = null]);
}
public void execute(Database.BatchableContext bc, List<Contact> scope) {
for (Contact c : scope) {
c.Email = '[email protected]';
}
Database.update(scope, false); // partial success allowed
}
public void finish(Database.BatchableContext bc) {
// Send notification or chain next batch
}
}
// Execute: Database.executeBatch(new ContactBatchUpdate(), 200);
テストクラス
@IsTest
private class AccountTriggerHandlerTest {
@TestSetup
static void makeData() {
Account parent = new Account(Name = 'Parent Co');
insert parent;
Account child = new Account(Name = 'Child Co', ParentId = parent.Id);
insert child;
}
@IsTest
static void testBulkInsert() {
Account parent = [SELECT Id FROM Account WHERE Name = 'Parent Co' LIMIT 1];
List<Account> children = new List<Account>();
for (Integer i = 0; i < 200; i++) {
children.add(new Account(Name = 'Child ' + i, ParentId = parent.Id));
}
Test.startTest();
insert children;
Test.stopTest();
List<Account> updated = [SELECT Description FROM Account WHERE ParentId = :parent.Id];
System.assert(!updated.isEmpty(), 'Children should have descriptions set');
System.assert(updated[0].Description.startsWith('Child of:'), 'Description format mismatch');
}
}
SOQL のベストプラクティス
// Selective query — use indexed fields in WHERE clause
List<Opportunity> opps = [
SELECT Id, Name, Amount, StageName
FROM Opportunity
WHERE AccountId IN :accountIds // indexed field
AND CloseDate >= :Date.today() // indexed field
ORDER BY CloseDate ASC
LIMIT 200
];
// Relationship query to avoid extra round-trips
List<Account> accounts = [
SELECT Id, Name,
(SELECT Id, LastName, Email FROM Contacts WHERE Email != null)
FROM Account
WHERE Id IN :accountIds
];
Lightning Web Component(カウンターの例)
<template>
<lightning-card title="Counter">
<div class="slds-p-around_medium">
<p>Count: {count}</p>
<lightning-button label="Increment" onclick={handleIncrement}></lightning-button>
</div>
</lightning-card>
</template>
// counterComponent.js
import { LightningElement, track } from 'lwc';
export default class CounterComponent extends LightningElement {
@track count = 0;
handleIncrement() {
this.count += 1;
}
}
<?xml version="1.0" encoding="UTF-8"?>
<LightningComponentBundle xmlns="http://soap.sforce.com/2006/04/metadata">
<apiVersion>59.0</apiVersion>
<isExposed>true</isExposed>
<targets>
<target>lightning__AppPage</target>
<target>lightning__RecordPage</target>
</targets>
</LightningComponentBundle>
@jeffallan、Synergetic Solutions のプリンシパルコンサルタントが管理しています
コメント
Markdown 対応