Tabelog Tech Blog

食べログの開発者による技術ブログです

新卒2年目でインバウンド向け新規アプリ開発に携わった話 - 立ち上げからリリースまで

この記事は 食べログアドベントカレンダー2025 の11日目の記事です🎅🎄

こんにちは、食べログカンパニー 開発本部 インバウンド事業開発部所属のです。昨年カカクコムに新卒入社し、今年で2年目を迎えました。

本記事では、インバウンド向け食べログアプリの新規開発プロジェクトについて、筆者の目線から経験談をお伝えします。実際のプロジェクトの進め方、苦労した点、学びになった点など、具体的なエピソードを交えながらお話しします。

目次

インバウンドアプリ開発の経緯

まず、私がこのプロジェクトにアサインされるまでの経緯についてお話しします。

新卒研修の後、私は食べログカンパニー 開発本部 アプリ開発部に配属され、食べログAndroidアプリ(国内版)の保守・運用や新機能開発を8ヶ月担当しました。大規模アプリケーションの開発は学びが多く、案件ごとに多くのことを吸収できました。一方で、歴史ある食べログアプリは既に完成度が高く、大規模な改修を行う機会は限られていました。

「今後のキャリアのために、もっと大きな案件を経験したい」 そう考えた私は、チームリーダーに「規模の大きな案件があればぜひ挑戦させてほしい」と相談していました。

折しも、世の中では訪日外国人観光客が増加していました。食べログ多言語版サービスのWeb版はすでにリリースされていましたが、それに加えてモバイルアプリ版の需要も高まっていたタイミングでした。こうしてインバウンドアプリの開発プロジェクトが発足し、ありがたいことに私がアサインされる運びとなりました。

このプロジェクトは、iOSアプリ開発、Androidアプリ開発、バックエンド開発、デザイン、企画など、複数の職種が連携する開発でした。私はその中のAndroidアプリ開発の一員としてアサインされ、ベテランエンジニアの先輩方と共に開発を進めていくこととなりました。当時の私はAndroidアプリ開発の経験がまだ浅かったため、まずは基本的な画面や機能の実装から任せていただき、先輩方に学びながらチームに貢献していく形でのスタートとなりました。

開発の流れ

それでは、どのようにこのプロジェクトを進めていったのか、楽しかったことや苦労したことなど、印象的だったエピソードを交えながらお話しします。

開発序盤

自分が最初に関わったのは、「お店のこだわり」画面という比較的シンプルな画面の実装です。 この画面は構造がシンプルで、モブプログラミングを通して設計のすり合わせを行うのに最適だったため、最初の題材として選びました。

画面とコードを共有しながら、「設計上はこうすべきだが、この部分は具体的にどう実装するか?」「このクラスは、こういう理由でここに置こう」といった議論をリアルタイムで行いました。

経験の浅い私にとって、こうした先輩方の思考プロセスを間近で学べる時間は非常に貴重で、その後の開発をスムーズに進めるための大きな糧となりました。

開発中盤

デザイナー・企画担当者とのコミュニケーション

今回の開発体制では、職種の垣根を超えたコミュニケーションの場が定期的に設けられていました。

まずデザイナーとは、週2回の定例ミーティングが設定されていました。チャットだけでなく画面共有をしながら通話で議論する場があったおかげで、技術的な制約とデザインの意図をその場ですり合わせることができ、手戻りを防ぎながらスムーズに方針が決まっていきました。

また、月に1回、企画担当者に向けた対面でのデモ会も実施しました。振り返ってみて特に効果的だったのは、フィードバックを効率的に引き出せた点です。

30分という限られた時間でしたが、実機を操作してもらうことで、チャットでのやり取りだけでは挙がってこないであろう改善案や指摘を数多く得ることができました。また、そこで得たフィードバックを持ち帰ってすぐに反映していく動きが取れたため、結果として開発効率の向上に寄与したと感じています。 また、定期的に成果を見せる場があることで、開発モチベーションの維持につながったと感じています。

チャレンジを助けてくれたAI

プロジェクトが中盤に差し掛かった頃、まだ担当が決まっていない重要な機能として「予約ボトムシート」が残っていました。 これは日付・人数・予約時間を選択して予約確認画面へ遷移するための機能ですが、複数の画面から呼び出される上に、ユーザーのアクションに応じて4種類のAPIを制御する必要があるなど、比較的複雑かつビジネス的にも重要なコンポーネントでした。

予約ボトムシート

私は手持ちのタスクに余裕ができ始めており、開発への理解度も深まってきたタイミングでした。「今なら挑戦できるかもしれない」と考え、この機能の実装を担当したいと申し出ました。自分にとっては難易度が高い機能であると感じたため、まずは仕様に詳しい先輩エンジニアに設計レビューを依頼して盤石な設計を行なってから、実装に取り掛かろうと考えました。これは、AIと自分自身のガードレールを先に引いてしまおうと考えたためです。

実際には下記の流れで開発を進めていきました。

  1. Devinを使って国内版のソースコードから入念に仕様を調査・理解する
  2. 仕様に詳しい先輩エンジニアに設計レビューを依頼して設計方針を固める
  3. 設計・実装方針を盤石にした後に、機能ごとに実装を細分化
  4. 細分化した実装はCursorに任せ、自身はコードリーディングと修正を繰り返す
  5. 詳細な部分での技術的な疑問は、Cursorに聞きながら開発を進めていく

この流れで、比較的スムーズに開発を進めることができました。

実際には、のちにエッジケースの考慮漏れなどが見つかり、先輩エンジニアにフォローいただく場面もありました。しかし、結果として無事予約ボトムシートを実装しきることができ、技術的にも多くの学びを得ることができました。特に、私のような設計力の乏しい若手エンジニアがどのようにAIと協働していくと良いのかを実感できました。

開発終盤

手のつけやすい部分から開発を進めてきたこともあり、終盤に差し掛かると技術的に難しい実装や複雑な仕様に直面し、開発が難航することが増えました。その中から、特に印象に残っているエピソードを1つ取り上げたいと思います。

写真詳細画面でハマった話

プロジェクトを通して一番苦労したのは、写真詳細画面の実装でした。この画面は、アプリ内の写真をタップしたときに全画面で表示し、左右スワイプで次の写真を閲覧できる機能を持っています。一見シンプルに見えますが、遷移元によって、スワイプできる写真の枚数や表示するべき文言、機能に差があり、開発に取り掛かってみると予想以上に複雑な仕様であることがわかりました。

特に苦労したのは、以下の2点です。

1. 複数の画面から呼び出される設計

写真詳細画面は、写真表示のある全ての画面から遷移できるため、どの画面のどの場所から来たのかによって表示すべき情報や写真の枚数に差があります。そのため、遷移元を判定し、適切な写真リストを構築する必要がありました。

写真詳細画面

入念に設計したつもりでしたが、いざ実装してみると以下のような問題に直面しました。

  • 他の画面では守れていたアーキテクチャルールが、仕様の複雑化により守れなくなり、レビューで指摘を受けて初めてアーキテクチャ違反に気づく
  • 「この処理はこのレイヤーに書く」という責務の意識が薄れてしまい、ViewModel に状態更新処理を書いてしまう

こうした手戻りにより、予想以上に時間を要してしまいました。スケジュール上はテストフェーズに入りたい時期でもあったため、焦りを感じながら開発を進める苦しい時期でした。

2. ジェスチャーの競合

写真を全体表示したときのピンチイン・ピンチアウトなどのジェスチャー機能の実装にも苦戦しました。国内版を参考にしようと思いましたが、今回 UI には Jetpack Compose を利用しているため、従来のViewベースで作られている国内版とは構造が異なり、コードを流用することはできませんでした。

調査の結果、Composeの標準ライブラリ(ピンチズームやパン操作に対応した Modifier.transformable や detectTransformGestures)を使うのが最も保守性が高く、実装コストも低いと判断しました。しかし、左右スワイプ用の標準コンポーネントである HorizontalPager の上に置いた写真にこれらを適用すると、ジェスチャーイベントが内部で競合してしまい、左右スワイプでのページ送りができなくなるという問題が発生しました。

ジェスチャー競合イメージ図

左右スワイプとジェスチャーを両立させるため、当初はジェスチャーを自作しようと試みました。タップした指の本数や指間の距離をリアルタイムで計算し、ユーザーの操作を判定するロジックを、AIの力も借りながら1日ほどかけて実装しました。しかし、操作感にいまいち違和感が残ったり、タップのつもりがパン操作(写真を動かす操作)として誤検知されたりと、なかなか品質が安定しませんでした。

さらに、独自実装は保守性を下げることになり、Jetpack Composeを採用したメリットも薄れてしまいます。解決策を模索していたところ、去年のDroidKaigiでのある発表を思い出しました。「タッチイベントの仕組みを理解してジェスチャーを使いこなそう」というセッションです。

この発表の後半部分で解説されていた「スワイプとジェスチャー競合の回避策」が、まさに今回の課題に対するピンポイントな解決策となりました。 発表者の方が開発されている Zoomable というJetpack Compose用OSSライブラリの考え方が大変参考になり、最終的には detectTransformGestures の内部実装を部分的に書き換えて利用することで、上記の問題を解決することができました。

テスト・バグ改修フェーズ

機能開発が一通り完了した後は、テスト・バグ修正フェーズに入りました。テストケースについては、部内のAI推進プロジェクトで Cursor と GitHub MCP を活用してリポジトリから自動生成する仕組みを作ってくださり、2,433 項目ものテストを効率的に作成することができました。 生成されたテストケースは8割以上がそのまま採用できる品質で、工数削減と品質担保の両立に大きく貢献しました。

また、このテスト実施によって致命的なバグを発見することができました。店舗一覧から予約しようとした際、どの店舗を選択しても最初に選んだ店舗の予約に進んでしまうという不具合です。 自分の担当箇所からバグが見つかった際は、申し訳なさと同時に、リリース前に発見できて本当によかったという安堵感が入り混じりました。もしこれがリリース後にユーザーの手に渡っていたらと考えると、背筋が凍る思いでした。 テストの重要性は頭では理解していましたが、今回の経験を通して、プロダクトの品質担保と重大なトラブルの未然防止にいかに不可欠かを、身をもって実感することができました。

いよいよリリース

リリース直前のトラブル

多言語アプリならではの課題にも直面しました。テストと修正が完了し、Google Play Store への申請に向けてリリースビルドを行ったところ、リリース版のAPKに限って言語切り替えができないという不具合が発生しました。

原因は、コードの難読化処理によってアプリ内の多言語文字列リソースまで削除されてしまっていたことでした。リリース直前で緊張が走りましたが、チームで話し合っていたところメンバーの1人が迅速に解決策を提示してくれ、Gradleの設定で特定のリソースを保持するよう指定することで無事解決できました。

リリース、そして今後

こうして様々な困難を乗り越え、11月10日に無事リリースを迎えることができました。ありがたいことにユーザー数も日々増えており、リリースから1ヶ月で、iOS・Android合わせて30万インストールを突破しました!

リリース後、組織改編により新たに「インバウンド事業開発部」が発足し、私はそこへ配属されることになりました。これまではジュニアエンジニアとして先輩方に学びながら開発に参画する立場でしたが、今後は自分が主体となってプロダクトを牽引していくことが求められます。 このアプリは今後、様々な施策や新機能開発を経て、訪日旅行者に特化したアプリへと進化していきます。その中で私も、単に依頼された機能を開発するだけでなく、エンジニアの視点から積極的に意見を発信し、プロダクトの成長と品質向上に貢献していきたいと考えています。

最後に

新卒2年目というタイミングでこのような新規アプリ開発に携わり、立ち上げからリリースまでを一貫して経験できたことは、今後のエンジニアキャリアにおいて大きな財産になると思います。 また、未熟な私に対して丁寧なコードレビューや手厚いフォローをしてくださったチームの皆さん、そして私の意欲を汲み取り挑戦の機会を与えてくださった上長には、心から感謝しています。

明日は 羽澤さん の「Devinを食べログに広めるためにやったことと、その学び」です。お楽しみに!


食べログでは、20年の歴史を未来へ繋いでいく仲間を募集しています!
ご興味のある方は、ぜひこちらもチェックしてみてください。