キャンプアプリのシステムアーキテクチャの紹介🏕️
こんにちは!おぎーです。既に暑い日々が続いており溶けてしまいそうです🫠 今回は先日ベータ版をリリースしたキャンプアプリ「Campsyte(キャンプサイト)」のシステムアーキテクチャを紹介していきます!
アプリの概要
システムに関する話をする前に、キャンプアプリに関して再度紹介させてください!キャンプアプリ「Campsyte」では主に3つの機能を提供しています。
気になるキャンプ場を楽しみながら探す 🔍
予定を立てる/準備する🗒️
ノンストレスな当日の移動や買い出し 🚗
詳しくは前回のnoteに詳しく紹介しているので、そちらも読んで頂けると幸いです!
システムアーキテクチャ
Campsyteのシステム構成は大きく「アプリ」と「バッチ」の二つに分かれており、構成は以下のようになっています。
FirebaseというGoogleのアプリ開発プラットフォームを使って構築しています。アプリはFlutter、APIサーバーはGolang、バッチ処理はPythonを用いて開発しています。前職在籍していた「Chompy」のシステム構成にとってもインスパイアされています。
プロジェクトはモノレポ開発で管理しています。現状は一人での開発なのでとても楽に管理ができて良いです🏕️
次に簡単な構成等について紹介します。
アプリ (Flutter)
アプリはFlutterを用いて開発しています。Flutterは前職からがっつり使っており、既に多くのサービスなどで開発/利用実績があったので採用しました。僕が今一番自信のある言語です💪
構成は以下のようになっています。
FeatureFirstなディレクトリ構成
Riverpodによる状態管理
go_router による画面遷移
レイヤー毎にディレクトリを分けるのではなく、「Campsite」や「Auth」のようなFeature毎にディレクトリを分ける構成をしています。Webやアプリ開発においては経験的にこの構成の方が見通しが良くなると個人的に思っています。
基本的な考え方として関連性のものは寄せる(無闇にファイルを分けない)こともとっても重要だと思っています。Flutter x Riverpodによる開発は村松さんの記事がとっても参考になります!有料ですがその価値は十分にあるのでおすすめです。
API (Golang, Protocol Buffers, Firestore, Elasticsearch)
APIサーバはGolangで開発しています。フレームワークは特に使わずレイヤードアーキテクチャ+DDDの構成を用いて開発しています。APIはProtocolBuffersで定義しgRPC通信でアプリと疎通を行なっています。アプリからバッチサーバーまでのスキーマ定義を共通化することができとって良いです☺️
データベースはFirestoreを採用しています。NoSQLデータモデルでリレーショナルデータベースとは別物でクセが強いですが、個人的には以下の理由でFirestoreを推しています。
サブコレクションという仕組みでドキュメントに対してネストしたオブジェクトを格納できわかりやすい
ドキュメントに対してリストやマップなど複雑なオブジェクトを含めることができる
フルマネージドでスケーラブル、料金体系は従量課金で低コスト
特に2, 3は低予算でたくさんの仕様変更がある個人開発やスタートアップにとってとてもメリットがあると個人的に思っています。
前職で初めてFirestore(NoSQL)を使ってみましたが、JOINがない世界に最初はかなり違和感がありました。そんな時に村本さんの以下のQiitaの記事がとっても参考になりました (3年以上前の記事ですが今でもとっても参考になると思います)
Firestoreは複雑な条件によるデータの取得ができないため、検索機能などの提供は困難です。そのため、検索やホーム画面のリスト表示についてはElasticsearchを用いています。
Elasticsearchは大容量データを処理できる分散型検索エンジンです。FirestoreのデータをElasticsearchに同期させ、検索等の機能を実現しています。さらに、Elastic App Searchという検索エンジンサービスを用いることでより簡単に処理を実現することができています。
Elastic App SearchはElasticsearchのアプリケーション検索機能をより使いやすく抽象化されたサービスで、スキーマやデータ管理をよりわかりやすく行うことができます。
FirestoreとElastic App Searchとのデータ同期についても、Firebase Extension HubにてExtensionが提供されているので、簡単に構築することができます。
ただElasticsearchのGolang公式ライブラリ「go-elasticsearch」ではAppSearchを使うことが多分できなく、自前でHttpクライアント等を実装する必要があるのが注意点です。余裕がもしできたら、ラッパーのライブラリを公開できると良いかもと思っています。
バッチ (Python)
Campsyte上で表示されるためのデータ生成処理はPythonを用いて開発しています。現時点では以下のような処理を開発しています。
キャンプ場に関するデータの収集と生成
キャンプに関するYouTube動画やニュース記事の収集と紐付け
キャンプ場の予約空き情報の収集(開発中)
キャンプ場との紐付けやレビューの要約、チェックイン/アウト時間などフリーテキストの正規化なども行なっており、ここでは生成AIやMLなどの技術も用いて頑張っています。キャンプ場に関するデータは Google Places API (New) と各キャンプ場の公式サイト、キャンプ場予約サイトなどのデータを収集・加工し生成しています。
Google Places API (New)は最近Geminiと連携されており、近々日本でも場所ごとの特徴の要約機能が提供されるとのことでとても楽しみです🥰
※ 元々 旧Places API を用いて開発してましたが、このニュースを読んで強い気持ちで Places API (New) に移行させました。新旧で仕様がかなり異なるので少し大変でした🫠
構築した各サービスは Cloud Run jobs を用いてジョブを実行しています。
ジョブの実行スケジュールはCloud Schedulerを用いて管理しています。
Cloud Run jobs は2023年5月頃に一般提供となった比較的新しいサービスで、よりバッチ処理に特化した機能が提供されています。並列処理やリトライ機構など必要な機能が一通り揃っているかつシンプルなのでとてもおすすめです☺️
インフラ (Firebase)
アプリ提供を行うためにはデータベースやAPIサーバーの他にユーザ認証やプッシュ通知機構、分析ログの収集など様々の仕組みも構築する必要があります。
これらは Firebase アプリ開発プラットフォームによって提供されており、Campsyteでもふんだんに使用しています!具体的には以下のサービスを使用しています。
ユーザー認証: Firebase Authentication
データベース: Cloud Firestore
プッシュ通知: Firebase Cloud Messaging
アプリクラッシュログの収集: Firebase Crashlytics
ABテストや強制アップデート: Firebase Remote Config
分析ログの収集: Firebase Analytics
分析ログの分析: BigQuery
Firebaseのおかげで個人でもアプリを開発してサービス提供することができています。偉大なプラットフォームです🙏
まとめ
今回はキャンプアプリ「Campsyte」のシステムアーキテクチャについて紹介しました。各技術について、より詳しく紹介したいことはまだまだたくさんあるので定期的にnoteにて発信できたらと思っています。
引き続きよろしくお願い致します!
この記事が気に入ったらサポートをしてみませんか?