ストラングラーフィグパターン入門 - レガシーを段階的に置き換える

11分 で読める | 2026.04.10

公式ドキュメント

ストラングラーフィグパターンは、旧システムを一度に置き換えず、入口でrequestを振り分けながら機能を一つずつ新システムへ移す方法です。

新旧を長く並べることが目的ではありません。小さく切り替え、観測し、必要なら戻し、最終的に旧機能を撤去できることが中心です。

基本の流れ

入口で小さな機能単位の通信を旧システムから新システムへ観測しながら順番に切り替え、最後に旧機能を撤去する図

  1. 旧システムの前にrouterまたはfacadeを置く
  2. 最初はすべて旧システムへ通す
  3. 小さなbusiness capabilityを新システムへ実装する
  4. 一部trafficまたは特定routeだけ新側へ切り替える
  5. 結果と運用を確認し、旧側へ戻せる期間を取る
  6. 新側を正とした後、旧実装と移行用部品を撤去する

「画面」「DB table」「class」より、利用者に価値を返す機能単位で切り出します。たとえば商品検索は、注文確定より副作用が少なく、最初の候補にしやすい場合があります。

routerで切り替え境界を作る

routerはURL、header、利用者group、feature flagなどで新旧へ振り分けます。

GET /catalog/*  -> new catalog service
POST /orders/* -> legacy application
other routes   -> legacy application

route規則を一か所へ集め、変更履歴と現在値を確認できるようにします。複数のproxyやapplication codeへ分散すると、どちらが処理したか追えません。

切り替え時は次をtelemetryへ残します。

  • route先(legacy/new)
  • migration ruleのversion
  • response statusとlatency
  • request/trace ID
  • fallbackまたは切り戻しの発生

認証情報や個人情報をrouting logへそのまま残しません。

最初の機能を選ぶ

最初から最重要の決済を選ぶ必要はありません。次を満たす候補を探します。

  • 入出力と依存先を説明できる
  • 旧システム内の変更が比較的少ない
  • 成功条件を自動または手作業で比較できる
  • 独立したrouting ruleを作れる
  • 失敗時に旧側へ戻す意味が明確

価値がまったくない内部機能だけでは移行の学びが得にくく、複雑すぎる中心機能では境界作りに失敗しやすくなります。「小さいが本番価値がある」単位を選びます。

rollbackはroutingだけでは完了しない

新側のread-only機能なら、routeを旧側へ戻すだけで切り戻せる場合があります。書き込み機能では、新側が作ったデータを旧側が読めるかが問題です。

次のどれかがあると、単純なroute rollbackは危険です。

  • 新側だけが知るschemaで書いた
  • 外部へメール・決済・通知を送った
  • queue eventを発行した
  • 旧側と新側の両方が同じデータを更新した

切り替え前に「routeを戻した後、作成済みデータと副作用をどう扱うか」を試します。後方互換なschema、idempotency、処理済みeventの記録が必要です。

データ境界を決める

最も難しいのはcodeよりdataです。移行中の代表的な選択肢があります。

旧DBを一時的に共有する

新serviceが旧DBを読むと早く移行できますが、schema couplingが残ります。新serviceが旧tableへ自由に書き始めると、独立性が得られません。利用範囲と終了日を決めた一時策として扱います。

新側へdataを複製する

CDCやeventで新storeへ反映します。伝播遅延、順序、重複、schema変更、再同期が必要です。新側がread modelだけを持つ段階なら適用しやすい場合があります。

所有権を移す

ある機能の書き込みを新側だけへ切り替え、旧側はAPIやanti-corruption layer経由で参照します。最終形に近い一方、依存関係を洗い出してから切り替える必要があります。

同じfieldを新旧双方が自由に更新するdual writeは、片方だけ成功した時の修復が難しくなります。 必要ならoutbox、idempotent consumer、reconciliation jobなどを設計し、「常に同時成功する」と仮定しません。

shadow trafficの注意

同じread requestを新旧へ送り、responseを比較するshadow方式は検証に役立ちます。ただし、write requestをそのまま二重実行すると二重課金や二重通知が起きます。

shadow側はresponseを利用者へ返さず、timeoutやresource消費が本番側へ影響しないようにします。個人情報を別環境へ複製できるか、外部APIを呼ばないかも確認します。

比較ではJSON文字列の完全一致だけでなく、順序、時刻、生成IDなど許容差を定義します。

段階的な切り替え

一つのrouteを次の順で広げられます。

0%: shadowで比較
1%: 内部利用者だけnew
10%: 限定した利用者group
50%: error/latency/業務結果を監視
100%: newを正とする
retire: legacy routeとcodeを削除

割合は例であり、必ずこの順にする必要はありません。各段階の継続時間、進む条件、戻す条件を先に決めます。trafficが少ない機能では割合より、内部利用者や特定tenantで分ける方が観測しやすい場合があります。

完了条件を決める

Strangler移行が終わらない最大の原因は、「新側が動く」を完了とし、旧側と移行部品を残すことです。機能ごとに次を管理します。

  • 新側へrouting済み
  • data所有者が一つに決まった
  • 旧側へのcallとDB accessが0になった
  • rollback期間が終わった
  • 旧code、flag、proxy rule、同期jobを削除した
  • dashboard、alert、runbookを新側へ更新した

旧側への新機能追加を全面禁止できない場合もあります。重大bug修正や法令対応は必要です。新旧どちらへ変更するか、移行中の差分をどう反映するかを明示します。

採用しない条件

  • requestを振り分ける安定した境界を作れない
  • 新旧の共存が法令・data制約上許されない
  • 短期間で停止できる小規模systemで、段階移行の基盤の方が高コスト
  • 旧仕様が不明で、比較可能な成功条件もない

最後のケースでは、先に旧systemの観測、characterization test、data調査を行います。Strangler pattern自体が仕様を発見してくれるわけではありません。

よくある誤解

  • microservices化が必須:新側もmodular monolithで構いません。
  • proxyを置けば移行できる:data ownershipと副作用の境界が必要です。
  • routeを戻せばrollback完了:新側の書き込みと外部副作用を確認します。
  • 新旧の二重運用は安全:期間が長いほど運用、security、data同期の負担が増えます。
  • 最後に旧systemを消せばよい:機能ごとに旧codeと移行部品を撤去します。

まとめ

Strangler Figは、入口でroutingし、小さな機能を新側へ移し、観測とrollbackを繰り返す移行patternです。成功の鍵は、route切り替えだけでなくdataの所有者、書き込みの副作用、撤去条件を機能ごとに決めることです。

参考リソース

次に読む記事

← 一覧に戻る
PR
PR
PR
PR