「1要件1フロー」に固執して後悔したSalesforce管理者の失敗談

後から「やらなければよかった」と思った設計は、特定のオブジェクトに対して、変更の種類や目的に応じてレコードトリガーフローを細かく分割しまくったことです。特に顕著だったのは、ウチの組織にとって最も重要なオブジェクトの一つであるOpportunity(商談)でした。

「1要件1フロー」という幻想

当初、私はレコードトリガーフローの管理をシンプルに保ちたいと思っていました。「一つの要件には一つのフロー」というルールを自分の中で作り、例えば、以下のようなフローをガンガン作っていきました。

  • 商談のステージが「A」になったらタスクを自動作成するフロー
  • 商談の金額が変更されたら特定の項目を更新するフロー
  • 商談の特定のカスタム項目が更新されたら関係者にChatter投稿するフロー
  • 商談のクローズ日を更新したら関連する別のオブジェクトのレコードをチェックするフロー

これらのフローは、トリガーとなるオブジェクトもレコードトリガーの条件(更新時)も同じなのに、それぞれが独立したフローとして存在していました。当時の私には、これが「分かりやすい」「メンテナンスしやすい」というポジティブな意味合いに映っていたんです。一つのフローが複雑になりすぎず、特定の要件が変わっても他のフローに影響を与えにくい、という思考ですね。

事態が悪化した時の状況

商談に関するビジネスロジックが次々と追加されていくにつれて、この設計が徐々に私を苦しめ始めました。

  • デバッグの悪夢:ユーザーから「商談の更新がなんかおかしい」と報告が来ても、原因がどのフローにあるのか特定するまでに時間がかかりすぎるようになりました。ログを見ても、同じトランザクション内で複数のフローが動いているため、どこで期待しない値になってしまったのか、追いかけるのが本当に大変でした。
  • パフォーマンス劣化:商談の更新時に、複数のフローが同時に起動するわけですから、当然、処理時間が増大しました。特に、関連レコードの更新やループ処理を含むフローがいくつか重なると、トランザクションの時間が無視できないレベルになりました。ユーザーからの「遅い」という声が増え始めたのは、この頃です。
  • 処理順序の予測不能性:「作成または更新されたレコード」で実行するレコードトリガーフローの順序は、設定画面で指定できます。当時はそれが絶対だと思っていました。しかし、実際には異なるトリガーや条件を持つフローが複雑に絡み合うと、私が意図した順序と異なる挙動を示すケースが稀に発生し、混乱しました。特にApexとの連携がある場合は、さらに複雑になります。
  • Governor Limits の恐怖:特にDML操作やSOQLクエリを多用するフローが複数あると、同じトランザクション内でそれらのリミットに近づくリスクが常にありました。実際にエラーには至りませんでしたが、冷や汗をかいた経験は何度もあります。

今なら別の選択をする

もし今、同じ状況に直面したら、私は絶対に「1要件1フロー」というルールは採用しません。少なくとも、同じオブジェクトの同じトリガー(例: 商談更新時)で動くフローは、可能な限り一つにまとめるべきだと考えます。

具体的には、以下のようなアプローチを取ります。

  1. 単一のエントリポイントフロー:特定のオブジェクト・特定のトリガー(例: Opportunityのレコード更新前)に対しては、基本的に一つのレコードトリガーフロー(親フロー)のみを作成します。
  2. サブフローの活用:親フローから、各ビジネスロジックに対応するサブフローを呼び出します。これにより、メインのフローはシンプルに保ちつつ、各ロジックは独立したサブフローとして管理できます。サブフローには適切な条件分岐を設定し、不必要な処理が走らないようにします。
  3. 変数の有効活用:サブフロー間でデータをやり取りするために、入出力変数を適切に設計します。
  4. 設計ドキュメントの整備:フローが複雑になる分、どのフローが何を呼び出し、どのような条件で動くのかを明確にした設計ドキュメントは必須です。これは当時の私には全く足りていませんでした。

これは決して、フローを巨大なモンスターにしろという意味ではありません。あくまで同じトリガーで動くフロー群を「論理的に統合する」という考え方です。

「管理しやすいから」という理由でフローを細分化しすぎた結果、全体としての管理コストとデバッグコストが跳ね上がってしまったのは、私の大きな失敗でした。当時はその場の「分かりやすさ」に目を奪われていましたが、今ならもっと長期的な視点で、システム全体の健全性を優先する判断をするでしょう。

これは当時の自分向けのメモだ。

コメント