スパイラル開発で大規模リプレイスを成功に導く──ZOZOTOWN検索リプレイスの舞台裏

Title: スパイラル開発で大規模リプレイスを成功に導く──ZOZOTOWN検索リプレイスの舞台裏

1. はじめに

検索基盤部 検索基盤ブロックの佐藤(@satto_sann)、岡田(@ryokada33)、SRE部 検索基盤SREブロックの富田(@kei_gnu622)です。

ZOZOTOWNアプリ用に検索機能を提供していたオンプレサーバー上のレガシーなAPIを、約1年かけてクラウド環境へ全面リプレイスしました。

このリプレイスプロジェクトではスパイラル開発の導入開発初期からの環境整備といった工夫を積み重ねることで、当初のスケジュールどおり移行を完了しています。

また、副次的な効果として、検索速度が約2倍に向上しユーザー体験の改善にもつながりました。

本記事では、大規模リプレイスを円滑に進めるために実践したプロジェクト運営の取り組みを、以下の流れで紹介します。リプレイスをはじめとした、ソフトウェアやマイクロサービス開発プロジェクトの参考になれば幸いです。

  • 【2章】リプレイスプロジェクトの概要
    今回のプロジェクトが直面した技術的・運用的な難しさと、限られたリソースの中でどのような制約があったかを説明します。
  • 【3章】なぜスパイラル開発なのか
    過去のWeb版リプレイスで直面した課題を振り返り、その学びから今回スパイラル開発を選択した理由と背景を解説します。
  • 【4章】スパイラル開発を実践するための4つの工夫
    2週間サイクルでの開発、mainブランチへの積極的なマージ、機能フラグの活用、開発初期からの環境整備という4つの実践ポイントを紹介します。
  • 【5章】スパイラル開発を支えたテストプロセス
    開発サイクルに組み込んだテスト戦略と、品質を維持しながらスピードを保つために設計したテストプロセスの全体像を説明します。
  • 【6章】デプロイ基盤とリリース戦略
    頻繁なリリースを支えた自動デプロイの仕組みと、本番環境への影響を最小限に抑えたリリース戦略を紹介します。

目次


2. リプレイスプロジェクトの概要

本題へ入る前に、今回のリプレイスプロジェクトの概要を紹介します。ZOZOTOWNではWeb・アプリともに継続的にリプレイスを進めています。

techblog.zozo.com

今回のプロジェクトでは、ZOZOTOWNアプリに検索機能を提供するVBScriptで書かれたレガシーなオンプレAPI(以下、レガシーAPI)をリプレイスしました。リプレイス先は、クラウド環境で稼働するSpring Boot(Java)で構築されたAPI(以下、リプレイスAPI)です。

リリース前後のAPIのルーティングの様子

2.1. プロジェクトの難しさ

このプロジェクトの難しさを少しお伝えすると、以下3つの技術的・運用的な難しさがありました。

課題1:膨大な検索条件の組み合わせ
検索に関わるAPIパラメータは70項目以上にのぼります。これらは自由に組み合わせられるため、考慮すべきパターンは「組み合わせ爆発」と言えるほど膨大です。あらゆる条件の組み合わせに対して正しく結果を返せることが求められました。

課題2:高トラフィック環境での安定稼働
検索はZOZOTOWNのほとんどのユーザーが日常的に利用する主要な機能であり、常に高トラフィックに晒されています。高負荷な環境下であっても安定した動作やサービスを止めることなくリプレイスすることが必須条件でした。

課題3:レガシーコードの移行
十数年にわたり機能追加を重ねてきた数万行のVBScriptコードを、Spring Boot(Java)へ移行するという大規模な技術的チャレンジがありました。レガシー資産を正確に読み解きつつ、新しいアーキテクチャへ落とし込む作業は想像以上に複雑で、多方面での工夫と知見が求められました。

2.2. 制約と方針

ソフトウェア開発プロジェクトでよく知られる「アジャイルの鉄の三角形」では、以下3要素がトレードオフの関係にあるとされています。

  • スコープ(範囲)
  • スケジュール(期間)
  • リソース(品質・コスト)

今回のリプレイスプロジェクトでは、この三角形の各要素について以下のような制約がありました。

スケジュール
ZOZOTOWNの事業計画や、オンプレサーバーの縮退スケジュールを含めたリプレイス全体のロードマップとの兼ね合いから、期限を大幅に延長することは困難な状況でした。

スコープ
“リプレイス”という特性上、すでに稼働しているZOZOTOWNアプリの「検索機能」を過不足なく実装する必要がありました。また、検索の機能全体を見渡すと、ネイティブアプリ、BFF(Backend For Frontend)、検索エンジンなど、複数のレイヤーが関わっています。しかし、リプレイス期間の肥大化を抑えるため、今回のスコープはBFFレイヤーのAPIリプレイスのみに絞り込みました。具体的には、ネイティブアプリ側のコードは一切変更せず、APIのインタフェース(リクエスト/レスポンス形式)も原則として維持する方針としました。

リソース
5〜7名体制と限られた開発リソースの中での開発となりました。

このように、スケジュールとスコープが固定された状態で、限られたリソースを最大限活用しながら品質を確保することが求められました。


3. なぜスパイラル開発なのか

過去のリプレイスプロジェクトでは、属人化や結合の遅れによって手戻りが多発し、大規模リプレイスの難しさを痛感しました。

今回も扱う範囲は広く複雑で、初期に全体計画を固めることが難しい一方、スクラムのような価値検証型の進め方とも相性が良くないと考えていました。そこで、実装する機能単位を区切って品質を積み上げられるスパイラル開発が最も適していると判断しました。本章では、その判断に至った背景と学びを簡潔に整理します。

3.1. 過去のリプレイスで直面した課題と学び

私たちは過去に、Web版ZOZOTOWNの検索結果ページの大規模なリプレイスを実施しました。(Web版のZOZOTOWNとアプリ版のZOZOTOWNの検索機能を担うロジックは別のマイクロサービスで動いていました)。

当時のリプレイスでは、度重なる手戻りが発生し、全体として大きく工期が延びてしまいました。最終的には無事リリースに至りましたが、その過程で「大規模リプレイスの難しさ」を強く実感する結果となりました。

課題1: 実装する機能単位での分担による属人化と認識齟齬
過去のリプレイスでは、機能単位(スコープ)ごとに設計からリリースまで全期間で担当者を割り当てる形で進めていました。この方式により、各担当者が自分の範囲に強い責任感を持って開発を進められた一方で、機能ごとの仕様理解、実装方針や設計思想が分断され、チーム全体での整合性を保つことが難しくなりました。

その結果、部分的には完成していても全体として連携できない状態が生まれ、後任者や他メンバーへの知識共有が難しくなるなど、属人化が進行しました。また、仕様の整合性確認やレビューにも余計な時間がかかる要因となりました。

課題2: フロントエンドとの結合の遅れによる課題
過去のリプレイスでは、チームが大きかったこともありバックエンド側の実装がある程度進んでから、結合テストを行う方針でした。フロントエンドやクライアントアプリとの結合は後回しになっていました。しかし、API設計段階でのレビューやモック連携は行っていたものの、終盤の結合タイミングで、想定外の仕様差分や不具合が一気に顕在化しました。

実際に動作する環境でのユーザーストーリーベースのテストをおこなった際に、バックエンドとクライアントの間で整合性を欠き、検索結果の挙動や表示内容に不具合が多く見られました。

E2E(エンドツーエンド)の動作を通して初めて明らかになる不具合が多く、設計段階では検知できなかった差分対応が後半に集中しました。その結果、仕様調整や修正対応がテストフェーズの負担を増大させる要因となり、リリース準備全体に遅延を引き起こしました。

学び
これらの経験を通して、チームは次の3点を学びました。

  1. 早い段階での結合と検証が重要であること
    実際の動作環境で早期に結合テストを行い、ユーザーストーリー単位で整合性を確認することが品質向上につながると学びました。
  2. プロダクトとしての品質検証は初期の段階からプロセス全体に組み込むべきこと
    テストを後工程ではなく、開発の反復サイクル内に取り込むことで安定した品質を保てると考えました。
  3. 担当機能を固定しすぎないこと
    長期間同じ機能の開発を担当し続けると属人化や認識齟齬が生じやすくなるため、メンバー間で担当する機能を固定せず、知識を共有しながら進めることが重要だと感じました。

3.2. スパイラル開発の選択

前回のリプレイスでは、広い範囲を一度に開発・結合しようとしたことで、認識齟齬や手戻りが増え、チーム全体の負荷が高まってしまいました。

今回のリプレイスは「新しい検索体験をつくる」プロジェクトではなく、既存検索の同等挙動を新システム上で再現するという性質を持つプロジェクトです。要件自体は明確でしたが、ZOZOTOWN20年の歴史を支えてきた大規模で複雑なコード群を扱う必要があり、全体を見通して計画を立てにくい構造的な複雑さが存在していました。
※このような状況は、クネビンフレームワークにおける「Complex(複雑)な領域」に近い状態といえます。

[email protected], CC BY-SA 4.0, via Wikimedia Commons

そのため、ウォーターフォール型のように初期段階で全体を計画しきる進め方では対応が難しく、一方で、スクラムのように仮説検証を繰り返す新規事業型のアプローチとも性質が異なっていました。そこで私たちは、スパイラル開発を採用することにしました。

スパイラル開発は、チームで集中して実装する機能を期間で明確に区切り、その期間でリリース品質まで集中して仕上げるサイクルを繰り返す開発手法です。
スクラムが「価値検証(アウトカム)を中心に、仮説を試しながら仕様を磨く」手法であるのに対し、スパイラル開発は「あるべき挙動が明確な機能を、確実に積み上げていく」ことを目的としたアプローチです。

今回のリプレイスプロジェクトでは、スクラムが得意とする価値検証型のサイクルを必須とせず、仕様の再現性と高品質なアウトプットを積み重ねるスパイラル開発のほうが適していると判断しました。

下表に、各手法と本プロジェクトとの相性をまとめます。

手法 特徴 今回のプロジェクトとの相性
ウォーターフォール 設計からリリースまでを一方向に進める。計画が明確な反面、変更や手戻りに弱い。 ✗ 既存仕様の再現範囲が広く複雑。終盤の結合で手戻りが発生しやすい。
スクラム アウトカムを中心据えて、機能単位の短期開発と価値検証を繰り返す △ 要求が明確で仮説検証を必要としないため、スプリント単位での価値検証が適さない。
スパイラル開発 設計・実装・テストを反復し、段階的にシステムを完成させる ◯ 既存検索の同等挙動を機能単位で再現し、品質を積み上げる進め方として適している。

社内の別の大規模案件でスパイラル開発を採用していたことも、選択を後押ししました。

最終的には予定していたすべての仕様をリプレイスできました。ただし、この仕組みを導入した当初は別の意図もありました。スケジュールの制約で対応の難しい仕様が生じた場合に、安全に後ろ倒しやドロップができる状態を作ることです。


4. 大規模リプレイスをスパイラル開発で回すポイント

本章では、スパイラル開発を円滑に進めるために私たちが実践した以下4つのポイントについて紹介します。

  1. 2週間ごとに「動くもの」を作る
  2. mainブランチへの積極的なマージ
  3. 機能フラグを使って安全に本番リリース
  4. 開発初期からアプリ上で動かせる環境整備

4.1. 2週間ごとに「動くもの」をつくる

前述の通り、スパイラル開発の核心は短いサイクルで「実際に動く成果物」を完成させ、チーム全体で動作確認を繰り返すことです。

実際に動く成果物=検索機能として、私たちはプロジェクト全体で実装しなければならない機能を複数のスプリントに分割し、各スプリントで以下のように検索機能を順番に実装していきました。

  • スプリント1: ショップ検索
  • スプリント2: カテゴリ検索
  • スプリント3: 価格検索
  • ...

各スプリントでは、対象機能の設計から実装、テストまでを2週間で完了させることを目標としました。ここで重要なのは、「コードを書き終わる」ことではなく、「アプリ上で実際に動作する状態にする」ことをゴールに設定した点です。

この進め方によって、以下のメリットを得られました。

全レイヤーに関わることで属人化を防止
ひとつの機能を完成させるには、APIのプレゼンテーション層やビジネス層、データアクセス層など全レイヤーに手を入れる必要があります。また、スプリントごとに担当機能を入れ替えながら共同開発を進めることで、特定のメンバーだけが詳しい領域を作らず、チーム全体で知識を共有できました。

成果物が明確になり、進捗が見える化される
各スプリントの終わりには「使える検索機能がひとつ増える」という目に見える成果が生まれます。これにより、スケジュールに対して順調なのか遅れているのかを早い段階で把握でき、必要に応じて計画を調整することも可能になりました。

スパイラル開発の様子

4.2. mainブランチへの積極的なマージ

スパイラル開発を円滑に進めるうえで、ブランチ戦略も重要なポイントでした。私たちは、開発中の機能であっても積極的に本番環境で動作しているコード=mainブランチへマージする方針を採用しました。

なぜ開発用ブランチを長期間維持しないのか
ZOZOTOWNでは、今回のリプレイス以外にも日々様々な開発が並行して進められています。このような状況で、リプレイス用の統合ブランチを長期間維持し続けると、mainブランチとの差分が大きくなることは明確でした。実際、過去のWeb版検索リプレイスでも、終盤の統合作業で予想外の時間を取られた経験がありました。

スプリントごとにmainへマージする運用
今回のリプレイスでは、各スプリントで実装した機能が一定の品質に達したら、速やかにmainブランチへマージするルールを設けました。これにより、並行して進む他の開発との差分を最小限に抑え、常に最新のコードベースで作業できる状態を維持しました。なお、「一定の品質に達した」ことをどのように担保したかについては、次章のテストプロセスで詳しく紹介します。

ブランチ運用の様子

振り返りで見えた成果
プロジェクトの振り返りでも、以下のようなポジティブな声が上がっており、開発効率に大きく貢献していることが分かりました。

  • 「ベースブランチへのマージを定期的におこなったので、同期負荷がWeb版リプレイスに比べて格段に下がった」
  • 「他チームとのコードに関する調整がほとんどいらなかった」

4.3. 機能フラグを使って安全に本番リリース

開発途中の機能をmainにマージすることには「本番環境に影響を与えないか」という懸念が伴います。mainブランチへの積極的なマージを可能にしたのが、機能フラグ(Feature Flag)の活用です。

機能フラグの基本的な考え方
機能フラグとは、コード上に実装された新機能の有効・無効を、設定値によって切り替えられる仕組みです。機能フラグがOFFの状態では、新しいコードが本番環境に存在していても、実際のユーザーリクエストには影響を与えません。

機能フラグOFFで本番リリース
私たちは、開発中の機能をすべて「フラグOFF」の状態でmainにマージし、本番環境へのデプロイまでしていました。これにより、「コードは本番に乗っているが、機能としてはまだ有効化されていない」という状態を実現しました。

なお、フラグOFFの状態で、ユーザーのリクエストによってリプレイスコードにアクセスされた場合は、あえて明示的にエラーを返す仕組みにしました。エラーが発生した場合はアラートが発報される監視体制は整備済みのため、開発者が気づかないうちに未完成なコードが利用されてしまう事態を防止しました。

機能フラグによる安全性について

4.4. 外部サービス連携部分のモック化

機能フラグにより安全にコードを本番環境へ配置できるようになりましたが、開発段階で「実際に動くもの」を作るためには、もう1つ重要な課題がありました。それが、外部サービスとの連携です。

リプレイス後の検索機能は、複数のマイクロサービスと、それらが提供する50以上のエンドポイントに依存しています。商品情報、ショップ情報、お気に入り情報など、検索結果の表示に欠かせないデータは、すべてこれらのサービスから取得しています。

しかし、開発初期からすべての外部サービスに接続して開発を進めるのは、コストが高く現実的ではありません。

そこで、実装がまだ完了していない部分の連携にはモックを用意し、まずはAPI全体として「ひと通り動く」状態を早期に作りました。

この仕組みにより、スプリントごとに新しく実装した機能を、実際の端末からすばやく動作確認できるようになりました。これらを活用したテストプロセスについては、次章で詳しく説明します。

5. スパイラル開発を支えた「テストプロセス」

本章では、検索リプレイスを成功へ導いた要因の1つである「テストプロセス」について解説します。スパイラル開発において、複雑な検索機能を段階的に実装しながらも品質を維持できた要因、開発リズムにテストを組み込むための具体的な仕組み、さらにそれによって得られた成果と学びを、実践的な視点で紹介します。

5.1. テストを開発のサイクルに組み込む

スパイラル開発では、短いサイクルの中でリリースを繰り返しながら品質を高めていくことが求められます。各スプリントで異なる関心領域を扱うなかでも、既に実装済みの部分も含めた品質を維持し続ける必要があります。

3章で紹介した過去のリプレイスプロジェクトのような「開発の後工程としてテストを行う」進め方では、十分な品質とスピードを両立することは困難でした。そこで私たちは、プロジェクト初期からテストを開発プロセスの中心に位置づけ、開発・検証・改善を同じリズムで進める体制を整えました。

5.2. スパイラル開発のために設計したテストプロセス全体像

今回のリプレイスは複雑な検索ロジックを扱う一方で、スプリントごとに実装する機能を区切りながら実装を進めます。そのため、部分ごとの開発を進めつつも、全体の品質を破綻させない状態をどのように作るかが重要なポイントとなりました。

これら背景を踏まえ、私たちは"いつ・何を・どの粒度で検証するか"を明確にした段階的テストプロセスを設計し、開発の初期段階から導入しました。

以下の表は、実際に運用していたテストプロセスをフェーズ別にまとめたものです。

テストグループ 実施タイミング テスト内容 目的
開発中テスト 開発中に随時・マージ前CI ユニットテスト コードレベルの正しさを即時に確認。境界値・異常系までカバーし、仕様の確認
開発中に随時 アプリE2E動作確認 実機/エミュレータを使い「プロダクトとして提供する形」で動作確認し、UI/UXレベルの齟齬を確認。
スプリントごとのテスト 2週間に1回 アプリE2E結合テスト スプリントで実装した範囲の結合テストを実施。
2週間に1回 新旧APIレスポンス比較リグレッションテスト 上記結合テストのケースについて、自家製自動APIテストツールを用いてリプレイス前後で比較し、守るべき仕様が維持されているか確認
2週間に1回 レビュー会(モンキーテスト) 成果物をチーム全員で俯瞰し、ユーザー視点で動作の違和感や齟齬を調整する
リリース前テスト 全機能の開発完了後 受入結合テスト 開発チームによる、最終コードでの実機テスト。「実装したことがすべてできているか」を確認
全機能の開発完了後 QAリグレッションテスト 第三者QAチームによる、ユーザーストーリーに基づいた網羅的な品質確認
全機能の開発完了後 負荷試験 高負荷を想定した本番耐性の確認

5.3. テストプロセスのポイント

プロセスの中でのポイントは、以下の3つのプロセスです。

  • 開発中のE2E動作確認
  • 新旧APIレスポンス比較リグレッションテスト
  • レビュー会(モンキーテスト)

以下では、それぞれの役割と効果を説明します。

5.3.1. E2E動作確認:実装直後から「プロダクトとしての挙動」を確かめる

開発フェーズでは、開発者が実装したコードをエミュレータまたは実機から直接操作し、ZOZOTOWNアプリ上での実際のユーザー体験としてどう動作するかを随時確認できるような環境を整備しました。

  1. 検証端末の全メンバーへの配布
    Android端末とiPhoneを開発メンバー全員に配布し、誰でもすぐに実機で動作確認できる体制を整えました。
  2. ローカル実行のAPIと実機アプリの接続環境の整備
    開発者がローカルで起動したAPIに対して、ZOZOTOWNアプリ(インハウス版)から直接リクエストを送れるようにしました。これにより、開発しながらアプリ上で挙動を気軽に確認できるようになりました。

このプロジェクトの実装レイヤーはバックエンドの開発ですが、単なる「APIが正しく返るか」を見るテストにとどめません。画面遷移・検索条件の適用・表示ロジックなど、“実際のユーザーが触れる状態”の挙動を初期段階から検証することが目的でした。

5.3.2 レスポンス比較リグレッションテスト:守るべき仕様の破壊を防ぐ“自動チェック”

今回のリプレイスでは、「旧サービスと同じ結果が返ること」が絶対条件でした。そのため、旧APIと新APIのレスポンス差分を自動比較できる自家製ツールを作成しました。スプリントごとに蓄積してきたすべてのテストケースを用いてリグレッションテストを実施しました。

特に効果が大きかったのは、「スプリントごとに異なる機能を開発しても、全体として同じ振る舞いであることを機械的に保証できた」ことです。

このプロセスを継続的に運用した結果、最終的にはテストケースが約1,000件まで蓄積され、それらを高頻度で実行できる状態を構築しました。その過程では、開発中に70件以上のリグレッションを検出しており、この自動チェックの有効性を十分に示す結果となりました。

5.3.3. レビュー会:ユーザー目線での齟齬をスプリント単位で解消する

2週間に1度のレビュー会では、開発チームに加え、チーム外の関係者もアプリでの挙動を実際に確認し、成果物をユーザーの視点で体験することを重視しました。

レビュー会の目的は、単なる「動作チェック」ではなく、認知のズレをなくすことにありました。

  • デモを通じてチームの認識をそろえる
  • 「実装者の意図」と「ユーザーが体験する挙動」が一致しているか
  • 想定していない分岐・遷移がないか

また、副次的な効果として「徐々に完成していく様子を共有できるためモチベーションが維持できる」「Tipsが共有されチームとしての開発効率が良い」効果もありました。振り返ってみると、この点こそがプロジェクト全体に大きな効果をもたらしていたと感じます。

5.4. 成果と学び

  • 最終QA段階で不具合ゼロ
    検索リプレイスでは、リリース前の最終QAで一件の不具合も発生せず、品質面で非常に安定した状態を保てました。
  • スケジュール遅延ゼロ
    リリース開始までの工程はすべて計画通りに進行し、想定していた作業を予定どおり完了できました。
  • リリース後のリグレッションもゼロ
    リリース後に細かなバグが見つかりましたが、その修正においてもリグレッションは一件もなく、整備したテストプロセスの再現性と堅牢性が確認できました。

この成果を通じて、私たちはテストを後追いで行うのではなく、開発リズムに組み込むことが品質とスピードの両立に直結することを実感しました。

テストは一部の担当者だけが実施する仕組みではなく、チーム全員が関わるプロセスとして設計することで、実際のユーザーへの影響を意識した実装や、認識齟齬・不具合を早い段階で修正できる文化が根づきました。


6. デプロイ基盤とリリース戦略

この章では、スパイラル開発を支えたインフラ構築と安全なリリースの仕組みについて紹介します。

ZOZOTOWNの検索機能は、1日あたり数百万回も利用される重要なサービスです。そのため、少しのダウンタイムも許されず、デプロイの安全性と効率性の両立が不可欠でした。SREは、それらの要件に基づいたデプロイ基盤を構築し、スパイラル開発における頻繁なリリースサイクルを支えました。

6.1. 安全かつ効率的なデプロイの仕組み

ZOZOTOWNのプラットフォーム環境はEKSで稼働しており、FluxやFlaggerといった安全かつ効率的なデプロイを実現するための仕組みが導入されています。以下は弊社が KubeCon + CloudNativeCon Japan 2025 にスポンサーブースを出展した際に展示したアーキテクチャ図です。

引用:KubeCon + CloudNativeCon Japan 2025参加&協賛レポート

今回のリプレイスAPIのデプロイ基盤は、このプラットフォーム上にあるFluxとGitHub Actionsを組み合わせて開発者がPRのマージをするだけで完結するように設計されています。

詳細を以下に記載します。

  1. ECRへのイメージプッシュで自動的にPR作成
    開発者がリプレイスAPIリポジトリでDockerイメージをECRへプッシュすると、FluxのImageUpdateAutomationが新しいイメージを検知します。検知後、Kubernetesマニフェストを管理するインフラリポジトリへイメージタグを更新するcommitを自動的にpushします。その後、リリースブランチへ自動でPRを作成し、Slackで開発者へ通知します。

  2. 安全性を担保する自動承認
    作成されたPRは、内容に応じて自動承認されます。自動化によるコミットのみの場合は、イメージ更新と判断しGitHub Actionsで自動承認されます。自動化によるcommit以外を含む場合はイメージ更新以外の変更を含むため、SREがPRをレビューします。

  3. PRマージと自動デプロイの実行
    2で自動的に承認されたPRは、開発者によってPRをマージします。マージ後はEKSクラスタ上のFluxが自動的に変更を検知し、変更内容をリプレイスAPIのDeploymentに反映します。反映後はFlaggerによるプログレッシブデリバリーが開始され、エラーが発生した場合はロールバックする仕組みもあるので、安全にリリースすることが出来ます。

  4. 本番環境は別途SREによる承認
    開発環境(dev)やステージング環境(stg)は、マージと同時に自動デプロイされます。一方、本番環境(prd)にはRelease Gateという仕組みを導入しています。

techblog.zozo.com

これはイメージ変更PRをマージ後に、SREによる承認を得なければprdへデプロイできない仕組みです。この承認プロセスにより、prd環境への影響はSREが確認しつつも、dev/stg環境では開発者自身で迅速にデプロイができるようになっています。

環境ごとのワークフローの様子

6.2. 非機能面の品質確保

今回の検索リプレイスはスパイラル開発による段階的な開発・リリースを進めてきましたが、最終的にはユーザーのトラフィックをリプレイスAPIにルーティングする必要があります。

特に、ZOZOTOWNの検索機能は日常的に高トラフィックを処理しておりビジネスの面でも重要な機能であるため、ユーザー影響を抑えるために慎重な対応が求められました。

そのため、本番リリース前にSREが中心になって以下のような非機能面の品質検証および運用体制の強化を実施しました。

  1. 負荷試験・障害試験を実施
  2. SRE部のテックリードによるリリース前レビュー(プロダクションレディチェック)
  3. 開発者とSREとのリリース前の監視指標の認識合わせ

6.2.1. 負荷試験・障害試験を実施

ここではリプレイス前のセール時の最大リクエスト数の負荷を掛け、レイテンシや各種メトリクス指標で大きな性能悪化が出ないかを確認します。また事前に本番同等の負荷を掛けることで、本番環境へ出す前にリプレイスAPIのインフラ増強をしておくべきかを確認できます。

障害試験では、各マイクロサービスの呼び出し時に500系エラーやレスポンス遅延を意図的に発生させ、想定通りの挙動となるかを確認します。500や遅延はIstioのFault Injectionを使って実現しています。

これにより事前に呼び出す際のマイクロサービスで障害が発生しても意図通りな挙動であるかを確認します。

6.2.2. SRE部のテックリードによるリリース前レビュー(プロダクションレディチェック)

本番リリース前には、SRE部が独自に整備している「プロダクションレディマイクロサービスチェックリスト」を用いて、SRE部のテックリードによるレビューを実施しています。このチェックリストは、セキュリティやCI/CD、障害・負荷試験、監視、ドキュメント整備など、インフラ運用に必要な観点を網羅したものです。

チェックリストは形式的なものでなく、実際の運用・障害対応まで見据えた具体的な項目が並びます。「graceful shutdownの実装」「カナリアリリースの仕組み」「DatadogやSentryによる監視・アラート設計」「オンコール体制の整備」などです。

最終的に、SRE部のテックリードがこれらの項目をレビューし、「本番リリースOK」と判断できた段階でリリースを進めます。このプロセスを通じて、リリース後のトラブルや運用負荷を大幅に低減できるだけでなく、開発チームとの連携強化やナレッジの共有にもつながっています。

6.2.3. リリース前に開発者とSREで監視指標の認識合わせ

これまでバグを出さないためのテストを行ってきましたが、検索リプレイスのような大規模な変更では、予期しない問題が多様な形で現れる可能性があります。

そのため開発チームとSREチームで、事前にリリース時の監視体制と切り戻し方針について議論し合意しました。また、数値基準を厳密に決めすぎると、「この数値は基準を超えているが、本当に切り戻すべきか?」という議論がリリース当日に発生し、判断が遅れる可能性もあります。

そこで私たちが合意したのは、具体的な数値ではなく、「判断の枠組み」でした。

【合意した切り戻しの方針】

  1. 断続的・継続的なエラー発生・単発のエラーではなく継続する場合
  2. リプレイス前後で比較して明らかに体感できるレベルのレイテンシ悪化
  3. ビジネス影響の兆候
    • 検索実行数の不自然な減少
    • カスタマーサポートへの問い合わせ増加
    • 売上影響の可能性
    • 社内で策定したSLOに違反

重要なのは、「何かあったらひとまずレガシーAPIにリクエストを戻す」というシンプルで明快な方針を共有したことです。後述の6.3で説明するFlaggerのManual Gatingの利点は「いつでも安全に戻せる」ことです。この利点を活かし、迷ったら切り戻して安全確保する判断を優先できるようにしました。

【監視体制と判断プロセス】

合意した切り戻し方針を元に、N%リリース期間中は開発チームとSREチームが「同じ監視指標の画面を見て、同じ認識で判断できる状態」も整えました。

例えば、「断続的・継続的なエラー発生やレイテンシ悪化の確認」はDatadog、「リプレイス前後の比較」はレガシーAPIからログを送信しているSplunkの画面を見るといった認識を揃えました。

これらを常時モニタリングし、異常の兆候が見られた段階で開発チームとSREチームが即座に協議できる体制を整えました。

6.3. リプレイスAPIへの安全な切り替え

6.3.1. 段階的なトラフィック切り替え

本番リリースではユーザー影響を最小限に抑え、かつ長い期間をかけて段階的にリプレイスAPIへ切り替えることが求められました。ZOZOTOWNではFlaggerによる自動カナリアリリースを採用していますが、自動でリクエスト比率が上がってしまうため長い期間をかけたリリースには向いていませんでした。

そこで今回は、FlaggerのManual Gating機能を活用した段階的にリプレイスAPIへ切り替えました。

まず、機能フラグをONにしてリプレイスAPIを本番環境にデプロイした後、リクエストの99%をレガシーAPI、1%をリプレイスAPIにルーティングする設定で運用を開始します。この間、開発チームとSREチームが事前に合意した監視指標(レイテンシ、エラー率、ビジネス影響など)をもとに、リアルタイムで状況を確認しました。数日間問題がなければ、段階的にリプレイスAPIの比率を引き上げ、最終的に100%切り替えを完了します。この比率は以下の基準で設定しました。

このルーティング比重操作の詳細な技術は、以下のテックブログもご参照ください。

techblog.zozo.com

本番リリースにおけるトラフィック切り替えの様子

6.3.2. 即座に切り戻せる安心感

この仕組みの最大のメリットは、問題発生時にすぐ切り戻せることです。

もしバグやパフォーマンス劣化などの異常が検知された場合は、スクリプトを実行してトラフィックをすぐさまレガシーAPIへ戻せるため、ユーザー影響を最小限に抑えられます。その後、開発者が修正をデプロイし、再度Manual Gatingで段階的リリースを再開する、というサイクルを安全に回すことができました。

この「即座に切り戻せる安心感」があったからこそ、私たちは本番環境で大胆にリリースを進められました。実際のリリースでも、細かな挙動の違いを検知した際はすぐ切り戻し、修正後に再度段階的にリリースすることで、安全でスピーディな運用を実現できました。


7. おわりに

本記事では、リプレイスの過程でスパイラル開発をどのように取り入れ、実際のプロジェクト運営の中で活かしたのかを紹介しました。

小さく動かしながら品質を積み上げる仕組みづくり、早い段階で実環境に近い検証をする文化、そして安全にリリースできる基盤が、今回のリプレイス成功を支えた大きな要因でした。本記事が、同じようにレガシーシステムのリプレイスや段階的移行に取り組む方の参考になれば幸いです。

ちなみに

今回のリプレイスでは副次的な効果として検索速度が約2倍に向上しました。

ぜひZOZOTOWNアプリで検索してみてください!以前よりサクッと動く感覚を、体感していただけると思います。

紹介

このプロジェクトの完了により、Web・アプリ双方の検索基盤リプレイスがひと区切りとなり、検索UI/UXの改善をよりスピード感をもって進められる環境が整いました。今後は、この新しい基盤を活かして検索体験そのものをさらに良くしていくフェーズに入ります。

ZOZOでは、一緒にサービスをつくり上げてくれるエンジニアを募集しています。ご興味のある方は、以下のリンクからぜひご応募ください。

corp.zozo.com

カテゴリー