開発

Apexとは?Salesforce専用のオブジェクト指向言語をガバナ制限と実装目線で解説

ApexはSalesforceプラットフォーム上でだけ動く、強く型付けされたオブジェクト指向のプログラミング言語です。構文はJavaに近く、データベース操作(SOQL/DML)を言語仕様として組み込んでいる点が最大の個性になります。この記事では、Apexの定義とアーキテクチャ上の位置づけ、トリガ・クラス・バッチ・非同期といった構成要素、マルチテナント特有のガバナ制限、宣言的なFlowとの使い分け、そしてSummer ’26(API v67.0)で変わったセキュリティ既定まで、実装者が判断に使える粒度で扱います。標準機能で足りるのか、Apexを書くべきなのかの線引きを条件付きで示すのが、この記事のねらいです。

目次

まとめ:Apexは「Salesforceの中でだけ」効くサーバサイド言語

Apexは汎用言語ではありません。Salesforceのデータモデル(オブジェクトと項目)を型として直接参照し、レコードの保存前後に処理を差し込むために設計された、プラットフォーム内蔵の言語です。書けることの範囲はSalesforceが引く境界に一致します。

採用判断の軸はひとつです。宣言的なFlowで組めるならApexを書かない、Flowでは表現できない条件分岐・大量データ処理・外部連携が必要になった時だけApexに降りる。この線引きを守れるかが、保守コストとガバナ制限(1トランザクションあたりのSOQL 100回・DML 150回といった上限)に耐えるかを分けます。Summer ’26のAPI v67.0では、データベース操作が既定でユーザモードになるなどセキュリティの初期値が変わったため、既存Apexをそのままバージョン上げする前にレビューが要る、という点も先に押さえておきます。

Apexの定義とプラットフォーム上での位置づけと実行モデルの基礎

まず、Apexが「どのレイヤーで、何のために動くのか」を固めます。ここを曖昧にしたまま書き始めると、汎用言語の感覚でコードを組んでガバナ制限に衝突します。

強く型付けされたオブジェクト指向言語というApexのコアの性質

Apexはクラス・インターフェース・継承・例外を備えたオブジェクト指向言語で、変数や項目の型はコンパイル時に検証されます。存在しない項目名を参照すればコンパイルが通りません。この「スキーマを直接参照して型安全にする」設計こそ、汎用言語との一番の違いです。オブジェクト指向の基礎概念(カプセル化・継承・多態性)はオブジェクト指向とは何かを実装目線で解説した記事で補完できます。Apexのクラス設計もこの延長線上にあります。

Salesforce/Lightning Platform専用という制約の意味

Apexで書いたコードは、Salesforceのサーバ(Lightning Platform)上でしか実行できません。手元のPCやAWS上で単体起動する、という使い方はできない構造です。裏を返すと、認証・データアクセス・トランザクション境界をプラットフォームが肩代わりするため、業務ロジックだけに集中できます。同じ「特定の業務プラットフォーム専用言語」という性格は、SAP上でだけ動くABAPという業務開発言語と好対照です。汎用性を捨てて、その基盤の中での生産性を取る設計思想が共通しています。

レコード保存・API公開・非同期実行などApexが動く起動契機

Apexは常駐サーバのように動き続けるわけではなく、決まったイベントで呼び出されて短時間だけ走ります。実装者が把握すべき起動契機は次のとおりです。

  • レコードの保存前後に走るトリガ(before/after insert・update・delete)
  • 画面やLightningコンポーネントから呼ぶメソッド(@AuraEnabled)
  • REST/SOAPのカスタムWeb API公開(@RestResource)
  • スケジュール実行・バッチ・キューイングによる非同期起動

どの契機で動くかによって後述のガバナ制限の上限が変わります。「同じApexでも同期か非同期かで許容量が倍違う」ことを、設計段階で意識しておきます。

Apexで書く主要な構成要素とバルク化を前提にしたクラス設計

Apexの実装は、トリガ・クラス・テストクラス・非同期処理の組み合わせで成り立ちます。ここでは各要素が「何を担当するか」を、実務での置き所とともに整理します。

トリガ本体とハンドラクラスへの責務分離という保守しやすい実装

トリガはレコードイベントを受ける入口で、ロジックそのものは別のクラス(ハンドラ)に逃がすのが実務の定石です。トリガ本体に条件分岐を書き込むと、同一オブジェクトに複数トリガが乱立したとき実行順が保証されず、保守が破綻します。1オブジェクト1トリガに絞り、処理はハンドラへ委譲する形が原則です。Trigger.newTrigger.oldMapで変更前後の値を比較し、必要なレコードだけを処理対象に選ぶのが基本パターンになります。

最大200件をまとめて処理するためのバルク化を前提にしたクラス設計

Apexで最も事故が起きるのは、ループの中でSOQLやDMLを呼ぶコードです。トリガは一度に最大200件のレコードをまとめて渡してくるため、1件ずつ処理する発想で書くと即座に上限に触れます。クエリはループの外で1回にまとめ、更新対象はListに貯めてループ後に一括DMLする、というバルク化を最初から前提にします。

  1. ループ前:関連レコードを1本のSOQLでまとめて取得しMapに格納
  2. ループ内:メモリ上のMapを参照して加工し、更新対象をListへ追加
  3. ループ後:貯めたListを1回のDMLで一括更新

この3段構えを崩さなければ、200件でも1件でも消費するSOQL・DMLの回数は一定に保てます。

テストクラスと75%コードカバレッジという本番デプロイの条件

Apexは本番組織へ配布する前に、テストクラスによる自動テストが必須です。組織全体で75%以上のコードカバレッジがなければ本番デプロイ自体が拒否される仕様になっています。これは推奨ではなくプラットフォームが課す配布条件で、テストを後回しにするとリリース自体が止まる設計です。テストの考え方はSalesforceに限らないため、テスト設計の基礎を押さえておくと転用が利きます。Test.startTest()Test.stopTest()で囲った区間は、非同期処理を同期的に検証でき、ガバナ制限のカウントもリセットされます。

マルチテナント環境が課すガバナ制限とその回避のための実装技法

Apex固有の難所がガバナ制限です。Salesforceは1つのインフラを多数の企業で共有するマルチテナント構造のため、1社のコードが資源を独占しないよう、実行エンジンがトランザクション単位で上限を課します。上限を超えると例外が発生し、その例外は握りつぶせません(catchできない設計)。

同期と非同期で倍近く変わるガバナ制限の代表的な上限値の早見表

覚えるべき上限は多くありません。頻繁に触れる代表値を、同期・非同期で並べます(Salesforceの公開する制限クイックリファレンスに基づく代表値。詳細は組織のAPIバージョンで確認します)。

制限項目 同期トランザクション 非同期(バッチ・Queueable等)
SOQLクエリ発行回数 100回 200回
DMLステートメント数 150回 150回
SOQLで取得する総レコード数 50,000件 50,000件
CPU時間 10,000ミリ秒 60,000ミリ秒
ヒープサイズ 6MB 12MB
外部コールアウト数 100回 100回

実装時に効いてくるのはSOQL回数とCPU時間です。前述のバルク化はこの上限を守るための技法そのもので、ループ内クエリを撲滅すればSOQL回数はまず枯渇しません。

数万件規模の大量データを扱うときのバッチApexという逃げ道

数万件を一括処理したい場面では、同期処理のままだと総レコード数やCPU時間で詰まります。ここでDatabase.Batchableインターフェースを実装したバッチApexに切り替えるのが定石です。バッチは対象レコードを既定200件ずつのチャンクに分割し、チャンクごとに独立したトランザクションとしてガバナ制限をリセットしながら流します。夜間の大量更新やデータ移行は、この非同期バッチが定番の置き場所です。

非同期処理の使い分けとFuture・Queueable・Batchの選択基準

非同期には4系統あり、規模と依存関係で選びます。単発の軽い外部コールアウトなら@future、ジョブの連鎖や引数にオブジェクトを渡したいならQueueable、数万件超の分割処理ならBatchable、定時起動ならSchedulableという対応です。新規実装で@futureよりQueueableを勧めるのは、ジョブIDで監視でき、後続ジョブをチェーンできるためです。

Apexと宣言的自動化Flowの採用判断と使い分けの境界線の基準

ここが実装者の判断が最も問われる章です。Salesforceにはコードを書かずに自動化を組むFlow(フロー)があり、両者の境界を引けるかで、組織の保守コストが大きく変わります。結論から言い切ります。

宣言的なFlowで足りる定型処理にApexを書かないという原則

単一オブジェクトの項目更新、条件付きのレコード作成、承認申請の起動、画面ウィザードといった定型は、Flowで組むべきでApexを書く場面ではありません。理由は保守の担い手です。Flowは管理者(非エンジニア)が改修でき、コードレビューやデプロイ手順を通さずに調整できます。ここにApexを持ち込むと、以後の小さな仕様変更のたびに開発者の工数が発生し、組織のスピードを落とします。

Flowでは表現しきれずにApexへ降りるべき4つの判断条件

逆に、次のいずれかに該当したらFlowで粘らずApexへ移します。無理にFlowで組むと、かえって読めない巨大フローになり保守不能になります。

  • 複雑な繰り返し・入れ子ループや、コレクションの高度な加工が必要
  • 1回の処理で数千〜数万件を扱い、バルク化とバッチ分割が要る
  • 外部システムへのREST/SOAPコールアウトや、複雑な例外ハンドリングが必要
  • Flowでは表現しきれないトランザクション制御・ロールバック制御が要る

将来の拡張可能性を理由にApexを採用してはいけない場面の線引き

「将来の拡張に備えてとりあえずApexで書く」は失敗パターンです。要件がFlowの範囲に収まっているうちは、拡張の可能性を理由にコード化しない方が保守は軽くなります。Apexは書いた瞬間からテストクラスとカバレッジ維持の義務が付いてくるためです。逆に、月次バッチのように最初から大量データと非同期が確定している処理を、Flowで無理に組むのも見送る判断になります。判断は「今の要件がどちらの土俵か」で決め、可能性で決めないのが原則です。

Summer ’26(API v67.0)で変わったセキュリティ既定への対応

時点依存の話をひとつ。2026年のSummer ’26リリース(API v67系)で、Apexのセキュリティ初期値がここ数年で最大級の変更を受けました。既存コードを新バージョンへ上げる前に確認すべき点なので、事実と対応をセットで示します。

データベース操作が既定でユーザモードで実行されるという既定変更

API v67.0でコンパイルしたApexでは、データベース操作が既定でユーザモード(実行ユーザの項目・レコードアクセス権を尊重)で走るようになりました。従来のシステムモード前提で、権限を持たないユーザでも全レコードを触れることを暗黙に期待していたコードは、バージョンを上げると挙動が変わり得ます。対応は、意図してシステムモードで動かしたい箇所に明示指定を付け、それ以外はユーザモード既定を受け入れて権限設計を見直すことです。

共有sharing宣言の既定値とトリガの実行モードに関する見直し

共有宣言を省略したクラスの既定も変わります。v66.0以前は省略時にwithout sharing相当だったのに対し、継承チェーンにv67.0以降で保存されたクラスが混ざると、省略時の既定がwith sharing寄りに解釈されます。加えてトリガは全APIバージョンで常にシステムモードで動く扱いに整理され、トリガへの共有・アクセスモード宣言は許可されなくなりました。既存資産をアップグレードするなら、sharing宣言を省略しているクラスを洗い出し、意図した共有ルールを明示するのが安全側の対応になります。

レガシーAPIバージョン31.0〜40.0廃止という保守の締め切り

あわせて、Platform APIバージョン31.0〜40.0が廃止予定として告知されました。完全廃止はSummer ’28で、その時点で当該バージョン向けのコールは失敗します。古いバージョンで固定された連携やApexが残っている組織にとって、41.0以降への引き上げは実質の締め切り付きタスクです。「動いているから触らない」を続けると、廃止時に連携が止まるため、棚卸しを前倒しする判断が要ります。

Apex開発の環境構築と、内製で抱えるか外注に出すかの判断軸

最後に、これからApexに着手する場合の入口と、内製か外注かの線引きを示します。

開発者コンソールからVS Code+CLIまでの環境の選択肢

軽い検証はブラウザ内の開発者コンソールで完結しますが、実務ではVS CodeにSalesforce Extensionsを入れ、Salesforce CLI(sfコマンド)でソースをローカル管理する構成が主流です。バージョン管理・CI・コードレビューを回すなら、コードをGitに載せられるこの構成が前提になります。検証はサンドボックス(本番のコピー組織)で行い、本番へは前述の75%カバレッジを満たしたうえでデプロイします。

内製で抱えるか受託に出すかを分ける要件規模と保守体制の見極め

Apexの厄介さは、言語そのものより「ガバナ制限・共有モデル・年3回のリリースへの追従」という運用面に集中します。単発のトリガ改修なら内製で十分ですが、複数オブジェクトをまたぐ業務ロジック、大量データのバッチ設計、外部システム連携、そしてv67.0のようなセキュリティ既定変更への追従判断まで含むと、片手間の内製では品質が安定しません。要件がその規模に達したら、設計と実装をSalesforce導入支援・Apex開発の受託に切り出し、社内は運用と要件定義に集中する分担が現実的です。バルク化やテスト設計の型を最初に固めてもらえば、以後の内製改修もその土台の上で回せます。

Apexの開発でつまずきやすい論点に答えるよくある質問と回答

Apexの学習・導入を検討する担当者から寄せられやすい質問に、実装の観点から簡潔に答えます。

ApexとJavaは何が違うのですか?

構文はJavaによく似ていますが、実行できる場所と扱えるデータが違います。ApexはSalesforceのサーバ上でだけ動き、SOQLやDMLといったデータベース操作が言語仕様に組み込まれています。一方でマルチテナント由来のガバナ制限があり、Javaのように資源を自由に使えるわけではありません。Javaの経験者なら文法の習得は速いものの、制限とデータモデルの理解に時間を割く必要があります。

Apexを学ぶのにプログラミング経験は必須ですか?

オブジェクト指向の基礎(クラス・変数・条件分岐・ループ)を理解していることが前提になります。まったくの未経験からだと、言語仕様よりオブジェクト指向の考え方でつまずきやすいため、先に基礎概念を押さえると学習がスムーズです。SalesforceのオンライントレーニングTrailheadに、Apex向けの体系的な学習コースが用意されています。

ガバナ制限に引っかからないコツはありますか?

最大のコツはバルク化です。ループの中でSOQLやDMLを呼ばず、クエリはループ外で1回にまとめ、更新はListに貯めて一括処理します。これでレコード件数が増えてもSOQL・DMLの消費回数が一定に保たれます。大量データはバッチApexに切り出し、チャンクごとに制限をリセットさせるのが定石です。

ApexとFlow、どちらで作るべきですか?

宣言的なFlowで組めるならFlowを優先します。単一オブジェクトの更新や承認起動はFlowの土俵です。複雑なループ、数千件以上の一括処理、外部コールアウト、細かな例外・トランザクション制御が必要になった時だけApexに降ります。将来の拡張可能性を理由に先回りでApex化しないのが、保守を軽くする原則です。

Apex開発を外注する場合、何を基準に依頼先を選べばよいですか?

ガバナ制限を踏まえたバルク化設計と、75%カバレッジを満たすテスト設計を標準工程として持っているかを確認します。加えて、年3回のSalesforceリリース(Summer ’26のAPI v67.0のような既定変更)への追従を運用として組み込めるかも判断材料になります。単に動くコードを書くだけでなく、リリース追従まで含めて任せられる体制かを見極めると、導入後の保守で困りません。

関連記事

資料請求

RELATED POSTS 関連記事