私は Salesforce 管理者として、Sales Cloud の初期導入から様々な自動化を経験してきた。特に忘れられない「やらかし」は、ワークフロールールからプロセスビルダーへ移行した際の判断ミスだ。
当時、ワークフロールールだけでは実現できない複雑なビジネスロジックが次々と求められ、「もっと柔軟で強力な自動化ツールはないのか」と常に考えていた。そこに現れたのがプロセスビルダーだった。GUIベースで複数アクションを組み合わせられるプロセスビルダーは、まさに夢のツールに見えた。
プロセスビルダーへの過度な期待と、その末路
「これならApexを書かずに何でもできる!」と私は興奮し、商談オブジェクトに関するあらゆる自動化要件をプロセスビルダーに詰め込み始めた。
- 商談のフェーズが「Closed Won」になったら、関連する契約オブジェクトを自動作成し、契約担当者チームにChatterで通知。
- 商談の金額が一定以上で、かつ特定の製品ラインが含まれていたら、承認プロセスを開始し、特定のタスクを営業部長に割り当てる。
- 商談の更新日付が30日以上前だったら、担当者にメールアラートを送信し、活動予定を作成。
このようなロジックを、1つのオブジェクトに対して複数のプロセスビルダーで実装していった。当初は「条件が明確に分かれているから大丈夫だろう」と安易に考えていた。例えば、商談の更新トリガーで動くプロセスが3つ、それぞれ別の条件で発火する、という設計だ。
しかし、これが大きな落とし穴だった。それぞれのプロセスが独立しているようでいて、実際には同じトランザクション内で動き、互いのフィールド更新が別のプロセスの発火条件になってしまう、という事態が頻発した。特にやっかいだったのは、AプロセスがフィールドXを更新し、それがBプロセスの発火条件になっていて、BプロセスがフィールドYを更新し、それがAプロセスの別の条件を満たしてさらにAプロセスが再発火、といった無限ループに近い挙動だ。もちろんGovernor Limitsに抵触してエラーになることもあったが、それ以前に意図しない挙動の方が深刻だった。
予期せぬ挙動とデバッグの泥沼
現場からは「この商談、フェーズ変えただけなのに何でこのタスクが二重に作られるんだ?」とか「特定のユーザーだと動くのに、別のユーザーだと動かない」といった問い合わせが急増した。ログを見ると、複数プロセスが同じトランザクション内で発火していることはわかる。だが、どのプロセスがどの順番で、どのフィールドを更新し、それが別のプロセスのどの条件を満たして再発火したのかを追跡するのは、まさに泥沼だった。プロセスビルダーの実行順序は制御が難しく、公式ドキュメントに記載されているルール(例えば、トリガーは特定の順番で発火する、など)を完全に理解していても、複雑に絡み合ったプロセス間での相互作用を予測するのは至難の業だった。
特にデバッグで苦労したのは、時間ベースのアクションだった。ある条件を満たしたら「X日後にYを実行」といった設定は、デバッグログでリアルタイムに追うことができず、テスト環境でひたすら時間を進めるか、待つしかなかった。このあたりの「不確実性」が常に付きまとった。
フローという選択肢の出現と、深く後悔したこと
そんな中、フロー(特にレコードトリガフロー)が強力なツールとして進化し始めた。Apexトリガーに近い制御が可能で、エラーハンドリングもプロセスビルダーより格段に優れていると知った時、私は「これだ!」と直感した。
フローは、プロセスの実行順序、複雑なデータ処理、エラーハンドリングといった点で、プロセスビルダーを圧倒的に凌駕していた。特に、同じオブジェクトに対する複数の自動化ロジックを、一つのフローに集約して管理できる点は目から鱗だった。Before-Save/After-Saveの概念も導入され、Apex開発者が行っていたような細かい制御が宣言的に可能になったのだ。
しかし、私の組織ではすでに大量のプロセスビルダーが稼働しており、それらをフローに移行する作業は想像を絶する大変さだった。ビジネスロジックを一つ一つ洗い出し、フローで再構築し、テストをする。この移行プロジェクトは数ヶ月単位の大規模なものとなり、組織に大きな負担をかけた。「もし、最初からフローの可能性をもっと真剣に検討していれば、これほどの技術的負債を抱えることはなかっただろう」と深く後悔した。
当時の私は、プロセスビルダーの「手軽さ」に惹かれすぎた。学習コストや開発効率の面では優れているように見えたが、長期的なメンテナンス性やパフォーマンス、複雑な要件への対応力を考えると、フローに軍配が上がった。
当時の判断は、新しいツールへの期待と、その潜在的な課題を見極めきれなかった私の未熟さから来ている。
今の判断基準:フローファースト
今なら、新しい自動化要件に対しては、まずフローを検討する。ほぼ全てのケースでフローを主軸に設計するだろう。プロセスビルダーは、極めて単純な単一オブジェクトのフィールド更新や、関連レコードへのごく簡単なアクションに限定する。それも、既存のものがなければ新たにプロセスビルダーを作成することはほぼない。
特に「レコードトリガフロー」の登場はゲームチェンジャーだった。オブジェクトごとに1つのトリガーフローに集約し、その中で様々な条件分岐を行うことで、実行順序の問題やパフォーマンス劣化を大幅に軽減できるようになった。これにより、デバッグも格段に楽になった。
Governor Limits に関しては、プロセスビルダーが複数発火すると、それぞれのプロセスがDML操作やSOQLクエリを独立して実行するため、総和としてリミットに抵触しやすかった。一方でフローは、一つのトランザクション内でより効率的に多くの処理を行えるよう設計されている。特にBefore-Saveフローは、DML操作を伴わないフィールド更新が可能で、パフォーマンス最適化に大きく寄与する。
具体的に、複雑な処理をフローに移行する際、以下のような構造を採用することが多い。
// 例:商談オブジェクトのレコードトリガフロー
// 実行条件:レコードが作成または更新された時
// 実行タイミング:レコードが保存される前 (Before Save)
// ロジック例1: 特定のフェーズに達したらフィールドを更新
if (NOT(ISBLANK({!$Record.StageName})) &&
(ISCHANGED({!$Record.StageName}) || ISNEW()) &&
OR(ISPICKVAL({!$Record.StageName}, 'Qualification'), ISPICKVAL({!$Record.StageName}, 'Needs Analysis'))) {
// 関連フィールドの値を初期化・更新する
{!$Record.Next_Steps__c} = '顧客にアプローチ';
{!$Record.Probability} = 50;
}
// ロジック例2: 特定の金額を超えたら優先度を高く設定
if (NOT(ISBLANK({!$Record.Amount})) &&
(ISCHANGED({!$Record.Amount}) || ISNEW()) &&
{!$Record.Amount} >= 100000) {
{!$Record.Priority__c} = 'High';
}
// ...他のBefore Saveロジック...
// レコードが保存された後 (After Save)
// ロジック例3: フェーズ変更後にChatter投稿とタスク作成
if (ISCHANGED({!$Record.StageName}) &&
ISPICKVAL({!$Record.StageName}, 'Closed Won')) {
// Chatter投稿
// タスク作成 (Create Records要素)
// メール送信 (Send Email要素)
}
これはあくまで概念的なコードだが、このように一つのフローで様々な処理を統括することで、ロジックの可視性が向上し、デバッグもしやすくなった。今なら、オブジェクトに対して複数の自動化が存在する場合、**必ず1つのレコードトリガフローに集約する** ことを強く推奨する。
これは当時の自分向けのメモだ。
コメント
コメントを投稿