
はじめに
こんにちは、カート決済部カート決済基盤ブロックの林です。普段はZOZOTOWN内のカート機能や決済機能の開発、保守運用、リプレイスを担当しています。
ZOZOTOWNの購入フローは、セッションに強く依存したロジックが長年の改修により肥大化し、機能改善や保守の際の調査・改修コストが増大していました。この課題を解決するため、私たちのチームは2024年5月から約2年にわたる段階的なリプレイスプロジェクトを進めています。
ミッションクリティカルな購入フローを無停止で移行するため、私たちは3つのフェーズに分けた段階的なアプローチを採用しました。本記事では、その実践的な進め方と、実際に直面した課題について紹介します。
なお、同じチームの多田と三浦が、このリプレイスにおけるアーキテクチャ選択(モジュラモノリス)の背景と設計について別の記事で紹介していますので、併せてご覧ください。
目次
- はじめに
- 目次
- 背景・課題
- 新システムの構成とセッション問題の解決
- リプレイス戦略の全体像
- フェーズ1:一部機能の比較フェーズ
- フェーズ2:段階的な入れ替えフェーズ
- フェーズ3:全体リプレイス
- 今後の展望
- まとめ
背景・課題
セッションに依存したロジックの肥大化
ZOZOTOWNの購入フローは、Classic ASP(以下、ASP)で実装されており、長年の改修によりセッション情報がいたるところで更新される構造になっていました。この結果、ロジック間の依存関係が複雑化し、機能改善や保守の際の調査コストが増大するとともに、部分的な入れ替えも困難な状態でした。
サービス無停止でのリプレイス要件
ZOZOTOWNの購入フローは、ECサイトの中核をなすミッションクリティカルな領域のため、サービスを停止できません。さらに、リプレイス期間中であっても、新規機能の追加や運用改善は継続的に発生し、それらは既存ロジック側とリプレイス側のどちらにも反映する必要がありました。
その結果、移行にあたっては以下の制約を考慮する必要がありました。
- ビッグバン切替の回避:一括での全面切り替えはリスクが高すぎる
- 二重開発の不可避:新旧両システムを並走する以上、修正は両方に入れる必要がある
- 段階的検証の必須化:各段階で十分に検証しながら、慎重に移行を進める必要がある
これらの課題に対し、私たちは新システムの構築と段階的な移行戦略により解決を図りました。
新システムの構成とセッション問題の解決
既存システムの問題点
既存のASPシステムでは、購入フロー内のいたるところでセッション情報が更新される構造になっており、以下の問題がありました。
1. セッション更新の分散
- どのタイミングで何が更新されるか追跡困難
- 機能改善時の影響範囲を特定しづらい
- デバッグやトラブルシューティングに時間がかかる
2. 部分的な入れ替えの困難さ
- セッション情報と密結合しているため、機能単位での切り出しが難しい
- 段階的なリプレイスを阻害する要因
3. 保守性の低下
- 新規メンバーがシステムを理解するのに時間がかかる
- セッション構造の変更が困難
新システムの構成
これらの問題を解決するため、責務を明確に分離した構成を採用しました。

既存システム(リプレイス前)
- ASP
- すべてのロジックとセッション管理が密結合
新システム(リプレイス後)
- 画面層(以下、Shopping BFF)
- ユーザーの入力値や購入フロー内の一時的な状態を管理
- セッションで管理していた情報を専用のRedisで管理(購入フローに閉じた情報のみ)
- Java/Spring Boot
- ビジネスロジック層(以下、Shopping API)
- ビジネスロジックの中核を担う
- カート、注文、決済などのドメインロジックを実装
- Java/Spring Boot、モジュラモノリス構成
Shopping BFF + Redisによる解決
新システムでは、Shopping BFFで状態管理を集約する構成にしました。
設計方針
購入フローに閉じた情報のみをBFFで管理
- 他のサービスと共有する必要のないデータ
- 注文プロセス中のみ必要な一時的な状態
Redisでの永続化
- ZOZOTOWN共通のセッションではなく専用のRedisで管理
- TTL(Time To Live)を設定し、不要なデータは自動削除
メリット
- 管理箇所の集約:BFFに状態管理を集中させた結果、見通しが向上
- 独立性の確保:各ドメイン(カート、注文、決済)の状態が明確に分離
状態管理をShopping BFFに集約し、ビジネスロジックをShopping APIに分離したことで、状態とロジックの責務を明確に切り分けました。これにより、セッション依存による密結合は解消され、機能単位での段階的な入れ替えが可能になりました。あわせて、システム全体の見通しと保守性が向上しました。
リプレイス戦略の全体像
なぜ段階的なアプローチを選んだか
段階的なアプローチを採用した理由は以下の通りです。
- リスクの分散:機能を小さく区切って検証し、問題発生時の影響範囲を限定する
- 二重開発の最小化:新実装へ移行した範囲は旧実装への改修を減らせるため、早期リリースで並行開発の期間を短縮する
- 継続的なフィードバック:各フェーズで得られた知見を次のフェーズへ反映する
- チームのモチベーション維持:小さな成功体験を積み重ね、長期プロジェクトでも前進感を保つ
3つのフェーズに分けたアプローチ
これらの理由から、私たちは以下の3つのフェーズに分けてリプレイスを進めてきました。
フェーズ1:一部機能の比較フェーズ
- 既存ロジック(ASP)と新ロジックを並行稼働
- 結果を比較・検証し、差分を解消
フェーズ2:段階的な入れ替えフェーズ
- 比較で問題ないことを確認した機能から順次切り替え
- 二重開発の負担を最小化
フェーズ3:全体リプレイス
- 画面を含めた購入フロー全体を新システムに移行
- n%リリースで段階的にトラフィックを切り替え
フェーズ1とフェーズ2を機能単位で繰り返し、重要機能の切り替えが完了した段階でフェーズ3を実施します。
フェーズの関係性
フェーズ1・2ではビジネスロジック層のリプレイスを先行して進め、フェーズ3では画面層のリプレイスを実施する計画です。ビジネスロジック層を先に安定化させることで、画面リプレイス時には既に検証済みのAPIを使用できる体制を整えています。
現在の進捗状況
2026年2月時点で、フェーズ1・2は既にリリースが完了しており、本番環境で稼働しています。フェーズ3については開発が完了し、現在はリリースに向けた最終準備を進めている段階です。
次の章から、各フェーズの詳細について説明します。
フェーズ1:一部機能の比較フェーズ
比較対象の選定
リスクを最小限に抑えるため、読み取り系の機能を比較対象としました。具体的には以下の機能です。
- お届け先一覧の取得
- 支払い方法一覧の取得
- 配送日時の指定一覧の取得
これらの機能を選んだ理由は以下の通りです。
- 読み取り専用:データの更新を伴わないため、万が一の不具合でもユーザーへの影響が限定的
- 検証が容易:結果の比較が容易で、差分の原因を特定しやすい
- 段階的な複雑化:条件が少ないお届け先一覧から始め、徐々にロジックが複雑な機能へと比較対象を拡大
- 即時停止が可能:比較モードを停止するだけで対応可能
並行稼働の仕組み
既存のASPから新しいShopping APIを呼び出す形で並行稼働を実現しました。以下がその仕組みです。

この仕組みの重要なポイントは以下の通りです。
- フラグによる制御:対象機能を柔軟に切り替えられ、トラフィックの切り替えも即座に実施できる
- ASP側での比較:両方の結果をASP側で受け取り、差分をチェックする
- ユーザーへの影響なし:ユーザーには常にASPの結果を返すため、体験に影響を与えない
- 比較情報の保存:各種情報をJSONで保存し、集計・分析できる
- 負荷の考慮:比較は一部サーバーに限定して実施する
比較・検証方法
保存した比較情報を定期的にチェックし、以下の観点で検証しました。
- 一致率の確認:どの程度の割合で結果が一致しているか
- 差分の原因分析:不一致の場合、どのようなケースで発生しているか
- 優先度の判断:ビジネスへの影響度から修正の優先順位を決定
特に重要だったのは、差分が発生した際の根本原因の特定です。多くの場合、以下のような原因がありました。
- ASP側のロジックの暗黙的な仕様(ドキュメント化されていない挙動)
- データベースの参照タイミングによる差異
購入フローはミッションクリティカルな領域のため、これらの差分を1つずつ解消し、100%一致するまで比較を継続しました。
フェーズ1で得られた知見
比較フェーズを経て、以下の知見が得られました。
- 暗黙知の可視化:長年のシステムに埋もれていた仕様が明らかになった
- テストケースの充実:差分から得られた知見をテストケースに反映できた
- 段階的移行の有効性:小さく始めるアプローチが、リスク管理に有効であることが明らかになった
次のフェーズでは、この比較で問題ないことを確認した機能から、実際に切り替えを進めていきます。
フェーズ2:段階的な入れ替えフェーズ
入れ替え順序の工夫
比較フェーズで十分に検証した機能から、段階的に切り替えを進めました。具体的な順序の例と、その選定理由をいくつか紹介します。
| 順序 | 機能 | 特徴 |
|---|---|---|
| 1 | お届け先一覧の取得 | 条件が少なく、ロジックがシンプル |
| 2 | 支払い方法一覧の取得 | 決済方法の選択可否の判定ロジックが複雑 |
| 3 | 配送日時の指定一覧の取得 | 在庫や配送条件との連携が必要 |
この順序で進めた理由は以下の通りです。
- リスクの段階的な増加:シンプルな機能から複雑な機能へ段階的に広げる
- 経験の蓄積:各段階で得られた知見を次に活かす
- 影響範囲の管理:問題発生時にトラフィックの切り替えをしやすい順序にする
切り替えの仕組み
比較フェーズで差分がないことを確認した機能については、以下のように切り替えました。

重要な変更点は以下の通りです。
- 比較処理を廃止:検証済みのため、比較情報の保存は不要
- API結果を直接返す:Shopping APIの結果をそのままユーザーに返す
- 旧ロジックの保守を停止:切り替え済み機能はASP側を保守対象から除外
二重開発の最小化
このフェーズでは、二重開発を最小化できたことが大きな効果でした。
段階的リプレイスのメリット:
- 切り替え済みの機能に対する新規追加や修正は、新ロジック(Shopping API)のみに実施する
- 旧ロジック(ASP)への反映が不要になり、開発工数を削減できる
ビッグバンリリースとの比較:
- ビッグバンの場合、切り替え完了まで旧ロジックにも改修が必要になる
- 開発期間中は変更を二重に実装する必要がある
- 一方、段階的リプレイスでは、切り替え済み範囲が増えるたびにこの期間を短縮できる
例えば、新しい決済方法の追加が必要になった場合の修正範囲は以下の通りになります。
- 段階的リプレイス(API層移行済み):Shopping APIのみ修正
- ビッグバンでのリプレイス:ASPとShopping APIの両方を修正
このように、切り替え済みの機能については旧ロジックへの反映が不要になり、長期プロジェクトにおける開発負担を大きく軽減できました。
フェーズ2の成果
フェーズ2を通じて以下の成果を得ました。
- 対象機能の完全移行:読み取り系の主要機能をすべて新システムに移行
- 開発工数の削減:二重開発の期間を最小化し、チームの生産性が向上
- 品質の向上:段階的な検証により、問題を早期に発見・修正
次のフェーズでは、画面を含めた購入フロー全体を新システムに移行します。
フェーズ3:全体リプレイス
フェーズ3では、画面を含めた購入フロー全体を新システムに移行する計画で進めています。
n%リリースによる段階的な移行
全体リプレイスでは、トラフィックを段階的に切り替えるn%リリースを採用する計画です。同一ユーザーが途中で旧フロー・新フローを行き来しないよう、ユーザー単位で一度割り当てた割合を保持する形でルーティングする設計としています。
n%リリースの設計方針
段階的な切り替えにおいて、以下の方針で進める計画です。
| 段階 | 目的 | 検証期間 | 備考 |
|---|---|---|---|
| 1% | 本番環境での動作確認と想定外の問題の早期発見 | 長期 | 注文から発送完了まで問題なく処理されることを検証 |
| 20% | 1%で得られた知見を反映し、より大きなトラフィックでの検証 | 短期 | 問題がなければ次の段階へ |
| 50% | 本番に近い負荷での最終検証 | 中期 | 大規模なトラフィックでの安定性を確認 |
| 100% | すべてのトラフィックを新システムに移行 | - | 万が一の問題に備え、即座にロールバックできる体制を維持 |
各段階での検証項目
各n%段階で、以下の項目を重点的に監視する計画です。
機能的な正常性
- 注文完了率
- 決済成功率
- エラーログの監視
パフォーマンス
- レスポンスタイム
- スループット
- データベースの負荷
問題が発見された場合は、即座に前の割合に戻す体制を整えています。
全体リプレイスにおける課題
フェーズ3では、フェーズ1・2とは異なる課題に直面しています。
1. 機能改修とのコンフリクト
- 画面を含む全面リプレイスのため、リリースまで約1年半の開発期間が必要になる
- その間、既存システム(ASP)にも新規機能や改善が継続的に追加される
- 新旧両方のシステムに同じ変更を反映する二重開発が発生する
具体例としては以下が挙げられます。
- 新しい決済方法の追加
- ユーザーインタフェースの改善
- バグ修正や運用改善
これらをASPとShopping BFF/Shopping APIのすべてに実装する必要があり、工数が増加しています。
2. モチベーションの維持
- 長期にわたる開発により、チームのモチベーション維持が課題
- 「いつ終わるのか」という不安感
- 同じ機能を二重に実装する徒労感
課題への対応策
これらの課題に対し、以下のように対応しました。
1. フェーズ2の成果を活用
- API層はフェーズ2で既に移行済みのため、Shopping APIへの修正のみで対応できる範囲が拡大
- BFF層のみの修正で済むケースも多く、完全な二重開発を避けられた
2. 優先度の明確化
- 新規機能の開発は、極力リプレイスのリリース後に行う
- 緊急性の高い修正のみ二重開発で対応
今回の課題と今後の改善点
長期にわたるリプレイスプロジェクトにおいて、チームのモチベーション維持が課題として浮上しました。約1年半の開発期間中、同じ機能を二重に実装する必要があり、「いつ終わるのか」という不安感や徒労感がチームに蓄積しやすい状況でした。
今回の経験を踏まえると、次に同様のプロジェクトに取り組む際には、以下の点をあらかじめ検討しておくべきだと感じました。
- プロジェクト初期段階でのマイルストーン設計:長期プロジェクトでも前進感を保てるよう、細かいマイルストーンを設定
- 定期的な成果の可視化:各段階での成果を可視化し、チーム全体で進捗を共有する仕組みの構築
- チームメンバーのケア体制:長期プロジェクトにおけるメンバーの心理的負担に配慮した体制づくり
今後の展望
リプレイスプロジェクトの完了後も、以下のような継続的な改善と発展を計画しています。
新システムでの運用安定化と監視体制の強化
リリース完了後は、新システムの安定稼働を最優先とし、監視体制の強化に取り組みます。具体的には、パフォーマンスメトリクスの継続的な収集・分析や、エラー検知の精度向上、アラート体制の整備などを進めていきます。また、運用ノウハウの蓄積と共有により、障害発生時の迅速な対応体制を構築します。
モジュラモノリスからマイクロサービスへの段階的な移行検討
現在のモジュラモノリス構成は、開発効率とシステムの見通しの良さを両立できていますが、将来的にはマイクロサービスへの移行も視野に入れています。ただし、マイクロサービス化はトレードオフを伴うため、ビジネス要件やチーム体制、技術的な成熟度を考慮しながら、慎重に検討を進める方針です。
さらなるパフォーマンス改善と開発体験の向上
新システムへの移行により開発効率は向上しましたが、さらなる改善の余地があります。レスポンスタイムの最適化やデータベースクエリのチューニング、開発ツールの整備など、継続的な改善を通じて、より快適な開発体験とユーザー体験を実現していきます。
得られた知見を他のシステムのリプレイスにも適用
本プロジェクトで得られた段階的リプレイスの手法や、並行稼働による検証のノウハウ、長期プロジェクトにおけるチーム運営の知見は、社内の他システムのリプレイスにも適用可能です。これらの知見を共有し、組織全体の技術力向上に貢献していきます。
まとめ
本記事では、ZOZOTOWNの購入フローにおける段階的リプレイスの実践について紹介しました。
セッションに強く依存した既存システムを、3つのフェーズに分けて段階的にリプレイスしています。
- 一部機能の比較フェーズ:並行稼働により、リスクを抑えながら新旧ロジックの差分を解消
- 段階的な入れ替えフェーズ:検証済みの機能から順次切り替え、二重開発の期間を最小化
- 全体リプレイス(進行中):n%リリースにより、画面を含む購入フロー全体を安全に移行する計画
また、Shopping BFF + Redisの構成により、セッション依存の問題を解消し、システムの見通しと保守性の向上を実現しています。
大規模ECにおける段階的リプレイスを検討している方や、ミッションクリティカルなシステムの無停止移行に取り組んでいる方の参考になれば幸いです。
ZOZOでは、一緒にサービスを作り上げてくれる方を募集中です。ご興味のある方は、以下のリンクからぜひご応募ください。