☕️

カフェ混雑情報アプリimakoを支える技術

2024/12/27に公開

はじめまして、カフェ混雑情報アプリimakoの開発チームです。

私たちが開発するimakoは、2024年9月にリリースしたばかりの「どのカフェも混んでいて入れない」という課題を解決するために誕生したサービスです。
おかげさまで、キー局地上波の朝の情報番組でとりあげられたり、人気メディアに紹介されたり、と少しずつ知名度をあげているの最中です。

このimakoをどういった技術で支えているのか、最初のブログでご紹介したいと思います。
奇をてらった構成ではなくよくみかけるものですが、採用理由などを載せましたのでご参考になれば幸いです。

バックエンド

App: Ruby on Rails

Ruby on Rails のAPIモードを採用しています。はじめにカフェマスターデータ作成のロジックから実装を始めPoCとして開発チームが慣れている言語であるのが大きな理由です。

最近はTypeScriptのフレームワークが人気のようですが、現段階では他の言語やフレームワークを使う理由も見当たりませんでした。
もちろん運用を進める上でRuby on Railsの課題もでてくるかもしれませんが、現段階では特に不満を感じておらず後述のGraphQLの実装も苦になりません。

現在はRuby3.3 + Ruby on Rails7.2 の組み合わせですが、使用しているgemの対応が完了しだいRuby 3.4やRuby on Rails8へのバージョンアップを開始します。

開発チームはRubyが好きなのです。

DB: PostgreSQL

データベースはPostgreSQLを採用しました。こちらも開発チームが慣れていることに加え、位置情報を扱うアプリケーションであることからPostGISなどGIS機能が比較的充実していることをあげたことが理由です。

DynamoDBやBigQueryの直接利用なども検討はしましたが、ローカルでのテストのしにくさやデータベースという重要なリソースが特定のプラットフォームに縛られることを考慮すると、RDBMSのMySQLかPostgreSQLの2択となってしまいました。

これらのDBはどちらもシェアもあり無料で利用できるため選択する上では、Postgresのスキーマが使いたいなどの理由がない限りは、開発チームのいままでの経験や好みによってくるかもしれません。(今回も MySQLを積極的に採用する理由がなかったので、PostgreSQLを採用したが大きいです)

(初期のインフラ基盤として Render を採用したのですが、その際にPostgreSQLが利用可能だった、というのも後押しになりました)

API: GraphQL

APIのクエリ言語として、GraphQLをメインで採用しています。スキーマ駆動の開発とフロントエンドの型安全を保証したいな、という思いがあり、GraphQL採用にメリットが大きく採用しました。(それならOpenAPIでも?と思うアナタ、正解です。ただ、GraphQLのよさに気づくと戻りたくないのですよね・・・)

もちろんREST APIが存在しないわけではなく、一部の内部APIはOpenAPIで実装しています(主に、OAuth関係ですが、他にもシステム外部からのデータ取得などで利用してます)

GraphQLの問題点として学習コストの高さはよく言われます。
実際、N+1対応のためにわざわざLoader寄稿が必要だったり、リクエストの中身はすべてPOSTパラメータになるので、URLからリクエストを判別できないなど運用上の工夫が必要になったりと懸念もあります。
しかし、スキーマ駆動やフロントエンドでの開発体験はGraphQLに完全に利があり、学習コストを許容する価値はあるかなと思っています。
1から始めるからGraphQLもありだとおもいます。

ETL: Embulk

マスターの管理でGoogle Spread SheetやCloud StorageからのCSVをRDBMSなどに取り込みしており、その処理を Embulk を利用して取り込み・加工をしています。

バッチ取り込みは量が多くなるとスケーリングやデータソースの種類などが増えたりと非機能要件が増えがちです。Embulkには豊富な入出力プラグインがあり、サイズに応じてスケールすることができるなど便利なツールです。

当初も別のSaaSサービスや自前実装など検討しましたが、Embulkでの実装が一番シンプル・低コストで当面はスケーリングも可能と判断して採用しました。

Cloud Run上で動作可能なのも強みです。

フロントエンド

App: Remix(SSR) + TypeScript

フロントエンドは、2024年現在のデファクトスタンダードに近いReactを採用しました。
最初はVite+SPAモードでフレームワークを使わず実装していましたが、SSR化の際にフレームワークを導入しました。
こちらは Vite を使いReact Routerを使っている理由、 Remix の導入となりました。

Remix は開発チームが今回のプロジェクトで初めて使ったため、慣れるまでは少し苦労しましたが、React Router からの移行もシームレスに行うことができ(同じ開発元ですから)、古き良きWebアプリケーションになれていれば書きやすいなという印象でした。

おっと、今はまたReact Router V7 が2024年11月にリリースされましたね。Remix V3は(一時的ではありますか)React Router V7と統合されました。
私たちも先日アップデートを成し遂げました!

(なお、利用していたRemix Authに破壊的変更があり、それとFirebase Hostingとの相性が悪く苦労したのですがまたの機会に)

GraphQL: graphql-request + GraphQL Codegen

GraphQLクライアントは、Remixのサーバ・クライアント両方から利用でき軽量のgraphql-requestを採用しています。

SPAモードでの実装時は Apollo Clientを使っていました。SSRではサーバ側からのGraphQLリクエストが主となりApolloの強みがでないことや、SSR対応に一定の手間がかかるので、サーバ側はシンプルなクライアントのほうが好ましいので移行しました。

GraphQL Codegen は TypeScript を使うときの有名な型生成ライブラリです。このライブラリの使い方は最初クセがあり苦労しましたが、その苦労をはるかに超える恩恵を受けています。

Map: Google Map

地図はGoogle Mapを採用しています。カフェなどの店舗情報を表示するアプリケーションであり、データ量が豊富であることやアプリ利用者が慣れているマップサービスであることがあげられます。

オフィシャルがメンテナンスするJS SDKのReact版 react-google-mapsの存在も力強いです。

また、地図上に店舗を表示するものをマーカーと呼びますが縮尺によってまとめ表示をするライブラリ js-markerclustererで低コストで見やすい地図が実現できました。

一方、このフロントエンド実装で一番手間がかかっているのがこの部分であり、工夫も存在するのでいずれテックブログでご紹介できたらなと思っています。

PWA: Vite PWA

ホーム画面からの利用やWebPushの利用で、PWA構成にするため Vite PWAを採用しています。
店舗数が増えパフォーマンスに懸念がある、オフラインで利用したいなどのニーズがでてきたら開発するかもしれませんが・・・現在はそこまで手がまわっていません。

IaaS/PaaSなど

クラウド基盤: Google Cloud + AWS

クラウド基盤は Google Cloud をメインで利用しています。
ただし、一部機能は、コスト削減などの理由でAWSを利用しています。

RenderやVercelなど複数のサービスの利用も検討したのですが、それぞれ制限が多く二大クラウドを利用しました。

さきほど、地上波で放映されたとふれましたが、こちらは前もってテレビ局側から連絡を受けており数日の猶予で対策をうて耐えることができました。

その際に、1日だけDBのスケールアップしたり、Cloud Runのインスタンス数を事前にふやしたりする柔軟なリソース管理のおかげでした。
サービスを運用するといきなりこういった相談をうけることがあるので、スケーリングしやすいサービスの選択は大事ですね。

Webサービス: Cloud Run

バックエンドやSSRサーバはすべて Cloud Run を使っています。
Cloud Run はDockerイメージで、サービス・ジョブともに低コストで柔軟に使えることができ重宝しています。
コールドスタンバイの概念など、関数系のサービスに近づいてるなぁ、と思ってたいたらCloud Functionが統合されましたね。

ストレージ: Cloud Storage + S3

ストレージは、通常のテキストデータなどは Cloud Storage, 画像や動画データは S3 を利用しています。

理由はコストメリットのみです。

AWS CloudFront + S3 が現状のリクエスト数では一番もろもろの実装コストが抑えられる画像配信を作ることができました。

ジョブサーバ: Workflow + Cloud Run

ジョブの実行、依存関係やパラメータ管理のために Workflow で、ワークフローをくんで Cloud Run のジョブを呼び出すスタイルにしています。
現在は、手動実行ですが、スケジュール実行、Event Arcを使ったトリガー実行もいずれ実装する予定です。
(例えば、Cloud Stroageにデータがアップロードされたタイミングで、店舗マスターデータ更新処理を走らせる、など)

まとめ

以上、弊社サービスimakoのご紹介でした。
まだまだ成長過程のサービスですが、カフェの混雑問題に立ち向かうべく少しずつ開発しています!

ここでWe are hiring! の流れとなりますが、2024年末では募集しておりません。
ですが、もしそれでも私たちサービスに興味ありましたら、お問い合わせよりご連絡ください!

GitHubで編集を提案
imako tech blog

Discussion