Salesforce Spiff の計算でのカプセル化の使用
カプセル化とは、手数料計算の区分を個別の名前付き計算項目に分離することです。この手法により、メモリ使用量が減り、デバッグが簡素化され、読みやすくなり、ビジネスルールの変更に応じて設定が管理しやすくなります。
必要なエディション
| 使用可能なインターフェース: Salesforce Classic (一部の組織で使用可能) および Lightning Experience の両方 |
| 使用可能なエディション: Enterprise Edition、Unlimited Edition、および Developer Edition |
| 有料オプションで使用可能なエディション: Web Services API が有効になっている Professional Edition |
カプセル化とは?
手数料の計算を記述する場合、すべての条件、リレーション、算術演算を組み合わせた 1 つの大きな式を作成しがちです。カプセル化はその逆のアプローチで、ロジックを意味のある最小単位に分割し、各単位に名前を付けて、それらの名前付きピースから最終的な計算を構成します。
カプセル化は計算項目レベルで行われます。適切に構造化された計画では、各計算項目で 1 つの操作が実行されます。下位レベルの計算は上位レベルの計算に入力され、上位レベルの計算は最終的な支払金額に入力されます。
年間経常収益 (ARR) に対する営業担当の取り分がしきい値を超えている場合に、現在の期間に完了した分割商談に対して営業担当に手数料を支払う計画について考えてみます。カプセル化を使用しない場合、1 つの式ですべての条件とすべての算術ステップが結合されます。
Calculated field, without encapsulation:
=if(CloseDate >= BeginningOfPeriod
AND CloseDate <= EndOfPeriod
AND OwnerId == UserId
AND ContractLength_Months__c > 12
AND Split_Percent__c != null
AND (Split_Percent__c * ARR) >= 20000,
Split_Percent__c * ARR * CommissionRate,
0)この式は読みづらく、追跡も難しく、壊れやすいものです。項目の名前を変更すると、その項目を参照するすべての計算を見つけて編集する必要があります。
カプセル化を使用すると、各条件と各計算値が独自の名前付き項目になります。最終的な支払式は、これらの名前付き項目から直接読み取られます。
次の例では、検索条件式と計算項目の両方を使用します。filter 式は true または false を返し、Boolean ロジックのみを使用します。if() ステートメントはサポートされません。計算項目は値を返し、完全な式構文をサポートします。どちらの場合もカプセル化の利点を得られますが、異なる理由があります。計算項目にはパフォーマンス上の利点があります (エンジンで各項目を評価して結果を保存する場合)。一方、検索条件式には構造上の利点があります (読みやすく、管理しやすく、更新しやすい)。
With encapsulation:
// Step 1 — Qualify the period (filter expression)
ClosedInPeriod = CloseDate >= BeginningOfPeriod
AND CloseDate <= EndOfPeriod
// Step 2 — Qualify the rep and deal type (filter expression)
ByRepMultiYear = OwnerId == UserId
AND ContractLength_Months__c > 12
// Step 3 — Compute the split amount (calculated field)
SplitARR = Split_Percent__c * ARR
// Step 4 — Qualify the threshold (filter expression)
SplitARREligible = Split_Percent__c != null
AND SplitARR >= 20000
// Step 5 — Final payout (calculated field)
Payout = if(ClosedInPeriod AND ByRepMultiYear AND SplitARREligible,
SplitARR * CommissionRate,
0)計算済み項目の場合、手数料エンジンは各項目を 1 回評価し、その結果を保存します。後続の参照では、ロジックを再計算するのではなく、保存された値が参照されます。検索条件の構造に関係なく、検索条件は常に全体として実行されるため、検索条件式ではこの動作は共有されません。
Payout 項目は、同じ算術比較と日付比較をインラインで再計算するのではなく、4 つの名前付き値を読み取ります。Split_Percent__cの名前を変更して、SplitARRとSplitARREligibleのみを更新しても、支払式は影響を受けません。
カプセル化の利点
カプセル化には、モノリス式よりも次のような利点があります。
- メモリ効率。手数料エンジンは、ステートメントごとに 1 回カプセル化された計算を実行し、結果を保存します。後続の計算参照では、ロジックを再計算するのではなく、保存された結果が参照されます。このアプローチは、大規模なデータセットやトラバースリレーションを参照する計算で特に有用です。
- トラブルシューティングが容易。支払が正しくない場合、各指定計算を個別に追跡し、ロジックが期待と異なっている箇所を見つけます。前の例では、
ClosedInPeriod、SplitARR、およびSplitARREligibleを個別に追跡して、どの条件がレコードを誤って除外または包含しているかを特定します。一体式は、手数料エンジンで 1 つの単位として評価されるため、検査が困難です。 - 合理化されたレポート。名前付き計算項目は、スピフレポートの個別のデータポイントとして使用できます。モノリス式は最終出力のみを生成します。カプセル化された項目により、中間値を表示できます。たとえば、支払対象資格とは無関係に
SplitARRに関するレポートを作成できます。 - 読みやすさの向上。
SplitARR * CommissionRateを読み取る最終的な支払計算は、同等のネストされた式よりもはるかにわかりやすくなります。名前付き項目は、今後計画を確認するすべてのユーザーにインテントを伝えます。 - 拡張性。コネクタ項目が変更されたり、ビジネスルールを更新したりする場合、適切にカプセル化された設定では 1 か所での変更が必要になります。前の例では、対象資格しきい値を 20,000 から 25,000 に変更すると、
SplitARREligibleのみの更新になります。しきい値をインラインで埋め込むモノリス式では、それを含むすべての検索条件と計算を見つけて編集する必要があります。
リレーションへのカプセル化の適用
オブジェクト間のリレーションは、カプセル化を適用する最も重要な場所の 1 つです。計算が項目を取得するためにリレーションを移動するたびに、メモリと処理時間が消費されます。リレーションコールをカプセル化すると、作業が 1 回だけ実行されます。
関連オブジェクトを使用するときは、次の方法を考慮してください。
- 使用可能な場合はダイレクト・パスを使用します。商談商品と商談分割のデータが必要な場合は、商談オブジェクトを介してルーティングするのではなく、直接 OppProduct と商談分割のリレーションを使用します。パスが短いほど、トラバースが少なくなります。
- 自己参照関係を使用します。OppToAccount と AccountToOpps を 2 つの個別のリレーションとして作成する代わりに、一意のキーが AccountId である OppToOpp リレーションを作成します。この方法では、1 つのリレーション定義で同じ結果になります。
- 関連オブジェクトで計算を実行します。現在のオブジェクトの計算で関連オブジェクトから 3 つの項目を取得して組み合わせるのではなく、必要な値を生成する計算項目を関連オブジェクトに作成します。次に、リレーションを使用してその 1 つの項目を参照します。1 つの項目を取得する 1 つのリレーションコールは、複数の項目を取得する 1 つのリレーションコールよりもコストが低くなります。
たとえば、OppSplit.SplitPercentとOppSplit.ARRをリレーションを介して個別に参照し、商談の計算でそれらを乗算するのではなく、商談分割オブジェクトでSplitARR計算項目を作成します。次に、商談の計算では、1 つのリレーションコールを実行して 1 つの事前計算済み値を参照します。
Less efficient — two relationship traversals per record:
Payout = OppSplit.SplitPercent * OppSplit.ARR * Rate
More efficient — one relationship traversal per record:
// On OppSplit object:
SplitARR = SplitPercent * ARR
// On Opportunity object:
Payout = OppSplit.SplitARR * Rateキャプチャトレースを使用したカプセル化の適用
カプセル化とトレースは連携します。カプセル化された計算は個別の名前付き項目であり、項目は個別で明示的に識別されるため、項目レベルで追跡を選択的に有効にできます。営業担当が参照する必要のない、大規模なデータセットが含まれる中間計算の追跡を無効にできます。営業担当が明細書を確認する最終的な支払金額と主要な評価指標の追跡を有効にします。
| 計算種別 | おすすめの追跡 | 理由 |
|---|---|---|
| リレーションのトラバース | 無効化 | トラバースごとに追加データが保存されます。リレーション項目の追跡をオフにして、ステートメントあたりのメモリ消費量を減らします。 |
| 累積変数 | 無効化 | 累積変数はレコードをループし、中間値を保存します。これらを追跡すると、内部ロジック担当者が不要になり、メモリ使用量が大幅に増加します。 |
| 二重条件 | 無効化 | 二重条件には、中間集計と ID リストが含まれます。これらのステップを追跡すると、役に立つコンテキストを追加せずに担当者ビューにノイズが発生します。 |
sum()、count()、let() 関数 |
無効化 | これらの集計関数は、大規模なレコードセットで動作します。トレースには、評価されたすべてのレコードのデータが保存されます。レコード数が多いほど、このデータはコスト高になります。 |
| YTD および大規模データセットの計算 | 無効化 | 過去 1 年間または過去 4 四半期の合計で、大量の履歴レコードがスキャンされます。そのセットのすべてのレコードの追跡を保存すると、大量のメモリが消費されます。ステートメントに出力値を表示しますが、エンジンに完全な内部履歴が保存されないようにします。 |
| レートテーブル、目標データ、またはその他の機密値 | 無効化 | [トレース] を使用すると、ステートメントビューとエクスポートで中間値が営業担当に表示されます。営業担当が属していないプランの料金や目標など、営業担当が参照できないデータを参照する項目の追跡を無効にします。 |
| 最終的な支払項目と担当者向け評価指標 | オン | 営業担当は追跡を使用して、手数料の計算方法を把握します。ステートメント評価指標カードと義務リストに表示される値、およびレポートとエクスポートで報奨金管理者が必要とする項目の追跡を有効にします。 |
たとえば、支払ロジックに中間ステップとして過去 1 年間の累計金額が含まれている場合、追跡を無効にしてその累計金額を独自の項目としてカプセル化します。参照するPayout項目はトレースを有効にしたままにしておくことができるため、内部蓄積ロジックを公開することなく、営業担当に最終的な数値を提供できます。
// YTDCommissions — turn off trace (large dataset, internal only)
YTDCommissions = amounts_from(beginning_of_year(BeginningOfPeriod),
days_ago(BeginningOfPeriod, 1),
plan_name)
// CurrentPeriodPayout — turn on trace (rep-facing)
CurrentPeriodPayout = SplitARR * CommissionRate
// YTDTotal — turn on trace (rep-facing summary metric)
YTDTotal = YTDCommissions + CurrentPeriodPayout
