背景と応用シナリオ
Salesforceアーキテクトとして、私は日々、企業の複雑なシステムランドスケープをどのようにSalesforceプラットフォームと効果的に統合するかという課題に直面しています。多くの企業では、顧客情報はSalesforceにありますが、注文履歴、在庫データ、請求情報などの重要なデータは、ERP、基幹システム、あるいはカスタムデータベースといった外部システムに散在しています。これらのデータをSalesforce上で一元的に表示し、活用したいというニーズは非常に高いです。
従来、この課題を解決するためには、ETL(Extract, Transform, Load)ツールを用いたバッチ処理によるデータ同期や、カスタムAPI連携を駆使した個別開発が一般的でした。しかし、これらのアプローチには、データの鮮度の問題、開発・保守コストの増大、そしてSalesforce内のストレージ消費といった課題が伴います。
ここで登場するのが Salesforce Connect です。Salesforce Connectは、データをSalesforce内にコピーすることなく、外部システムに保存されているデータにリアルタイムでアクセスし、表示・操作することを可能にする強力な統合ソリューションです。これは「データ仮想化(Data Virtualization)」というアプローチであり、Salesforceユーザーは、あたかもSalesforceの標準オブジェクトを操作しているかのように、外部データをシームレスに扱うことができます。
主な応用シナリオ
- 360度の顧客ビュー実現:取引先責任者のページに、外部ERPシステムからリアルタイムの注文履歴や請求情報を関連リストとして表示する。
- 在庫確認の効率化:商談や注文オブジェクトから、外部の在庫管理システムに直接アクセスし、リアルタイムの製品在庫を確認する。
- データコンプライアンス:個人情報や機密性の高い財務データなどを、規制の厳しい外部システムに置いたまま、Salesforce上では参照のみを許可する。
- レガシーシステムの延命:古い基幹システムをすぐにリプレースすることなく、Salesforceの最新UI/UXを通じてデータにアクセスし、活用する。
アーキテクトの視点から見ると、Salesforce Connectは、ポイントツーポイントのAPI連携や大規模なデータ同期プロジェクトに代わる、エレガントでスケーラブルな統合パターンの一つとして、非常に重要な選択肢となります。
原理説明
Salesforce Connectの核心は、Salesforceプラットフォームと外部データソースとの間に「ライブ接続」を確立することです。ユーザーが外部データにアクセスしようとすると、Salesforceはリアルタイムで外部システムにクエリを送信し、結果を取得して表示します。このプロセスは、主に3つのコンポーネントによって実現されます。
1. 外部データソース (External Data Source)
External Data Source(外部データソース)は、外部システムへの接続設定を定義するコンポーネントです。接続先のURL、認証情報、そして接続に使用するアダプタの種類などをここで設定します。Salesforce Connectは、主に以下のアダプタを提供しています。
- OData 2.0 / OData 4.0: OData (Open Data Protocol) は、RESTful APIを構築・利用するためのISO/IEC承認のOASIS標準です。多くのエンタープライズシステム(SAP、Microsoft Dynamicsなど)がODataをサポートしており、標準的な方法でデータ連携が可能です。これは最も推奨されるアダプタです。
- Cross-Org: 他のSalesforce組織のデータにアクセスするためのアダプタです。複数の組織を持つ企業が、組織間でデータを共有する際に非常に便利です。
- Custom (Apex Connector Framework): ODataをサポートしていないシステムや、独自のロジックを必要とする複雑な連携を実現するために、Apexコードで独自のアダプタを開発することができます。これにより、ほぼすべてのREST/SOAP APIを持つシステムとの接続が可能になります。
2. 外部オブジェクト (External Object)
External Object(外部オブジェクト)は、外部システムのデータテーブルをSalesforceのオブジェクトのようにマッピングするものです。カスタムオブジェクトと同様に、API参照名、項目、ページレイアウト、リレーションなどを定義できますが、データそのものはSalesforceに保存されません。ユーザーが外部オブジェクトのレコードを表示しようとすると、Salesforce Connectが外部データソースの設定を使って外部システムに問い合わせを行います。
3. リレーションシップ
外部オブジェクトをSalesforceの標準オブジェクトやカスタムオブジェクトと連携させるために、3種類のリレーションが用意されています。
- 参照関係 (Lookup Relationships): 標準/カスタムオブジェクトから外部オブジェクトへのリレーションです(例:取引先から外部の注文履歴へ)。
- 外部参照関係 (External Lookup Relationships): 外部オブジェクトから、同じ外部データソース内の別の外部オブジェクトへのリレーションです。
- 間接参照関係 (Indirect Lookup Relationships): 外部オブジェクトから標準/カスタムオブジェクトへのリレーションです。外部オブジェクト側の項目に、SalesforceレコードのIDとして機能する一意の外部ID項目が必要です(例:外部の注文履歴からSalesforceの取引先へ)。
これらのコンポーネントを組み合わせることで、アーキテクトはデータモデルを拡張し、Salesforceを真の「System of Engagement」として、外部の「System of Record」とシームレスに連携させることができるのです。
示例コード (Apex Connector Framework)
標準のODataアダプタで対応できない場合、Apex Connector Framework を使用してカスタムコネクタを開発します。これにより、独自のデータソース(例:社内REST API)への接続が可能になります。以下は、developer.salesforce.comで提供されている、基本的なカスタムコネクタの実装例です。この例では、架空のデータソースからデータを照会(query)するロジックを示しています。
カスタムコネクタは、DataSource.Provider クラスと DataSource.Connection クラスを実装する必要があります。
DataSource.Provider の実装
このクラスは、コネクタの機能(認証など)を宣言し、接続インスタンスを返します。
global class SimpleConnectorProvider implements DataSource.Provider {
// コネクタがサポートする認証機能を返す
// この例では基本的な認証(ユーザー名/パスワード)のみをサポート
override global List<DataSource.AuthenticationCapability> getAuthenticationCapabilities() {
List<DataSource.AuthenticationCapability> capabilities = new List<DataSource.AuthenticationCapability>();
capabilities.add(DataSource.AuthenticationCapability.BASIC);
return capabilities;
}
// コネクタがサポートする機能を返す
// この例では、クエリ時に WHERE句での基本的なフィルタリング (ROW_QUERY) と並び替え (SORTING) をサポート
override global List<DataSource.Capability> getCapabilities() {
List<DataSource.Capability> capabilities = new List<DataSource.Capability>();
capabilities.add(DataSource.Capability.ROW_QUERY);
capabilities.add(DataSource.Capability.SORTING);
return capabilities;
}
// 接続インスタンスを返す
// このメソッドが DataSource.Connection の実装をインスタンス化する
override global DataSource.Connection getConnection(DataSource.ConnectionParams connectionParams) {
return new SimpleConnectorConnection(connectionParams);
}
}
DataSource.Connection の実装
このクラスが、実際のデータ操作(同期、クエリ、検索)ロジックを実装する中心部分です。
global class SimpleConnectorConnection implements DataSource.Connection {
// 接続パラメータを保持するプロパティ
private DataSource.ConnectionParams connectionInfo;
// コンストラクタ
global SimpleConnectorConnection(DataSource.ConnectionParams connectionParams) {
this.connectionInfo = connectionParams;
}
// 外部システムのテーブル定義をSalesforceに同期する
// この例では "Orders" という固定のテーブルを定義
override global List<DataSource.Table> sync() {
List<DataSource.Table> tables = new List<DataSource.Table>();
List<DataSource.Column> columns;
// "Orders" テーブルの列を定義
columns = new List<DataSource.Column>();
columns.add(DataSource.Column.text('OrderID', 255)); // 注文ID
columns.add(DataSource.Column.text('CustomerID', 255)); // 顧客ID
columns.add(DataSource.Column.url('URL')); // 表示URL(必須)
columns.add(DataSource.Column.datetime('OrderDate')); // 注文日
columns.add(DataSource.Column.text('Status', 50)); // ステータス
// テーブルを作成してリストに追加
tables.add(DataSource.Table.create('Orders', 'OrderID', columns));
return tables;
}
// 外部オブジェクトへのクエリリクエストを処理する
// ここで外部APIを呼び出し、データを取得するロジックを実装
override global DataSource.TableResult query(DataSource.QueryContext context) {
// 本来はここでHttp.send()などを用いて外部APIを呼び出す
// 以下はダミーデータの生成ロジック
List<Map<String, Object>> sampleData = new List<Map<String, Object>>();
Map<String, Object> row1 = new Map<String, Object>();
row1.put('OrderID', '1001');
row1.put('CustomerID', 'CUST-001');
row1.put('OrderDate', Datetime.newInstance(2023, 10, 26));
row1.put('Status', 'Shipped');
row1.put('URL', '/services/data/v58.0/sobjects/Orders__x/1001');
sampleData.add(row1);
Map<String, Object> row2 = new Map<String, Object>();
row2.put('OrderID', '1002');
row2.put('CustomerID', 'CUST-002');
row2.put('OrderDate', Datetime.newInstance(2023, 10, 27));
row2.put('Status', 'Processing');
row2.put('URL', '/services/data/v58.0/sobjects/Orders__x/1002');
sampleData.add(row2);
// クエリ結果を DataSource.TableResult として返す
return DataSource.TableResult.get(context, sampleData);
}
// 検索機能を実装(今回は未実装)
override global List<DataSource.TableResult> search(DataSource.SearchContext context) {
return null;
}
}
注意: 上記の query メソッド内のデータはダミーです。実際のプロジェクトでは、Http.send() を使用して外部REST APIエンドポイントを呼び出し、取得したJSONレスポンスをパースして List<Map<String, Object>> 形式に変換する処理を実装します。
注意事項
Salesforce Connectは強力なツールですが、アーキテクトとしてその制約とトレードオフを十分に理解しておく必要があります。
権限とセキュリティ (Permissions and Security)
- 認証: 外部システムへの接続には、必ず指定ログイン情報 (Named Credential) を使用してください。これにより、エンドポイントURLや認証情報をコードから分離でき、セキュリティと管理性が向上します。
- 権限モデル: 外部オブジェクトのアクセス権はSalesforceのプロファイルと権限セットで管理しますが、最終的なデータ可視性は外部システムの権限モデルにも依存します。両方のシステムのセキュリティ設定を考慮した設計が必要です。
API制限とパフォーマンス (API Limits and Performance)
- コールアウト制限: Salesforce Connectによる外部アクセスは、SalesforceのApexコールアウト制限の対象となります。1トランザクションあたりのコールアウト数や時間制限に注意が必要です。
- 外部システムの負荷: 多数のユーザーが同時に外部オブジェクトにアクセスすると、外部システムのAPIが過負荷になる可能性があります。特に、関連リストやレポートでの大量データアクセスには注意が必要です。外部システムのAPIレート制限を必ず確認してください。
- レイテンシ: データはリアルタイムで取得されるため、外部システムからの応答速度が直接UIのパフォーマンスに影響します。ネットワークの遅延や外部システムのパフォーマンスがボトルネックになり得ます。
機能的な制約 (Functional Limitations)
- サポートされない機能: 外部オブジェクトは、Apexトリガ、ワークフロールール(一部)、レコードタイプの完全なサポートなど、標準/カスタムオブジェクトで利用できるすべての機能をサポートしているわけではありません。
- レポートとダッシュボード: 外部オブジェクトのレポートは可能ですが、パフォーマンスが遅くなる傾向があります。大規模なデータセットに対する複雑な集計や分析には不向きです。
- SOQL/SOSL: 外部オブジェクトに対するSOQLクエリには、サポートされる演算子や構文に制限があります。
エラー処理 (Error Handling)
外部システムがダウンしている、または予期せぬエラーを返した場合、ユーザーにはエラーメッセージが表示されます。Apex Connector Frameworkを使用する場合は、try-catch ブロックを適切に実装し、外部システムからのエラーをハンドリングして、ユーザーに分かりやすいフィードバックを提供することが重要です。
まとめとベストプラクティス
Salesforce Connectは、データ仮想化を通じて、外部データをSalesforceにシームレスに統合するための優れたソリューションです。アーキテクトとして、このツールをいつ、どのように使うべきかを正しく判断することが成功の鍵となります。
ベストプラクティス
-
適切なユースケースの選択:
- 推奨: 少量のデータをリアルタイムで参照する必要がある場合。データの鮮度が最優先事項である場合。外部システムへの「窓」として機能させたい場合。
- 非推奨: 大量データのバッチ処理、複雑なデータ変換、オフラインアクセス、または外部データに対する高度な分析やレポートが必要な場合。これらの場合は、伝統的なETL/API統合が依然として最適な選択肢です。
-
パフォーマンスの最適化:
- 外部APIエンドポイントが、フィルタリング、並び替え、ページネーションをサポートしていることを確認します。これにより、不要なデータを転送することなく、Salesforceからの要求に効率的に応答できます。
- ページレイアウトに外部オブジェクトの関連リストを多数配置することは避けてください。ページの読み込みが遅くなる原因となります。
- 標準アダプタを優先: 接続先のシステムがODataをサポートしている場合は、常にODataアダプタを第一選択肢とします。Apexカスタムコネクタの開発は、最後の手段として考えます。
- セキュリティを最優先: 認証には必ず指定ログイン情報を使用し、最小権限の原則に従って外部オブジェクトへのアクセス権を設定します。
結論として、Salesforce Connectは、すべての統合課題に対する万能薬ではありません。しかし、適切なシナリオで適用すれば、開発コストを削減し、データのサイロ化を解消し、ユーザーに統一されたエクスペリエンスを提供するための、非常に強力なアーキテクチャパターンとなり得ます。
コメント
コメントを投稿