出前館のオーダーブースト広告を支える技術(と私)
はじめに
はじめまして。出前館のマーチャント部でサーバーサイドエンジニアをしている石井です。
今回は11月末にリリースとなりました出前館のオーダーブースト広告に関する概要とそれを支える技術について、個人的な想いなども交えながら紹介します。
オーダーブースト広告とは?
オーダーブースト広告とは、ユーザーごとにパーソナライズされた店舗の情報を出前館サービスの広告枠に掲載できる加盟店向けの広告プロダクトです。
出前館サービスの広告枠に自店舗の店舗情報を掲載することで、店舗の認知拡大と注文数増加を促すことを目的としています。
出前館、加盟店の売り上げ拡大に貢献する「オーダーブースト広告」を提供開始
出前館には従来よりPR枠と呼ばれる出店店舗を広告する機能がありましたが、新しいオーダーブースト広告では下記の点が改善されており、より訴求効果の高い販促を手軽に実現できるソリューションとなっています。
広告PR枠 | オーダーブースト広告 | |
掲載位置 | 出前館のWebサイト、Android/iOSアプリのTOP画面 | TOP画面に加え、ジャンルや検索結果画面などにも掲載される |
掲載期間 | 期間指定(一ヶ月など)での掲載 |
出前館マネージャーアプリ(加盟店向けの管理アプリ)から自由にON/OFF可能 |
表示方法 | ランダム表示 | 注文確率の高いユーザーにマッチングさせて表示 |
課金形態 | 固定費用が発生 | 成果報酬型(広告経由での注文がなければ0円) |
改善イメージ
オーダーブースト広告は、Moloco社が提供するMoloco Commerce Media(以下MCMと表記)が軸となっています。
MCMは生成AIを活用した広告ソリューションで、ユーザーの好みやニーズに合わせた関連性の高い広告掲載を可能にします。
出前館とMoloco、高度なパーソナライズ広告の実現に向けた協業を発表
オーダーブースト広告を実現するアーキテクチャ構成
出前館の開発組織では、MCMを効率的に活用できる構成について既存のアーキテクチャをベースに検討を行いました。
前提として、出前館システムはドメインロジックの集約や開発生産性の向上などを目的としたマイクロサービスアーキテクチャの形で構成されており、主な構成要素としては下記のようなものがあります。
- 出前館ユーザーからのリクエストを受け付ける出前館のWebサイトとAndroid/iOSアプリ、及びそれに対応するBFF(Backend For Frontend。フロントエンドからのリクエストを集約し、後続のシステムに流す役割を持つ)
- 店舗オーナー(図内でShop Ownerと表記)からのリクエストを受け付ける出前館マネージャーアプリ(図内でManager-Appと表記)とそのBFF
- 上記BFFからリクエストを受け付ける各種ドメインサービス(Cart Serviceなど)
今回Moloco社のMCMの導入にあたり、広告ドメインのロジックを集約し、MCMへのアクセスのHubとなるAd Serviceというcomponent(※図内赤枠)を新設しました。
主なデータの流れは下記のようになっていて、これによりMCMとのデータ連携及びエンドユーザーへの広告表示を実現しています。
- Ad Serviceのバッチ処理で広告データの元となる店舗情報をMCMに連携
- 出前館マネージャーアプリから広告掲載を設定
- (出前館のWebサイトとAndroid/iOSアプリに広告として店舗の情報が表示される)
- ユーザーが広告経由で注文を行う
- 注文イベントがMCMに連携され、広告消化の実績として集計される
今回私はAd Serviceの開発リードとして、同サービスの立ち上げからリリースまでの業務に携わりました。
Ad Serviceを開発した背景
元々、出前館には広告に関するcomponentやシステムがなく、当初の想定では出前館のWebサイトのBFFやManager-AppのBFFから直接Moloco社のシステムと通信する形が想定されていました。
しかし「Moloco社への通信処理が分散してしまうと、ビジネスロジックが集約されず不整合やプロダクト全体の品質低下を招くのではないか?」という懸念があり、Ad Serviceを構築する流れになりました。
とはいえ当初想定外のcomponent追加となったため、担当者は不在でプロジェクトは見通しが立たない状況になっていました。
そのような中で私は思いました、「これはエンジニアとして良き成長が得られるきっかけになるのではないか?」と。
シニアエンジニアになるための近道として「全てのゼロイチ構築をリードする」、「何かあっても全て自分が判断し対処しなければならない環境に身を置く」というのがあると思います。
今回のプロジェクトはそれに近い所があり、そういった開発リードとしての経験を積むためには絶好の機会でした。
実際に出前館には頼れるマネージャーや優秀なエンジニアがたくさん在籍しています。これまでそういった方々と仕事をして得てきたナレッジもあったので、その蓄積を活かせば成功確率も十分だろうという確信がありました。
すかさず私は開発リードとして立候補し、Ad Serviceの開発チームを新規に立ち上げ、リリースまでのマイルストーンを策定し開発を進行していきました。
Ad Serviceについて
今回、Ad Serviceでは下記のような技術スタックを採用しました。
VerdaというのはLINEヤフー社のプライベートクラウドであり、サーバー、ロードバランサー、ストレージなどの仮想化リソースやデータベースなどのマネージドサービスを社内に提供しています。
出前館ではクラウド環境としてVerdaの他にAWSも扱っており、componentの性質によりそれらを使い分けています。
今回Ad Serviceでは、社内のインフラチームの協力の元、VerdaのKubernetesクラスタにKotlinのサーバーサイドアプリケーションとしてAPIやBatchをデプロイし、実行ログやメトリクスなどをNew Relic及びSlackを使って監視できる形に構築しています。
その他、CIではGithub Actions、CDではArgo CDを採用。特にデプロイ部分ではArgo Rolloutsを使用することで、カナリアリリースとゼロダウンタイムでのデプロイを実現し、Trafficがある日中帯でもデプロイが可能となってデリバリーの効率化に貢献しました。
アプリの言語としてはKotlinを採用。モダンな開発言語であるため表現力に優れ、Javaのエコシステムとも接合でき、社内に有識者も多いといった所で導入してたくさんのメリットがありました。
開発時のポイント
Ad Service開発時のポイントとして、プロダクトのソースコードをモノレポ(Mono Repository。単一のGit Repositoryのこと)で管理しているというのがあります。
Ad Serviceのリポジトリでは下記のようなディレクトリ構成を採用しています。(※ビルドツールはGradleを使用)
全体で一つのGradle Projectとなっており(build.gradle.ktsも一つだけ)、その中でsub projectとしてappやusecaseなどのGradle Projectを管理する形をとっています。
各projectは、図の矢印の方向に従って依存関係が成り立つようにbuild.gradle.ktsで制御しています。
appはAPIサーバやKafkaのSubscriberなど実行単位ごとに分けていて、その中で共通的にusecaseを呼び出して手続き処理を実行し、infraにて外部システムやミドルウェアへのI/Oを行うという、ある意味「分散と集約のいいとこ取り」のような形になっています。
また、Ad Serviceの特徴として外部システムへのI/O処理が多いというのもあるので、そういった意味でも理に叶った構成となっています。
トータルで見るとコンパクトにまとめつつコア部分を共通的な形に集約した形になっていて、管理コストの削減や開発スピード/品質の向上を実現しています。
その他、基本的な考え方としてはシンプルなDDD(Domain-Driven Design。ドメイン駆動設計)を採用しており、ビジネスロジックに関する処理はdomain model内に集約して他projectからそれを呼び出す形としています。
運用時のポイント
運用時のポイントとしては、New RelicのDashboardで主要メトリクス(CPU/メモリ使用率、分間リクエスト数、レイテンシ、エラー件数など)のモニタリングをしていることが挙げられます。
New RelicではNRQL(New Relic Query Language)を使ってメトリクスデータを抽出しグラフ表示させることができ、これがサービスの安定稼働に役立っています。
メトリクスデータの転送にはOpen Telemetryを使用していますが、これは上記のメトリクスの他、JVMのスレッド数やDBのコネクション数、Kafkaの処理レコード数など様々なニーズに応じたメトリクスを収集することが可能です。
現場ではこれを一目でわかるような形でDashboard化して簡単に確認できるようにしており、何か異常がみられた際もクイックにNext Actionを検討できるようになっています。
勿論、主要メトリクスの異常時はslack通知のアラートを設定しているので、開発者が迅速に気付くことできます。
New RelicのDashboardの例(APIサーバのCPUやメモリ使用率が時系列に沿って表示されています)
まとめ
以上、出前館のオーダーブースト広告の概要とそれを支える技術について簡単に説明させていただきました。
上記の他、GatlingをKotlinで書いて性能テストをサクサク回していった話や、Argo CDのApp of Appsを使ってインフラ作業コストを減らした話など、工夫点はたくさんありますが文字数の関係でここでは省略します(また機会があれば是非シェアさせてください)。
プロジェクト全体としては他にもたくさんの困難があり、失敗や頓挫も想定されましたが、素晴らしいメンバーに支えられ無事スケジュール通りのリリースを迎えることができました。
私の理想のエンジニア像として「開発の困難を巻き取ってQCDS(Quality(品質)、Cost(コスト)など開発の評価における指標のこと)を担保し、周囲に信頼と良い影響を与える」というのがありますが、このプロジェクトを通してそこに一歩近づけたのかなと思っています。
「点と点を線で繋ぐ」という言葉がありますが、サーバーサイドエンジニアにとって必要なのは日々の蓄積とそれを繋ぐ挑戦(チャレンジ)なのかもしれません。
上記のように、出前館には面白いプロジェクトや刺激を得られる仲間がたくさん待っています!
私も、今ご覧になっているあなたと一緒に仕事ができる日を楽しみにしています。
最後に、同じマーチャント部に属している倉井さん、古田さんの技術ブログも紹介しておきます(おふたりからはたくさんのことを学びました)。