Findy Tools
開発ツールのレビューサイト
目次
Xのツイートボタン
このエントリーをはてなブックマークに追加
Xのツイートボタン
このエントリーをはてなブックマークに追加
出前館のマルチプロダクト戦略を支えるアーキテクチャ〜技術的負債を解消しながら事業を多角化する〜
公開日 更新日

出前館のマルチプロダクト戦略を支えるアーキテクチャ〜技術的負債を解消しながら事業を多角化する〜

2024年11月26日(火)、ファインディ株式会社は「アーキテクチャConference 2024」を開催しました。本カンファレンスは、浜松町コンベンションホール & Hybrid スタジオのオフライン会場にて実施され、一部オンライン配信も行われました。
株式会社出前館は、1999年の設立から長年に渡り、フードデリバリーサービス「出前館」を運営。日々プロダクトをグロースさせながら技術的負債の解消にも取り組んでいます。そして2024年8月、新サービス「クイックマート」をリリースしました。
本カンファレンスでは、「出前館のマルチプロダクト戦略を支えるアーキテクチャ〜技術的負債を解消しながら事業を多角化する〜」と題して、プロダクト本部 プラットフォーム部 TechPMの阿部 将久氏が登壇。出前館がマルチプロダクト戦略を実現するまでの道のりを、失敗談も交えてお届けします。

■登壇者
株式会社出前館 プロダクト本部 プラットフォーム部 TechPM
阿部 将久(あべ のぶひさ)
SIerにて金融領域のTechLead、ProjectManagerとして、新サービスの立ち上げや大規模な基幹システムのリプレイスなど様々なプロジェクトを経験する。その後、LINEヤフー(ex. LINE)にてLINEモバイルのGrowth開発に従事した後に出前館に出向。出前館ではTechPMとしてレガシーシステムのリプレイスや、新サービス(クイックマート)の開発マネジメントを担当する。

出前館の新プロダクト「クイックマート」

出前館は設立から25年にわたり、「出前館」という単一のプロダクトを開発・運用してきました。フードデリバリー事業で大きな成長を遂げた私たちでしたが、さらなる成長のためにノンフード領域への拡大という新たな課題に向き合うことになりました。
そこで2024年8月、LINEヤフーとの共同事業として立ち上げたのが「Yahoo!クイックマート」です。食品や日用品を最短30分でお届けする、いわゆるクイックコマースと呼ばれるサービスです。



クイックマートの大きな特徴は、既存の出前館とは異なり、ユーザーが「Yahoo!ショッピング」から商品を注文できる点にあります。Yahoo!ショッピング上のクイックマートから注文を受け付けると、その情報は出前館を経由して加盟店や配達員に連携され、商品配達へとつながっていきます。
一見すると既存の出前館のシステムと似たような仕組みに見えるかもしれません。実際、ユーザー向けのチャネルが異なるだけで、加盟店や配達員向けのチャネルは出前館のプラットフォームを利用しているという点で、非常に似たスキームとなっています。



こうした背景から、私たちはクイックマートの開発において、重要な決断を迫られることになります。それは、「作らない開発」を目指すべきか、それとも新規開発に踏み切るべきか、という選択でした。


作らない開発を目指したが失敗した話

最初に私の頭に浮かんだのは、「もしかしたら、システム同士をつなぐだけで、何も作らずに新サービスが立ち上げられるのではないか」という淡い期待でした。既存の出前館のシステムとYahoo!ショッピングを連携させれば、新たな開発をほとんどせずにサービスを開始できるのではないか──そう考えたのです。

しかし、実際にはそう簡単な話ではありませんでした。大きく分けて2つの課題に直面することになったからです。

1つ目は、フードとノンフードのドメインの違いです。たとえば、医薬品はフードにはない、ノンフード固有の商品です。医薬品を販売する場合は日本の法令を遵守する必要があるため、規約への同意やアンケートへの回答など、フードにはないようなユースケース・フローが発生します。

また、商品を出店する際の免許確認についても違いがあります。フードではお酒の確認程度で済むのに対し、ノンフードでは医薬品やタバコなど、さまざまな商品で確認が必要になります。

在庫管理の考え方も大きく異なりました。飲食店の場合、食材から料理を作るため、在庫は「欠品しているかどうか」程度のシンプルな管理で十分です。一方でノンフード、特にコンビニやドラッグストアの場合は、実際の商品を物理的に在庫管理する必要があります。

さらに、ピッキングの概念も違います。フードの場合、配達員が店舗で料理を受け取るだけですが、ノンフードでは注文が入った後に加盟店スタッフが店舗内を回って商品を集める必要があります。場合によっては、システム上は在庫があっても実際には商品が見つからないということも起こり得ます。

特に、この在庫管理とピッキングの違いは、私たちにとって大きなインパクトがありました。フードのコンポーネントを流用できたとしても、ノンフード用に大幅な修正が必要になることが明らかになってきたのです。

2つ目の課題は、出前館本体の事情でした。実はこの時期、出前館ではフードのシステム刷新を進めていました。25年という長い歴史の中で、定期的なシステムのリニューアルは避けられません。そのタイミングで、フードの基盤を刷新しながら、ノンフードの新規事業を立ち上げるという状況だったのです。

経験のある方ならご存知かと思いますが、システムのリファクタリングをしながら新機能を追加するというのは、非常に難しい作業です。また、刷新前の古いコンポーネントをノンフードで流用してしまうと、新しいサービスが技術的負債を抱えたままの状態でスタートしてしまうリスクもありました。

こうした課題を検討した結果、私たちは当初想定していた「フードとノンフードの共通化」という選択肢を見送ることにしました。そして最終的に、オーダーやマーチャントといった主要なコンポーネントをフードとノンフードで別々に作成する構成を採用することにしたのです。




15のコンポーネントを4か月で作りきった話

フード/ノンフードを分離するのか、共通化するのかという課題も解決し、いよいよ開発という段階になりました。ただ、分離したことで開発対象のコンポーネントが増えすぎてしまうという課題があり、ここで私たちは頭を悩ませることになりました。

開発したコンポーネントは大きく3つのグループに分けられます。 まず、Yahoo!ショッピングとの連携を担当するサードパーティコンポーネント群。次に、注文や店舗、商品を管理するコアコンポーネント群。そして加盟店とのインターフェースとなるadmin、app、POSなどのコンポーネント群です。これらの多くはノンフード専用として新規開発しましたが、位置情報管理やアカウント管理など、一部のコンポーネントはフードと共通化して実装しています。



このように、私たちは大量のコンポーネント開発という課題に直面することになりました。これらのコンポーネントを短期間で開発するため、私たちは2つの技術的アプローチを採用しました。

マイクロサービス

一般的に、0→1のフェーズでは不確実性が高く、変化に柔軟に対応する必要があります。そのため、少数精鋭で進めるモノリシックな開発スタイルが選ばれることが多いのですが、私たちはあえてマイクロサービスアーキテクチャを選択しました。

その理由の1つは、クイックマートが持つアクターとユースケース、ドメインの多さです。ユーザー、加盟店、配達員、CSなど複数のアクターが存在し、それぞれに多岐にわたるユースケースがありました。MVPの段階でこれだけ多くの機能が必要な状況では、独立したチームが並行して開発できるマイクロサービスが適していると考えたのです。



また、私たちには大きなアドバンテージがありました。出前館のメンバーはフードの開発を通じて高いドメイン知識を持っており、マイクロサービスの開発・運用経験も豊富だったのです。これにより、マイクロサービスでよく課題となるドメイン分割の切りどころなども、無理なく解決することができました。

イベント駆動

もう1つの重要な技術選択が、イベント駆動の採用です。具体例として、注文キャンセルのフローを見てみましょう。

商品の在庫切れや配達不可など、さまざまな理由で発生する注文キャンセルは、出前館の重要なユースケースの1つです。このフローをREST APIで実装すると、オーダーサービスが全体のフローを理解し、適切なAPIを適切な順序で呼び出す必要があります。さらに、APIコールの失敗時のエラーハンドリングなども考慮する必要があり、オーダーサービスの負担が大きくなってしまいます。

そこで私たちは、イベント駆動のEvent Sourcingを採用し、サービス間のインターフェースにQueueを利用することで依存関係を逆転させました。これにより、オーダーサービスは後続の処理を意識することなく、単にキャンセルのイベントをプロデュースするだけでよくなりました。後続のサービスは、そのイベントをトリガーとして主体的に処理を進めることができます。




インターフェース定義にはprotobufを採用し、インターフェースをスキーマとして定義・共有することで、認識の齟齬によるコストも削減できました。また、決済のロールバックなど、結果整合性が必要なケースについては、補償トランザクションを採用することで、エラーハンドリングもシンプルに実装することができました。


クイックマートの開発を振り返って〜成功と失敗〜

最後に、クイックマートの開発を通じて学んだことを、成功談と失敗談として振り返っていきたいと思います。

成功談:分離による恩恵

フードとノンフードを分離した判断は、結果として大きな価値を生み出しました。3つの具体的な事例で説明します。

1つ目は、高いアジリティの実現です。実はサービスリリース直後、注文のキャンセル率が40%付近で高止まりするという問題が発生しました。しかし、フードとノンフードのシステムを分離していたおかげで、コアスペックの修正を約1日という短期間で完了できました。もしフードシステムへの影響を考慮しながらの修正が必要だった場合、この迅速な対応は困難だったでしょう。

2つ目は、インターフェース起因のバグの最小化です。マイクロサービスアーキテクチャでは、多数のインターフェースが存在するため、それに起因するバグが発生しやすい傾向にあります。しかし、私たちはイベント駆動を採用し、gRPC/protobufでインターフェースを定義することで、この問題を最小限に抑えることができました。その結果、短期間での開発でありながら、高い品質を維持することができました。

3つ目は、フードの障害がノンフードに影響を与えなかったことです。実際に、出前館本体がマルウェア感染により長期間のサービス停止を余儀なくされた際も、クイックマートは通常どおり稼働を継続することができました。これは、フード/ノンフードの分離によって単一障害点をなくしたことの成果といえます。アーキテクチャ設計においては、開発効率だけでなく、このようなサービスレベルの観点も重要な検討事項となるのです。




失敗談:見落としていた課題

一方で、いくつかの失敗も経験しました。1つ目は、インターフェース定義の統一化における課題です。イベント駆動におけるgRPC/protobufの有効性は認識していたものの、すべてのインターフェースでの採用には至りませんでした。一部のインターフェースでREST APIを使用せざるを得ない状況が発生し、その結果、インターフェースの認識合わせに多大な時間を要することになってしまったのです。
特にテストフェーズでは、REST APIのインターフェース部分に苦戦することとなりました。サービス間のインターフェースが多いクイックマートにおいて、インターフェース定義の一貫性は特に重要な要素です。この経験から、次回のプロジェクトではgRPC/protobufの採用をより積極的に推進する必要性を痛感しています。

2つ目は、ノンフードのドメイン特性に対する理解不足です。機能面でのドメイン特性は理解していたものの、非機能要件に関する理解が不十分でした。
特に顕著だったのが、商品登録における規模の違いです。フードの場合、1店舗あたり最大100商品程度でしたが、ノンフードではコンビニやドラッグストアで最大1万件の商品を1リクエストで登録する必要があります。この規模の違いに開発途中で気づいたため、同期処理から非同期処理への設計変更を余儀なくされました。この経験から、ドメイン特性の理解には機能面だけでなく、非機能面の検討も不可欠だということを学びました。

そして3つ目は、フード/ノンフードを完全に分離できなかった点です。フードではNumeric型の連番ID(1, 2, 3...)を使用していたのに対し、ノンフードではより柔軟なID体系としてULIDを採用しました。しかし、一部の共通コンポーネントでULIDを受け付けられないことが判明し、ノンフード用にNumeric型IDの二重採番が必要になるという事態に。事前の検証段階で、ID体系のような技術的な詳細まで調査すべきでした。


最後にまとめです。
出前館のような歴史のある企業でも、新プロダクトを短期間で開発することはできます。大変なことはたくさんありますが、何とかなります。また、クイックマートのように既存のプロダクトを水平展開する場合でも、ドメイン特性が異なる場合は新規開発するのがおすすめです。今振り返っても、私たちのこの選択は正しかったと確信しています。

マイクロサービスアーキテクチャは0→1の開発でも有効な選択肢になります。ただし、これはドメイン知識が豊富にある場合に限られますのでご注意ください。