Shopify Flowの「コード実行(Run Code)」アクションによるエンタープライズ級ロジックの構築
こんにちは、Flagshipのフロントエンドデベロッパー、Rossellaです。この記事では、Shopify Flow を単なる自動化ツールとしてではなく、より高度な開発プラットフォームとして活用した実例をご紹介します。
Shopifyは、個人起業家からフォーチュン500に名を連ねるブランドまで、数百万ものオンラインストアを支えています。Eコマースプラットフォームとして、商品カタログ、ショッピングカート、決済処理といった標準機能をそのまま提供していますが、その真の強みは拡張性にあります。開発者はカスタムフロントエンドを構築し、外部APIを統合し、アプリや連携を通じて洗練されたビジネスロジックを作り出すことができます。
Shopifyのネイティブツールの1つに、プラットフォームに組み込まれた無料の自動化エンジンであるShopify Flowがあります。表面上、Flowはノーコード・ソリューションに見えます。トリガー、条件、アクションをドラッグ&ドロップしてワークフローを構築します。例えば、500ドル以上購入した顧客にタグを付ける、在庫が少なくなったらメールを送信する、特定の倉庫に対して注文を自動フルフィルメントするといった具合です。
これらのビジュアルビルダーにより、一般的なEコマースの自動化は開発者以外の人々にとっても身近なものになりました。
しかし、Flowにはほとんどのユーザーが気づかない機能があります。それが「コード実行(Run Code)」アクションです。この唯一の機能が、Flowを単なる自動化ツールから、本物のプログラミングと視覚的なワークフロー調整が融合したハイブリッド開発プラットフォームへと変貌させます。Flowのステップ内で直接JavaScriptを記述でき、Shopifyのインフラを維持したまま、必要な場所にカスタムロジックを追加できるのです。
これは、顧客データ、注文、そしてフル機能のAdmin APIに直接アクセスしながら、Shopifyのネイティブなエコシステム内でエンタープライズレベルのロジックを構築する方法です。
ここでは、通常であればカスタムバックエンド・インフラ(複雑な計算、複数システム間にまたがる状態管理、外部APIとの統合)を必要とする問題を、すべてShopify Flowを通じてどのように解決したかを紹介します。
複雑な状態管理と外部連携の融合
プロジェクトの内容:外部プラットフォームと連携する顧客メンバーシップ・システムの構築。その外部APIが顧客ティアを計算し、特典を割り当てます。Shopifyはそのデータを取得・表示し、複数のストアフロント(オンラインストアおよびShopify POS)にわたる特典の使用状況を追跡し、すべての状態変化をシステム間で一貫させる必要がありました。
このシステムには、時間ベースの優先順位付けロジック(どの年の割り当て分を先に消費するか)、消費ルールの異なる複数のリソースタイプ、年度末の繰り越し自動化、そして完全な監査証跡が求められました。また、地域による差異を伴う複数のShopifyインスタンスへの展開も必要でした。市場ごとに異なる特典適用方法が必要とされる一方で、コアとなるロジックは一貫性を保たなければなりませんでした。そして、すべてがリアルタイムで実行され、顧客向けの表示には現在の状態が即座に反映され、アクションとデータ更新の間に遅延が許されない状況でした。
問いは技術的なことではなく、アーキテクチャに関するものでした。カスタムインフラを構築すべきか、それともShopifyのネイティブ機能を活用すべきか?
意思決定の枠組み:構築かプラットフォームか
カスタムバックエンドを作れば完全な制御が可能になりますが、それはインフラ管理、デプロイパイプライン、継続的なメンテナンスを意味します。Shopifyのネイティブツールは、迅速なデプロイと自動スケーリングを提供してくれますが、果たしてこの複雑さに耐えられるのでしょうか?
標準的なFlowアクションは単純な操作を扱いますが、複雑な計算、JSON操作、複数のメタフィールドにまたがる条件ロジックには、本物のプログラミングが必要です。
そこでコード実行(Run Code)の出番となります。
アプローチの検証
アーキテクチャを決定する前に、一連の小さな概念実証(PoC)用Flowを構築しました。
すべてを解決しようとしたわけではありません。ただ、いくつかの具体的な疑問に答える必要がありました:
- 「コード実行」で複雑なJSONを扱えるか?
- LIFOロジックを確実に実装できるか?
- 構造化された出力を後続のFlowステップに渡せるか?
- GraphQL経由で必要な情報をすべてクエリできるか?
これらが機能することが確認できると、決断はより明確になりました。
アーキテクチャの決定:
プラットフォームはすでに必要なものの80%を提供しており、ビジュアルビルダーでは扱えない複雑なロジックの隙間を「コード実行」が埋めることができる。
構築したもの:ハイレベル・アーキテクチャ
このソリューションでは、Flowのビジュアルビルダーとプログラミングレイヤーの両方を端から端まで使用しました。
ビジュアルアクションがワークフローの調整を担当しました。イベントでのトリガー、条件に基づく分岐、メタフィールドへの書き込みやタグ追加といった標準操作の実行です。一方、「コード実行」アクションが複雑なロジックを担当しました。LIFO消費アルゴリズム、監査証跡のためのJSON操作、複数のメタフィールドにわたる状態計算、固有のディスカウントコードのためのハッシュ関数などです。
顧客メタフィールドには、Flowのワークフローとテーマレイヤーの両方からアクセス可能なすべての情報(特典残高、利用履歴、ティア情報)を保存しました。これが顧客の特典ステータスに関する「信頼できる唯一の情報源(Single Source of Truth)」となりました。
外部データベースも、カスタムバックエンドもありません。ただShopifyを、通常より少し先まで使い倒しただけです。
プラットフォームの制約内での作業
Shopify Flowは完璧ではありません。私たちは創造的な解決策を必要とする現実的な制限に直面しました。
メタフィールドのトリガー問題。 Flowはメタフィールドの変更を直接トリガーにすることができません。外部APIが顧客の特典割り当てを更新した際、Flowにはそれに反応するネイティブな方法がありませんでした。解決策として「顧客セグメント」を変化検知に利用しました。メタフィールドが変更されると、顧客がセグメントに入ったり外れたりするため、それをFlowのトリガーとしたのです。理想的ではありませんが、機能しました。私たちが発見したパターンは、「セグメントは、本来の目的ではなくても、実質的にメタフィールドの変更を『監視』できる」ということです。
破損した状態でのテスト。 Flowのテストモードは現在のストアの状態を使用します。バグのあるFlowの実行によって顧客データが破損した場合(例えば、アクションの結果としてメタフィールドが誤って編集された場合)、その後の修正のテストが不可能になります。テストが、入力としてすでに間違っている値を使用してしまうからです。修正したロジックを検証するには、クリーンなデータが必要でした。
解決策:
- さまざまな「コード実行」アクションをGitHubリポジトリに抽出する
- バグが発生する前の顧客データや注文データを模したサンプルJSONデータを含むテストスクリプトを作成する
- ターミナルでロジックをテストし、検証が済んだときのみデプロイする
思わぬ副産物として、Flowロジックのバージョン管理と完全な開発履歴が得られました。これらは場当たり的なハックではありません。プラットフォームの限界を理解したときに浮かび上がってきたパターンなのです。
戦略的視点:コードを書かないタイミングを知る
プラットフォーム開発における真のスキルは、単にコードを書くことではありません。それは「いつコードを書かないか」を知ることです。
Flowのビジュアルアクションは、私たちが必要としたものの80%(ワークフローの調整、条件ロジック、メタフィールドの更新、タグ管理、API呼び出し)をすでに担っていました。「コード実行」は、ビジュアルビルダーでは表現できなかった残りの20%の隙間、つまりビジネスロジックを埋めました。LIFOアルゴリズム、状態計算、監査証跡。すべてが同じプラットフォーム内に収まっています。
カスタムバックエンドでも機能したでしょうが、それはFlowがすでに提供しているインフラを構築し、維持することを意味したはずです。
このプロジェクトで最も興味深かったのは、コードそのものではありません。ゼロから構築する必要がないものがどれほど多いかに気づいたことでした。Flowはオーケストレーション、ストレージへのアクセス、そしてスケーリングを与えてくれました。「コード実行」によって、プラットフォームを離れることなく、必要な場所に正確にカスタムロジックを追加することができたのです。
難しいのは「これを作れるか?」ということではありません。
「いつ作らないか」を知ることなのです。