Salesforce Apexクラス完全ガイド:開発者のためのベストプラクティス


役割:Salesforce 開発者


背景と応用シナリオ

Salesforceプラットフォームで働く開発者として、私たちは日々、標準機能だけでは満たせない複雑なビジネス要件に直面します。ここで中心的な役割を果たすのが Apex です。Apexは、Salesforceが提供する強力なオブジェクト指向プログラミング言語であり、その中核をなすのが Apex Class (Apexクラス) です。

Apexクラスは、データ構造(変数)と振る舞い(メソッド)をカプセル化するための設計図やテンプレートと考えることができます。これにより、再利用可能で、保守性が高く、スケーラブルなコードを作成することが可能になります。これは、Object-Oriented Programming (OOP) (オブジェクト指向プログラミング) の基本原則に則っています。OOPの概念(カプセル化、継承、ポリモーフィズム)を活用することで、複雑なロジックを整理し、管理しやすい単位に分割できます。

Apexクラスの具体的な応用シナリオは多岐にわたります:

カスタムビジネスロジックの実装

標準の入力規則やワークフロールールでは対応できない、複数オブジェクトにまたがる複雑なデータ検証や、特定の条件下でのレコードの自動作成・更新など、高度なビジネスロジックを実装します。

Webサービスの提供と利用

Apexクラスを使用して、外部システムにデータを提供するためのカスタム REST APISOAP API を公開したり、逆に外部のAPIを呼び出してSalesforce内にデータを取り込んだりすることができます。

トリガーのロジック分離

Apex Trigger (Apexトリガー) 内に直接大量のロジックを記述すると、コードの可読性や保守性が著しく低下します。トリガーから呼び出すヘルパークラスやハンドラークラスにロジックを移すことで、コードを整理し、テストを容易にします。

非同期処理

大量のデータを一度に処理する必要がある場合、Batch Apex (バッチApex) を使用してガバナ制限を回避しながら処理を実行します。また、将来の特定の時間にジョブを実行したい場合は Schedulable Apex (スケジュール可能Apex)、コールアウトなど時間のかかる処理を非同期で行いたい場合は Queueable Apex (キュー可能Apex) や @future メソッドを使用します。これらはすべてApexクラスとして実装されます。

カスタムUIのバックエンドコントローラー

Visualforce ページ、Aura Components、または Lightning Web Components (LWC) のサーバーサイドコントローラーとして機能し、UIとSalesforceデータベース間のデータ送受信やビジネスロジックの実行を担当します。

原理説明

Apexクラスは、Salesforceプラットフォーム上でコードを構造化するための基本的な構成要素です。クラスの構造を理解することは、効果的な開発の第一歩です。以下に、Apexクラスを構成する主要な要素を説明します。

クラス定義とアクセス修飾子

クラスは class キーワードで定義されます。その前には、クラスの可視性を制御する Access Modifier (アクセス修飾子) を指定します。

  • private: このクラス内でのみアクセス可能です。内部クラス(inner class)を定義する場合に主に使用されます。
  • public: 同じ名前空間(namespace)内のどのApexコードからでもアクセス可能です。最も一般的に使用されます。
  • global: すべてのApexコードからアクセス可能です。管理パッケージ(managed package)を作成し、外部の組織がそのクラスを利用できるようにする場合や、Webサービスを実装する場合に使用されます。
  • protected: このクラス、またはこのクラスを継承(extend)したサブクラス内のメソッドからのみアクセス可能です。

インスタンス変数と静的変数

変数は、クラスの状態を保持するためのものです。

  • インスタンス変数 (Instance Variables): クラスの各インスタンス(オブジェクト)に固有のデータを保持します。new キーワードでオブジェクトが作成されるたびに、新しいメモリ領域が割り当てられます。
  • 静的変数 (Static Variables): static キーワードで宣言され、クラスのすべてのインスタンスで共有されます。インスタンスを作成しなくても、ClassName.variableName の形式でアクセスできます。静的変数は、トリガーの実行コンテキスト全体で状態を共有するためによく利用されます。

メソッド

メソッドは、クラスの振る舞いを定義します。メソッドも変数と同様にアクセス修飾子と、static キーワードを持つことができます。

  • インスタンスメソッド (Instance Methods): クラスのインスタンスに対して操作を行います。そのインスタンスの変数にアクセスできます。
  • 静的メソッド (Static Methods): static キーワードで宣言され、インスタンスを必要とせずに ClassName.methodName() の形式で呼び出せます。ユーティリティメソッドなど、特定のインスタンスの状態に依存しない処理に適しています。

コンストラクタ

Constructor (コンストラクタ) は、クラスのインスタンスが作成される際に呼び出される特殊なメソッドです。クラス名と同じ名前を持ち、戻り値を持ちません。主な目的は、オブジェクトの初期化です。コンストラクタが定義されていない場合、引数のないデフォルトの公開コンストラクタが自動的に作成されます。

プロパティ

プロパティは、変数の値を取得(get)および設定(set)するための特別な構文です。VisualforceやAura/LWCのコントローラーで、UIとデータをやり取りする際によく使用されます。

public class MyController {
    // 自動実装プロパティ。コンパイラがprivate変数を自動生成する
    public String name { get; set; }

    // 読み取り専用プロパティ
    public Integer recordCount { get; private set; }

    public MyController() {
        // コンストラクタで初期化
        name = 'Initial Name';
        recordCount = 0;
    }
}

示例代码

以下は、Salesforceの公式ドキュメントにある、特定のメールアドレスリストにメールを送信するためのApexクラスの例です。このコードは、global アクセス修飾子、静的メソッド、そしてSalesforceの組み込みメール機能である Messaging クラスの使用方法を示しています。

// このクラスは、メール送信ロジックをカプセル化し、
// 他のApexコードから再利用できるようにグローバル(global)で定義されています。
global class EmailManager {

    // sendMailメソッドは、メールの送信処理を担当します。
    // 静的(static)メソッドであるため、EmailManagerクラスのインスタンスを作成せずに呼び出すことができます。
    // 例: EmailManager.sendMail('test@example.com', 'Subject', 'Body');
    // Webサービスとして公開するために `webservice` キーワードが付与されています。
    webservice static void sendMail(String address, String subject, String body) {

        // Messaging.SingleEmailMessageは、1通のメールを表現するためのSalesforceの標準オブジェクトです。
        // これを使用して、宛先、件名、本文などのメールの各要素を設定します。
        Messaging.SingleEmailMessage mail = new Messaging.SingleEmailMessage();
        
        // メールの宛先アドレスを配列として設定します。
        // この例では、メソッドの引数で渡された単一のアドレスをリストに格納しています。
        String[] toAddresses = new String[] {address};
        mail.setToAddresses(toAddresses);
        
        // メールの差出人表示名を設定します。
        // これを設定しない場合、メールを送信したユーザーの名前が使用されます。
        mail.setSenderDisplayName('Salesforce Support');
        
        // メールの件名を設定します。
        mail.setSubject(subject);
        
        // メールの本文をプレーンテキスト形式で設定します。
        // HTML形式で送信したい場合は、setHtmlBody() メソッドを使用します。
        mail.setPlainTextBody(body);
        
        // Messaging.sendEmailメソッドを呼び出して、実際にメールを送信します。
        // このメソッドは、最大10件のメールオブジェクトのリストを引数に取ることができます。
        // この例では、1件のメールのみをリストに入れて送信しています。
        // sendEmailの呼び出しは、ガバナ制限(1回のトランザクションでのコール回数)の対象となります。
        Messaging.sendEmail(new Messaging.SingleEmailMessage[] { mail });
    }
}

このクラスを匿名実行(Anonymous Apex)ウィンドウから呼び出す例は以下の通りです。

// EmailManagerクラスの静的メソッドsendMailを呼び出します。
// 実際のメールアドレス、件名、本文を引数として渡します。
EmailManager.sendMail('your-email@example.com', 'Apex Test Email', 'This is a test email sent from an Apex class.');

注意事項

Apexクラスを開発・運用する上で、いくつかの重要な制約や考慮事項があります。これらを無視すると、パフォーマンスの低下や予期せぬエラー、本番環境へのデプロイ失敗につながります。

Governor Limits (ガバナ制限)

Salesforceはマルチテナント環境であるため、すべてのユーザーが安定してプラットフォームを利用できるよう、1回のトランザクションで実行できる処理量に厳しい制限(ガバナ制限)を設けています。開発者は常にこの制限を意識する必要があります。

  • SOQLクエリ: 1トランザクションあたり100件まで。
  • DMLステートメント: 1トランザクションあたり150件まで。
  • CPU時間: 1トランザクションあたり10,000ミリ秒まで。
  • ヒープサイズ: 6MBまで。

これらの制限に違反しないためには、Bulkification (一括処理) の設計が不可欠です。例えば、forループ内でSOQLクエリやDML操作を実行することは絶対に避けるべきです。

セキュリティと共有設定

Apexクラスは、デフォルトではシステムの共有設定を無視して実行されます(without sharing として動作)。これは、クラスが組織のすべてのデータにアクセスできる可能性があることを意味します。ユーザーの権限や共有ルールを尊重させるためには、クラス定義に with sharing キーワードを明示的に指定する必要があります。

public with sharing class MySecureClass {
    // このクラス内のコードは、実行ユーザーの共有設定に従います。
}

@AuraEnabled が付与されたメソッドを持つクラスなど、特定のコンテキストではデフォルトの動作が異なる場合があるため、常に意図した共有設定になっているか確認することが重要です。

テストコードとコードカバレッジ

本番環境や管理パッケージにApexコードをデプロイするためには、Apexコード全体の少なくとも 75% がテストコードによってカバーされている必要があります。これは最低要件であり、品質を保証するためには90%以上を目指すべきです。テストクラスでは、単にコード行を通過させるだけでなく、正常系、異常系、バルク処理など、様々なシナリオを網羅的に検証することが求められます。また、テストメソッドでは @isTest(SeeAllData=false) を使用し、テスト専用のデータを作成して実行することがベストプラクティスです。

エラーハンドリング

DML操作や外部APIへのコールアウトなど、失敗する可能性のある処理は必ず try-catch ブロックで囲み、例外処理を実装する必要があります。特にDML操作では、Database.insert(records, false) のようにallOrNoneパラメータをfalseに設定することで、一部のレコードが失敗してもトランザクション全体がロールバックされるのを防ぎ、成功したレコードと失敗したレコードを個別に処理することができます。

まとめとベストプラクティス

Apexクラスは、Salesforceプラットフォーム上でカスタムソリューションを構築するための根幹をなす技術です。その構造と原則を深く理解し、ベストプラクティスに従うことで、堅牢でスケーラブルなアプリケーションを開発することができます。

最後に、開発者として心に留めておくべきベストプラクティスをまとめます。

  1. 単一責任の原則 (Single Responsibility Principle): 1つのクラスは1つの責務のみを持つように設計します。例えば、トリガーロジック、クエリ処理、ユーティリティ機能をそれぞれ別のクラスに分割します。
  2. コードの一括処理 (Bulkification): 常に複数のレコードを処理できるようにコードを設計します。コレクション(List, Set, Map)を最大限に活用し、ループ内でのSOQL/DMLを排除します。
  3. IDのハードコーディングを避ける: レコードID、プロファイルID、レコードタイプIDなどをコード内に直接書き込むのではなく、カスタムメタデータ、カスタム設定、または動的なSOQLクエリを使用して取得します。
  4. 命名規則の遵守: クラス名、メソッド名、変数名に一貫した命名規則を用いることで、コードの可読性を高めます。
  5. 適切なコメント: なぜそのコードが必要なのか、複雑なロジックの意図は何かをコメントで説明します。コードが「何をしているか」ではなく、「なぜそうしているか」を記述することが重要です。
  6. 常にガバナ制限を意識する: 開発の初期段階から、SOQLクエリの数やCPU時間を意識した設計を心がけます。デバッグログを活用して、パフォーマンスのボトルネックを特定します。

これらの原則を実践することで、あなたは単に動くコードを書くだけでなく、長期的に価値を提供し続ける優れたSalesforce開発者となることができるでしょう。

コメント