Salesforce カスタムオブジェクト:スケーラブルなソリューションを実現するためのアーキテクチャ設計

背景と適用シナリオ

Salesforce アーキテクトとして、我々は日々、クライアントの複雑なビジネス要件を、堅牢でスケーラブルな Salesforce ソリューションに落とし込むという課題に直面しています。その中核をなすのが、Salesforce プラットフォームのデータモデリング能力であり、その心臓部にあるのが Custom Object (カスタムオブジェクト) です。

Salesforce には、Account (取引先)、Contact (取引先責任者)、Opportunity (商談) といった強力な Standard Object (標準オブジェクト) が標準で用意されています。これらは多くのビジネスプロセスに対応可能ですが、現実のビジネスは多種多様です。例えば、プロジェクト管理、資産追跡、イベント登録、品質保証プロセスなど、標準オブジェクトだけでは表現しきれない独自のビジネスエンティティやプロセスが必ず存在します。

このような固有の要件に対応するために、私たちはカスタムオブジェクトを活用します。カスタムオブジェクトは、ビジネスに特化した情報を格納するための、いわばオーダーメイドのデータベーステーブルです。アーキテクトの役割は、単に「カスタムオブジェクトを作成する」ことではありません。「いつ、なぜ、どのようにカスタムオブジェクトを設計し、それがシステム全体のアーキテクチャ、パフォーマンス、保守性にどのような影響を与えるか」を深く理解し、最適なデータモデルを構築することにあります。

このアーティクルでは、Salesforce アーキテクトの視点から、カスタムオブジェクトの設計原理、スケーラビリティを考慮したベストプラクティス、そしてシステム全体に与える影響について深く掘り下げていきます。


原理説明

カスタムオブジェクトの設計は、単なるフィールドの追加作業ではありません。それは、アプリケーション全体の骨格を定義するアーキテクチャ上の重要な意思決定です。

API 参照名とマルチテナントアーキテクチャ

カスタムオブジェクトやカスタムフィールドを作成すると、その API 参照名 (API Name) の末尾には自動的に `__c` というサフィックスが付与されます。これは、Salesforce のマルチテナントアーキテクチャにおいて、顧客が定義したカスタム要素と Salesforce が提供する標準要素を明確に区別するための重要な仕組みです。アーキテクトとして、この命名規則は、インテグレーション、Apex コード、SOQL クエリ、そしてメタデータの移行において、コンポーネントを一意に識別するための基本原則であることを理解しなければなりません。

リレーションシップの選択:アーキテクチャへの影響

オブジェクト間の関連付けを定義するリレーションシップは、データモデルの最も重要な要素の一つです。その選択は、データセキュリティ、UI/UX、そしてレコードのライフサイクルに直接的な影響を及ぼします。

1. Master-Detail Relationship (主従関係)
これは、オブジェクト間に強固な親子関係を構築します。

  • 所有権と共有の継承: 子 (Detail) レコードは、親 (Master) レコードの所有者を継承し、共有設定も親に依存します。子オブジェクトの組織全体のデフォルト (OWD) は「親レコードに連動」に固定され、個別の共有ルールを設定することはできません。これは、セキュリティモデルを簡素化できる一方で、柔軟性を欠く可能性があるため、慎重な検討が必要です。
  • レコードの連動削除: 親レコードを削除すると、関連する全ての子レコードも自動的に削除されます (カスケード削除)。これはデータ整合性を保つ上で強力な機能ですが、意図しないデータ損失のリスクも伴います。
  • 積み上げ集計項目 (Roll-Up Summary Fields): 親オブジェクト上で、子レコードの COUNT、SUM、MIN、MAX などを計算できます。これは、コーディングなしで集計データをリアルタイムに表示できる非常に便利な機能です。
アーキテクチャの観点からは、2つのエンティティがビジネスロジック上、不可分である場合(例:請求書と請求明細)に主従関係を選択します。

2. Lookup Relationship (参照関係)
これは、オブジェクト間に疎結合な関係を構築します。

  • 独立した所有権と共有: 各オブジェクトは独自の所有者を持ち、個別の共有設定が可能です。これにより、柔軟なセキュリティモデルを構築できます。
  • 独立したライフサイクル: 参照先のレコードを削除しても、参照元のレコードは削除されません(参照項目がクリアされる設定は可能)。
  • 柔軟性: 必須ではない関連付けや、自己参照(例:親取引先)、複数のオブジェクトタイプへの参照(ポリモーフィック)など、より柔軟な関連付けが可能です。
エンティティが独立して存在しうるが、関連性を持たせたい場合(例:取引先とサポートケース)に参照関係を選択するのが一般的です。

データ型の選択とデータ整合性

フィールドのデータ型は、データの整合性、ストレージ消費量、そしてレポート作成能力に影響します。例えば、ステータス管理には、自由テキスト入力ではなく選択リスト (Picklist) を使用することで、入力値を標準化し、レポートでのグルーピングを容易にします。数値データには、精度とスケールを正しく設定することが、計算の正確性を保証します。アーキテクトは、将来のビジネス要件の変化も見越して、拡張性のあるデータ型を選択する必要があります。


サンプルコード

アーキテクトは、UI を介した手動設定だけでなく、Metadata API を用いた、プログラムによるスキーマの定義と展開にも精通している必要があります。これにより、CI/CD パイプラインを通じた、一貫性のある、再現可能な環境構築が可能になります。

以下は、プロジェクト管理用の「Project__c」というカスタムオブジェクトと、そのフィールドを Metadata API の XML 形式で定義した例です。このファイルを Ant 移行ツールや Salesforce DX を用いて組織にデプロイします。

Project__c.object-meta.xml

<?xml version="1.0" encoding="UTF-8"?>
<CustomObject xmlns="http://soap.sforce.com/2006/04/metadata">
    <!-- オブジェクト全体の定義 -->
    <label>Project</label> <!-- UI上の表示ラベル -->
    <pluralLabel>Projects</pluralLabel> <!-- UI上の複数形表示ラベル -->
    <nameField>
        <label>Project Name</label>
        <type>Text</type>
    </nameField>
    <deploymentStatus>Deployed</deploymentStatus> <!-- オブジェクトのリリース状況 -->
    <sharingModel>ReadWrite</sharingModel> <!-- 共有モデル(この場合は公開/参照・更新可能) -->
    <enableActivities>true</enableActivities>
    <enableHistory>true</enableHistory> <!-- 項目履歴管理を有効化 -->
</CustomObject>

Project__c オブジェクトのカスタムフィールド定義

通常、これらのフィールド定義は objects/Project__c.object ファイル内に含まれるか、個別の fields/Project__c.Status__c.field-meta.xml のようなファイルとして管理されます。以下は、オブジェクトファイル内に記述する際の例です。

<?xml version="1.0" encoding="UTF-8"?>
<CustomObject xmlns="http://soap.sforce.com/2006/04/metadata">
    <!-- 上記のオブジェクト定義に続けて、フィールドを定義する -->
    
    <!-- プロジェクトのステータスを管理する選択リストフィールド -->
    <fields>
        <fullName>Status__c</fullName>
        <externalId>false</externalId>
        <label>Status</label>
        <required>false</required>
        <trackHistory>true</trackHistory>
        <trackTrending>false</trackTrending>
        <type>Picklist</type>
        <valueSet>
            <restricted>true</restricted>
            <valueSetDefinition>
                <sorted>false</sorted>
                <value>
                    <fullName>Not Started</fullName>
                    <default>true</default>
                    <label>Not Started</label>
                </value>
                <value>
                    <fullName>In Progress</fullName>
                    <default>false</default>
                    <label>In Progress</label>
                </value>
                <value>
                    <fullName>Completed</fullName>
                    <default>false</default>
                    <label>Completed</label>
                </value>
            </valueSetDefinition>
        </valueSet>
    </fields>

    <!-- プロジェクトの開始日を管理する日付フィールド -->
    <fields>
        <fullName>StartDate__c</fullName>
        <externalId>false</externalId>
        <label>Start Date</label>
        <required>true</required>
        <trackHistory>false</trackHistory>
        <trackTrending>false</trackTrending>
        <type>Date</type>
    </fields>

    <!-- ... 他のフィールド定義やオブジェクト設定が続く ... -->
</CustomObject>

注: 上記の XML は Salesforce の Metadata API の公式ドキュメントで定義されているスキーマに基づいています。これにより、宣言的かつバージョン管理可能な方法でデータモデルを構築・維持することが可能になります。


注意事項

カスタムオブジェクトの設計と実装には、プラットフォームの制約と特性を深く理解する必要があります。

権限と共有 (Permissions & Sharing)

新しいカスタムオブジェクトは、デフォルトではどのプロファイルからもアクセスできません。「最小権限の原則」に基づき、オブジェクトへのアクセス(作成、参照、編集、削除)は、プロファイル (Profile) または権限セット (Permission Set) を通じて、明示的に許可する必要があります。また、組織全体のデフォルト (OWD) を「非公開」に設定し、共有ルール (Sharing Rules) や手動共有を用いてアクセスを解放していくアプローチが、セキュリティ上最も安全な設計です。

API 制限とガバナ制限 (API & Governor Limits)

Salesforce プラットフォームは、リソースを公平に分配するために様々なガバナ制限を設けています。

  • オブジェクト数の制限: エディションによって組織で作成できるカスタムオブジェクトの総数には上限があります (例: Enterprise Edition で 200、Unlimited Edition で 2,000)。無計画なオブジェクト作成は、将来の拡張性を損ないます。
  • フィールド数の制限: 1つのオブジェクトに作成できるカスタムフィールドの総数にも上限があります。
  • リレーションシップの制限: 1つのオブジェクトに作成できる参照関係や主従関係の数にも制限があります。特に、主従関係は2つまでという強い制約があります(一部拡張可能)。
アーキテクトは、これらの制限を常に念頭に置き、オブジェクトを正規化しすぎず、かといって一つのオブジェクトに責務を集中させすぎない、バランスの取れた設計を目指す必要があります。

大規模データ量 (Large Data Volumes - LDV)

カスタムオブジェクトに数百万件以上のレコードが格納される可能性がある場合、パフォーマンスへの影響を初期段階から考慮しなければなりません。

  • インデックス (Indexing): SOQL の WHERE 句や、レポートの検索条件で使用されるフィールドには、インデックスを付与することが極めて重要です。外部 ID (External ID) として設定されたフィールドや、主従・参照関係の項目は自動的にインデックスが作成されます。パフォーマンスが低い場合は、Salesforce サポートに依頼してカスタムインデックスを作成する必要があります。
  • データスキュー (Data Skew): 特定の一つの親レコードに、極端に多くの(例えば1万件以上)子レコードが関連付いている状態を指します。これにより、レコードロックの競合が発生し、更新処理のパフォーマンスが著しく低下する可能性があります。データモデル設計の段階で、このようなスキューが発生しないように負荷を分散させるアーキテクチャを検討する必要があります。


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

カスタムオブジェクトは、Salesforce をビジネスに最適化するための強力なツールですが、その力はアーキテクトの設計思想に大きく依存します。スケーラブルで保守性の高いソリューションを構築するためには、以下のベストプラクティスを遵守することが不可欠です。

1. 標準を第一に (Standard First): 新しいカスタムオブジェクトを作成する前に、必ず標準オブジェクトで要件を満たせないか徹底的に検討します。標準オブジェクトは、Salesforce のエコシステム全体(レポート、AI機能など)と深く統合されており、その恩恵を最大限に活用できます。

2. 明確な命名規則の確立: オブジェクトやフィールドの API 参照名、表示ラベルには、一貫性のある明確な命名規則を適用します。これにより、開発者や管理者がシステムの構造を直感的に理解できるようになります。

3. 説明の徹底: すべてのカスタムオブジェクトとカスタムフィールドに、その目的や役割を「説明 (Description)」欄に詳細に記述します。これは、将来の保守担当者にとって最も価値のあるドキュメントとなります。

4. 将来のスケーラビリティを計画: 今日の要件だけでなく、3年後、5年後のデータ量やビジネスプロセスの変化を見据えて設計します。特に、LDV やインテグレーションの可能性を考慮に入れることが重要です。

5. データモデルの文書化: スキーマビルダーや外部のER図ツールなどを用いて、データモデルを視覚的に文書化し、関係者間で共有します。これにより、アーキテクチャの全体像の理解が深まり、より良い意思決定につながります。

Salesforce アーキテクトにとって、カスタムオブジェクトは粘土のようなものです。それをどのようにこね、形作るかによって、生み出されるソリューションの価値と寿命が決定されます。技術的な知識はもちろんのこと、ビジネスへの深い洞察と将来を見通す先見性をもって、一つ一つのカスタムオブジェクトを設計していくことが、我々に課せられた重要な責務なのです。

コメント