「秘伝のタレ」を未来のシステムへ繋ぐ ── フィーチャー分割で実現した商品詳細APIリプレイス

「秘伝のタレ」を未来のシステムへ繋ぐ ── フィーチャー分割で実現した商品詳細APIリプレイス

はじめに

こんにちは。ZOZOでアプリバックエンドブロックのブロック長をしている湯川です。以前公開した記事では、ZOZOTOWNアプリ用APIのリプレイスの初期の開発・課題・解決方法などについて紹介しました。

techblog.zozo.com

今回はその続編として、商品詳細APIリプレイスをどのように進めたのかを紹介します。今回のリプレイス対象は、約5,000行のコードと約410項目のレスポンスを持つ巨大なAPIでした。長年の機能追加によって複雑化し、いわゆる「秘伝のタレ」と呼ばれる状態になっていました。

しかし本記事でお伝えしたいのは、単なるAPIリプレイスの話ではありません。

限られた期間の中で、以下に着目して大規模リプレイスを進めるための技術とマネジメントの取り組みについて紹介します。

  • 巨大なモノリスをどう理解したのか
  • 並列開発が可能な構造をどう作ったのか
  • なぜ3チームでの開発が可能になったのか

目次

迫る期限と見えない全体像

商品詳細APIリプレイスの着手時点で、私たちには大きな課題がありました。リプレイス前のAPIサーバーはオンプレで稼働しており、その縮退スケジュールは既に決まっていました。一方で、商品詳細APIは長年の改修によって巨大化しており、全体像を把握できるメンバーは誰も居ない状態でした。

価格、在庫、商品画像、サイズなど、多数の機能が単一APIに集約されていました。変更の影響範囲は広く、機能間の依存関係も複雑です。先述の通りコード量は約5,000行、レスポンス項目は約410項目もありました。

当然ながら、「どれくらい時間がかかるのか」すら正確には分からない状態でした。

「どんな手段を使ってもいい」

そんな状況の中で、上司から言われた言葉があります。

「どんな手段を使ってもいいので、達成方法を考えてほしい」

振り返ると、この一言が大きな転換点でした。

通常であれば、今いるチームで進めることを前提に考えがちです。既存の役割分担を維持し、既存の開発プロセスに合わせるのが普通です。

しかし、この言葉によって私自身がその前提を外せるようになりました。

  • チーム構成も変えていい。
  • 担当範囲も変えていい。
  • 進め方そのものを変えていい。

ならばまず、「この巨大な塊をどう攻略するか」を考えるべきだと思いました。

突破口となったフィーチャー分割

私は本案件の開発をリードするカイルさんに「どうにかしたいから対応方法を検討してほしい」と依頼しました。

カイルさんは前編で紹介したフェーズ3からリプレイスにJOINしたメンバーで、このプロジェクトではアーキテクトも担当しています。

様々な切り口で分割を検討した結果、彼が提案したのはフィーチャー単位での分割でした。この分割方法を掘り下げるため、カイルさんにインタビューしてきました。

湯川:最初に「どうにかしたいから対応方法を検討してほしい」とお願いしましたが、どうやってフィーチャー分割という発想に至りましたか?

カイル:最初はUIコンポーネント単位、レスポンスオブジェクト単位、データソース単位なども検討しましたが、レガシーエンドポイントのためコンポーネント間やオブジェクト間の依存関係が複雑です。開発単位として独立できないと思いました。その時、「このAPIをアジャイルでゼロから作った場合、どの粒度でどの順番で作っていくんだろう」と想像してみました。そうすると、ECサイトの商品ページに絶対必要なコアな機能と、一旦MVPができた状態で後から追加する細かい機能という粒度で分けられることに気づきました。

湯川:商品詳細APIは機能が多いですが、具体的にはどう整理しましたか?

カイル:そうですね、全部で41フィーチャーになりました。これだと依存関係や開発する順番を整理するのが大変そうだったので、細かい機能をさらに「基本機能」「商品タイプ」「追加機能」などカテゴリに分類しました。それぞれのカテゴリをひとつのフェーズとして順番に開発していくイメージです。

湯川:振り返ってみて、分割の観点で学びはありましたか?

カイル:「商品タイプ」のフィーチャーは様々な機能に横断して影響することが多く、分割観点としてあまりよくなかったかもしれません。後のショップ詳細APIでは、商品の属性ではなく機能の軸で分割するようにしました。例えば「◯◯ショップの商品」ではなく「特定ショップの専用UI」や「特定ショップのカテゴリ」というふうに細かく分けています。

このようにして、巨大なAPIを構造で捉えることができるようになりました。

さらに、分割のアウトプットとして、各フィーチャーごとに以下の情報もまとめてありました。

  • レスポンス項目
  • 既存コードで該当箇所がわかるコメントをうったコミット
  • 利用している外部API・マイクロサービス一覧

これらの対応によって、1チームで進めた場合は約1年規模という見積もりが出ましたが、並行開発という選択肢を取れるようになりました。ただし、並行開発を実現するためには、フィーチャー間の依存関係を明確にする必要がありました。

依存関係を可視化する

次に取り組んだのは依存関係の詳細な整理です。

  • 依存度の高いフィーチャー
  • 独立性の高いフィーチャー

どちらが先に必要か、どこがボトルネックになるかを構造として把握できるように再度コードを解析し、各フィーチャーごとの依存関係を明確にしました。

NotebookLMを使って、依存関係を動的に可視化できるインフォグラフィックも作りました。 フィーチャー間の依存関係を可視化したグラフ

私たちはこの作業を通じて、「どう実装するか」ではなく、「どこなら並列化できるか」を考えられるようになったのです。

構造を見てから戦略を立てる

ここでようやく組織の話になります。一般的には、先に体制を決めてから仕事を割り振ります。

しかし今回は逆でした。まず構造を理解し、次に依存関係を整理し、最後に組織を設計します。

つまり、組織に合わせてアーキテクチャを作るのではなく、アーキテクチャに合わせて組織を設計しました。

依存度の高い基本機能は特定チームが担当し、独立性の高い機能は別チームに任せます。

スプリントごとに担当フィーチャーを計画しながら、3チーム並列での開発体制を構築しました。

スケールできた理由

もちろん、人を増やしただけでは成功しません。むしろ、「人月の神話」の通り、遅くなることもあります。そこで私たちは、仕様理解のコストを下げることに注力しました。

実は商品詳細リプレイスの数か月前から、別チームがUIとレスポンスを紐付けた仕様書を整備していました。この仕様書が、フィーチャー分割、開発、テストのすべての基準になりました。

さらにレガシーAPIのリプレイスを進めていく中で、タスクテンプレートを整備し、チーム間でタスク粒度をある程度統一していました。

結果として、3チーム並列でもタスクの粒度が揃っているため、開発の相談ごとが発生しても連携がスムーズでした。

あえて改善しない

もう1つの成功要因があります。それは、改善しないことを決めたことです。商品詳細APIには改善余地が数多くありました。せっかくリプレイスする・作り変えるのであれば、「不要と思われる仕様をなくしたい」「レスポンス構造も整理したい」「より適切なエラーハンドリングをしたい」と思います。

しかし、それを始めると終わりが見えません。これは今までのリプレイスプロジェクトで得た知見でした。

今回の目的は改善ではなくリプレイスです。

そのため、現行をそのまま置き換えることに徹底的に集中しました。この意思決定によって議論が減り、スピードが大きく向上しました。

結果

最終的に、以下の様々な良い結果を得ることができました。

  • 3チームによる並列開発を実現
  • 約1年規模だった開発を約3か月で完了
  • サイクルタイムを50%改善
  • レイテンシーを50%改善
  • リプレイス前のAPIサーバーのCPU負荷を70%削減(ピーク時)
  • 不具合による切り戻しは0件

品質とスピードを両立しながら、オンプレサーバー縮退にも大きく貢献できました。

まとめ

今回のリプレイスを振り返ると、成功要因はやはりこのフィーチャー分割です。

このフィーチャー分割がきっかけで、後続のリプレイスも順調に進行しました。分割方法も改善を重ね、より細かくユーザーストーリーにあわせた分割ができるようになりました。そして、何より3チームのみんなで同じ目標に向かって開発を進めていくことができたのも大きな成果でした。

今回のプロジェクトは、まさにZOZOが大切にしている「想像」と「創造」を体現した取り組みだったと感じています。

この経験が、同じように大規模リプレイスへ挑戦する方々の参考になれば幸いです。

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

corp.zozo.com

カテゴリー