Salesforce Connect: リアルタイム外部データ連携の徹底解説

背景と応用シナリオ

Salesforce アーキテクトとして、私は常にお客様のビジネス要件と技術的実現可能性の最適なバランスを見つけることを目指しています。現代の企業システムは、Salesforce だけでなく、ERP (Enterprise Resource Planning)、レガシーシステム、データベースなど、複数のシステムで構成されています。これらのサイロ化されたデータをいかにして Salesforce 上でシームレスに活用するかは、多くのプロジェクトで中心的な課題となります。

従来、この課題を解決する主な方法は、ETL (Extract, Transform, Load) ツールやバッチ処理を用いて外部システムのデータを Salesforce のカスタムオブジェクトに定期的にコピー(データレプリケーション)することでした。このアプローチは、レポート作成やオフラインアクセスには有効ですが、以下のようなデメリットも抱えています。

  • データの鮮度の問題: 同期ラグにより、Salesforce 上のデータが常に最新であるとは限らない。
  • ストレージコストの増加: 大量のデータを Salesforce 内に複製するため、データストレージのコストが増大する。
  • 開発・運用コスト: 同期プロセスの開発と維持にコストと時間がかかる。

ここで登場するのが Salesforce Connect です。Salesforce Connect は、データを Salesforce 内にコピーすることなく、外部システムに保存されているデータにリアルタイムでアクセスし、表示・操作することを可能にする強力なデータ仮想化 (Data Virtualization) フレームワークです。あたかも Salesforce の標準オブジェクトやカスタムオブジェクトのように、外部データを扱うことができます。

応用シナリオ

Salesforce Connect が特に価値を発揮するのは、以下のようなシナリオです。

  • ERP との連携: 営業担当者が取引先ページで、ERP システムに保存されている最新の注文履歴や請求情報をリアルタイムで確認する。
  • 大規模データセットへのアクセス: Salesforce のストレージ制限を気にすることなく、外部のビッグデータリポジトリに保存された製品カタログや顧客の行動ログを参照する。
  • レガシーシステムの延命: 全面的なシステム移行が困難なレガシーシステム内のデータを、最新の Salesforce UI/UX を通じて活用する。
  • コンプライアンス要件: 特定のデータを物理的に Salesforce Platform に保存できない規制やポリシーがある場合に、データを元の場所に置いたまま参照する。

アーキテクトの視点から見れば、Salesforce Connect は「いつデータを移動し、いつ仮想化するか」という重要な設計判断を下すための強力な選択肢と言えます。


原理説明

Salesforce Connect の中核をなすのは外部オブジェクト (External Objects) という特別なオブジェクトです。これは、Salesforce のカスタムオブジェクトに似ていますが、データそのものは Salesforce 内に保存されません。ユーザーが外部オブジェクトのレコードを表示したり、クエリを実行したりすると、Salesforce Platform はリアルタイムで外部データソースに対してリクエストを送信し、結果を取得してユーザーに返します。

この連携を実現するために、Salesforce Connect は主に3つのアダプタをサポートしています。

  1. OData (Open Data Protocol) アダプタ: OData 2.0 または 4.0 をサポートする Web サービスに接続します。OData は REST に基づく標準化されたプロトコルであり、多くのモダンなシステム (SAP, Microsoft Dynamics など) で採用されています。設定は主に宣言的(ポイント&クリック)で完了します。
  2. 組織間 (Cross-Org) アダプタ: 他の Salesforce 組織のデータに接続します。これにより、複数の Salesforce 組織を持つ企業が、組織間でデータをシームレスに共有できます。
  3. Apex コネクタフレームワーク (Apex Connector Framework) アダプタ: OData や Salesforce のプロトコルに対応していない独自の API を持つシステムと連携するための、最も柔軟で強力な選択肢です。開発者は Apex コードを記述して、任意の外部システムへの接続ロジックを実装できます。

ユーザーが外部オブジェクトのリストビューを表示すると、Salesforce は対応する外部データソースにクエリ(例:OData の場合は $top, $skip, $filter などのパラメータを含む GET リクエスト)を送信します。外部システムはそのクエリを処理し、結果を返します。この一連のプロセスは透過的に行われるため、エンドユーザーはそれが外部データであることを意識する必要はありません。

このアーキテクチャは、データの一元管理(Single Source of Truth)を維持しつつ、必要な場所で必要な情報を提供するという、現代のエンタープライズアーキテクチャの理想形に近づくための重要な手段です。


コード例

ここでは、最も柔軟性の高い Apex Connector Framework を使用したカスタムアダプタの実装例を見てみましょう。このフレームワークでは、DataSource.Provider クラスと DataSource.Connection クラスを実装して、Salesforce がどのように外部システムと通信し、データを解釈するかを定義します。以下のコードは、Salesforce 公式ドキュメントにあるサンプルを基に、外部のデータソースからデータを取得し、同期するロジックを示しています。

この例では、架空のデータソース `MyDataSource` を想定しています。

/*
 * DataSource.Provider クラスを実装し、カスタムコネクタの基本情報と接続を定義します。
 * このクラスは、外部データソースの種類(この場合は 'MyDataSource')を宣言し、
 * 認証機能や接続インスタンスを提供します。
 */
global class MyDataSourceProvider extends DataSource.Provider {
    // コネクタがサポートする認証機能を宣言します。
    // ここでは匿名アクセスのみをサポートしています。
    override global List<DataSource.AuthenticationCapability> getAuthenticationCapabilities() {
        List<DataSource.AuthenticationCapability> capabilities =
            new List<DataSource.AuthenticationCapability>();
        capabilities.add(DataSource.AuthenticationCapability.ANONYMOUS);
        return capabilities;
    }

    // コネクタがサポートする機能を宣言します。
    // ROW_QUERY: SOQL クエリによる行の取得をサポート
    // SEARCH: SOSL 検索をサポート
    override global List<DataSource.Capability> getCapabilities() {
        List<DataSource.Capability> capabilities =
            new List<DataSource.Capability>();
        capabilities.add(DataSource.Capability.ROW_QUERY);
        capabilities.add(DataSource.Capability.SEARCH);
        return capabilities;
    }

    // 外部データソースへの接続インスタンスを返します。
    // Salesforce はこのメソッドを呼び出して、実際のデータ操作を行うオブジェクトを取得します。
    override global DataSource.Connection getConnection(DataSource.ConnectionParams connectionParams) {
        return new MyDataSourceConnection(connectionParams);
    }
}


/*
 * DataSource.Connection クラスを実装し、外部データソースとの実際の通信ロジックを定義します。
 * sync()、query()、search() などのメソッドをオーバーライドして、
 * 外部オブジェクトのメタデータ同期やデータ取得処理を実装します。
 */
global class MyDataSourceConnection extends DataSource.Connection {
    private DataSource.ConnectionParams connectionInfo;

    // コンストラクタ
    global MyDataSourceConnection(DataSource.ConnectionParams connectionParams) {
        this.connectionInfo = connectionParams;
    }

    // 外部データソースのスキーマを Salesforce と同期します。
    // ユーザーが「検証して同期」ボタンをクリックしたときに呼び出されます。
    // 外部のテーブル定義を基に、Salesforce の外部オブジェクトと項目を作成します。
    override global List<DataSource.Table> sync() {
        // 例: 'Orders' という名前のテーブル(外部オブジェクト)を定義
        List<DataSource.TableColumn> columns = new List<DataSource.TableColumn>();
        columns.add(DataSource.TableColumn.text('OrderID', 255)); // 注文ID
        columns.add(DataSource.TableColumn.text('CustomerName', 255)); // 顧客名
        columns.add(DataSource.TableColumn.url('DisplayUrl')); // 表示URL(必須)
        columns.add(DataSource.TableColumn.text('ExternalId', 255)); // 外部ID(必須)
        
        // DataSource.Table オブジェクトを作成してリストに追加
        List<DataSource.Table> tables = new List<DataSource.Table>();
        tables.add(DataSource.Table.get('Orders', 'OrderID', columns));
        return tables;
    }

    // ユーザーが外部オブジェクトのレコードにアクセスしたときに呼び出されます。
    // SOQL クエリを解釈し、外部システムからデータを取得して返します。
    override global DataSource.TableResult query(DataSource.QueryContext context) {
        // ここで外部システムへの HTTP Callout などを実行します。
        // context オブジェクトには、SOQLクエリの情報(テーブル名、フィルタ条件、上限数など)が含まれます。
        // この例では、ダミーデータを生成しています。
        System.debug('Querying table: ' + context.tableSelection.table);

        List<Map<String, Object>> responseData = new List<Map<String, Object>>();
        
        Map<String, Object> row1 = new Map<String, Object>();
        row1.put('OrderID', 'ORD-001');
        row1.put('CustomerName', 'Test Customer 1');
        // DisplayUrl と ExternalId は必須です。通常、一意のレコードIDをここに設定します。
        row1.put('DisplayUrl', '/services/data/v58.0/sobjects/MyExternalObject__x/ORD-001');
        row1.put('ExternalId', 'ORD-001');
        responseData.add(row1);

        Map<String, Object> row2 = new Map<String, Object>();
        row2.put('OrderID', 'ORD-002');
        row2.put('CustomerName', 'Test Customer 2');
        row2.put('DisplayUrl', '/services/data/v58.0/sobjects/MyExternalObject__x/ORD-002');
        row2.put('ExternalId', 'ORD-002');
        responseData.add(row2);

        // 取得したデータを DataSource.TableResult 形式で返します。
        return DataSource.TableResult.get(context, responseData);
    }
}

注意事項

Salesforce Connect は強力なツールですが、アーキテクトとしてその制約とトレードオフを十分に理解しておく必要があります。不適切なシナリオで利用すると、パフォーマンスの悪化や予期せぬエラーを引き起こす可能性があります。

権限とセキュリティ (Permissions and Security)

外部オブジェクトも Salesforce の共有設定モデルに従いますが、レコードレベルのアクセス制御は外部システムに依存します。外部データソースへの接続には、指定ログイン情報 (Named Credential) の使用が強く推奨されます。これにより、エンドポイント URL や認証情報をコードから分離し、安全に管理できます。

API 制限 (API Limits)

Salesforce Connect による外部システムへのアクセスは、Salesforce のコールアウト制限の対象となります。例えば、Enterprise Edition の OData アダプタには、1時間あたり 20,000 コールアウトという制限があります。ユーザーがリストビューを開いたり、レポートを実行したり、API 経由でクエリを発行したりするたびにコールアウトが消費されます。多数のユーザーが同時にアクセスするような高トラフィックなシナリオでは、この制限に達するリスクを慎重に評価する必要があります。

パフォーマンス (Performance)

外部オブジェクトのパフォーマンスは、完全に外部システムの応答速度に依存します。外部システムの API が遅い場合、Salesforce 上でのユーザーエクスペリエンスは著しく低下します。アーキテクトは、外部システムの API が以下の要件を満たしているか確認する必要があります。

  • 低レイテンシ: 迅速な応答が可能であること。
  • ページング対応: 一度に大量のデータを返すのではなく、ページング(例: OData の $top, $skip)をサポートしていること。サーバー駆動ページングが推奨されます。
  • フィルタリング対応: Salesforce からの絞り込み条件(例: OData の $filter)を効率的に処理できること。

データモデルとクエリの制限 (Data Model and Query Limitations)

外部オブジェクトは、標準・カスタムオブジェクトと全く同じように機能するわけではありません。

  • リレーション: 標準オブジェクトから外部オブジェクトへの参照関係は作成できません(逆は可能)。外部オブジェクト間のリレーションシップには、外部参照 (External Lookup)間接参照 (Indirect Lookup) という特別な種類のリレーションがあり、設計時に慎重な検討が必要です。
  • SOQL の制限: 集計関数 (COUNT(), SUM() など) のサポートは限定的です。複雑な WHERE 句や、親子リレーションをまたぐクエリ(サブクエリ)もサポートされない場合があります。
  • レポートとダッシュボード: 外部オブジェクトはレポートで利用できますが、結合レポートには使用できないなどの制限があります。
  • 書き込み操作: 外部オブジェクトを書き込み可能にするには、外部データソースの設定で「書き込み可能な外部オブジェクト」を有効にし、かつ外部システム側が作成・更新・削除の操作をサポートしている必要があります。

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

Salesforce Connect は、Salesforce を単なる CRM アプリケーションから、企業全体の情報を集約・活用するための「エンゲージメントのプラットフォーム」へと昇華させるための重要なアーキテクチャコンポーネントです。

アーキテクトとして、以下のベストプラクティスを念頭に置くことで、Salesforce Connect の価値を最大限に引き出すことができます。

  1. 適切なユースケースの選択:
    • 利用を推奨するケース: 少量のデータをリアルタイムで参照する必要がある場合。データの一元管理が重要で、コピーを作成したくない場合。ストレージコストを削減したい場合。
    • 利用を避けるべきケース: 大量のデータに対する複雑な集計やレポートが必要な場合。オフラインアクセスが必要な場合。外部システムへの頻繁な書き込みやバッチ処理が必要な場合。この場合は、従来型の ETL/API 連携を検討すべきです。
  2. インテグレーションパターンの理解: Salesforce Connect を「データ仮想化 (Data Virtualization)」パターンとして位置づけ、ETL などの「データレプリケーション (Data Replication)」や、Apex Callout などの「リモートプロセス呼び出し (Remote Process Invocation)」といった他のインテグレーションパターンと適切に使い分けることが重要です。
  3. 外部システムの API 設計: 可能であれば、Salesforce Connect からの利用を前提として外部システムの API を設計することが理想です。特に、効率的なフィルタリングとページングのサポートは、パフォーマンスに決定的な影響を与えます。
  4. セキュリティの徹底: 認証には必ず指定ログイン情報 (Named Credential) を使用し、最小権限の原則に従って外部システムへのアクセス権を付与してください。
  5. テストとモニタリング: 本番稼働前に、想定される負荷状況下でのパフォーマンステストを必ず実施してください。また、外部システムの API 稼働状況や Salesforce のコールアウト使用状況を継続的にモニタリングする仕組みを構築することが望ましいです。

結論として、Salesforce Connect は「銀の弾丸」ではありませんが、その特性と制約を深く理解し、適切なシナリオで適用すれば、開発コストを削減し、データの鮮度を高め、より柔軟でスケーラブルなシステムアーキテクチャを実現するための非常に強力な選択肢となります。

コメント