クイズ共有アプリを個人開発してGoogle Playでリリースしている者です。最初はFirebase + Algoliaの組み合わせで快適に開発していましたが、機能を拡張していく中で「なんか辛いな…」と感じることが増えてきました。
今回は実際に感じた問題点と、AWS移行を決断した理由について、実体験を交えて書いてみます。
📱 対象アプリ
GitHub: share_quiz
最初は快適だったFirebase
個人開発を始めた当初、Firebaseは本当に素晴らしいサービスでした。
// 認証も簡単
await FirebaseAuth.instance.signInWithGoogle();
// データベースも直感的
await FirebaseFirestore.instance
.collection('quiz')
.add(quizData);
セットアップが簡単で、インフラを意識せずに開発に集中できる。個人開発者にとって理想的な環境でした。
特に以下の機能は本当に素晴らしく、開発初期は「Firebase最高!」と思っていました。
- リアルタイム更新: 他のユーザーの投稿が即座に反映
- 簡単な認証: Google/Apple/メール認証が数行で実装
- 自動スケーリング: インフラ管理不要
- 豊富なSDK: Flutter/React/iOS/Android対応
// リアルタイムでデータが同期される
FirebaseFirestore.instance
.collection('quiz')
.snapshots()
.listen((snapshot) {
// 他のユーザーが投稿したクイズが即座に反映
updateUI(snapshot.docs);
});
このリアルタイム機能により、ユーザー同士のインタラクションが活発になり、アプリの魅力が大幅に向上しました。
問題1: Firestoreの限界に直面
アプリの機能を拡張していく中で、Firestoreの制約が徐々に見えてきました。
複雑な検索ができない
ユーザーから「タイトルに”歴史”を含み、難易度が中級以上で、作成日が1週間以内のクイズを検索したい」という要望が来ました。
// やりたいこと(SQLなら簡単)
SELECT * FROM quiz
WHERE title LIKE '%歴史%'
AND difficulty >= 'intermediate'
AND created_at >= DATE_SUB(NOW(), INTERVAL 1 WEEK);
// Firestoreでは...無理!
// 複数の不等号条件は使えない
// LIKE検索もできない
結果的に、複数のクエリに分割してアプリ側で結合する必要がありました。
インデックスの事前登録が必要
さらに、Firestoreで複数フィールドでクエリを実行するためには、Composite Index(複合インデックス)を事前に登録しなければなりません。
// このクエリを実行するためには...
FirebaseFirestore.instance
.collection('quiz')
.where('category', isEqualTo: 'history')
.where('difficulty', isEqualTo: 'intermediate')
.orderBy('createdAt', descending: true)
.get();
// Firebase Consoleで手動でインデックス作成が必要!
// category + difficulty + createdAt の組み合わせ
😅 開発中のストレス
「クエリを追加するたびにFirebase Consoleでインデックス作成…」
「インデックス作成に5-10分かかるし、忘れることも…」
ローカル開発ではエラーが出て、本番では動かないということもありました。
JOIN的な操作ができない
// やりたいこと:クイズと作成者情報を一緒に取得
// RDBなら簡単なJOIN
// Firestoreでは仕方なく複数回取得
final quiz = await getQuiz(quizId);
final creator = await getUser(quiz.creatorId); // 別クエリ
// N+1問題が発生しやすい
集計クエリができない
// やりたいこと:カテゴリ別のクイズ数を表示
// COUNT()が使えない!
// 全件取得してアプリ側で集計...
final allQuiz = await collection.get();
final categoryCount = <String, int>{};
for (final doc in allQuiz.docs) {
final category = doc.data()['category'];
categoryCount[category] = (categoryCount[category] ?? 0) + 1;
}
💡 気づいた瞬間
「あれ?これって普通のデータベースなら簡単にできることなのに…」
NoSQL固有の問題
実はこれらの問題はFirestore固有ではなく、NoSQL全般の特徴です。MongoDB、DynamoDB、Cassandraなど、どのNoSQLでも同様の制約があります。
- スケーラビリティ重視でクエリ機能を犠牲
- 非正規化前提の設計思想
- 結合処理はアプリケーション側で実装
NoSQLは「大量データを高速処理」するために生まれた技術なので、複雑なクエリができないのは仕様なんです。ただし、インデックスの事前登録は開発効率を大きく下げる要因でした。
Firebase Data Connectについて
※ 2024年にFirebase Data Connect(PostgreSQLベース)がリリースされましたが、現在はPreview版のため本番利用は推奨されません。正式版がリリースされれば、Firebaseでも複雑なクエリが可能になる予定です。
問題2: Algoliaの運用が辛い
Firestoreの検索機能の弱さを補うため、Algoliaを導入しました。検索機能自体は素晴らしいのですが、運用面で問題が…
手動デプロイ地獄
# staging環境の設定
algolia indices export quiz_staging --output staging.json
# production環境の設定
algolia indices export quiz_production --output prod.json
# 設定が微妙に違う...どっちが正しい?
環境管理の複雑さ
ダッシュボードで手動設定する項目が多すぎて、環境間の同期が困難でした。
- searchableAttributes: 手動設定
- ranking: 手動設定
- synonyms: 手動追加
- stop words: 手動追加
staging → production への反映が全て手作業になってしまいました。
バージョン管理できない
😱 実際にあった問題
「昨日まで動いてた検索が急に変になった」
原因:誰かがダッシュボードで設定変更
解決:???(履歴が分からない)
GitHub Actionsでの自動化も困難
# 頑張って自動化しようとしても...
- name: Deploy Algolia settings
run: |
algolia indices import quiz --input settings.json
# 部分的な失敗を見逃しやすい
# ロールバックが困難
# 設定の検証が別途必要
技術的には可能ですが、工数対効果が悪すぎました。その時間を機能開発に使いたい…
予想外のコスト増加
💸 Algoliaの料金体系
– 無料枠: 月10,000検索まで
– その後: 1,000検索あたり$0.50
– ユーザーが増えると一気に高額に…
最初は無料で使えるので気軽に導入しましたが、ユーザーが増えるにつれて検索回数が急増。月額料金が予想以上に高くなってしまいました。
AWS移行の決断
これらの問題を解決するため、AWS移行を決断しました。
移行後の構成
「NoSQLの問題って言ったのに、またDynamoDB(NoSQL)使うの?」と思われるかもしれませんが、AWSではFirestoreの問題を解決できる仕組みがあります。
// CDKでインフラをコード管理
const dynamoTable = new Table(this, 'QuizTable', {
partitionKey: { name: 'id', type: AttributeType.STRING },
billingMode: BillingMode.PAY_PER_REQUEST,
// GSIで柔軟なインデックス管理
globalSecondaryIndexes: [{
indexName: 'CategoryIndex',
partitionKey: { name: 'category', type: AttributeType.STRING },
sortKey: { name: 'createdAt', type: AttributeType.STRING },
}]
});
// 検索はOpenSearchに任せる
const searchDomain = new Domain(this, 'SearchDomain', {
version: EngineVersion.OPENSEARCH_1_3,
capacity: { dataNodes: 2 },
});
なぜDynamoDB + OpenSearchを選んだのか
「RDSの方が簡単じゃない?」と思われるかもしれませんが、以下の理由でDynamoDB + OpenSearchを選択しました。
DynamoDB + OpenSearchの利点
|
RDSと比較したデメリット
|
Firestoreとの決定的な違い
🔄 最大の違い:インフラのコード管理
Firestore: コンソールで手動設定 → 環境差異、バージョン管理不可
AWS: CDKでコード管理 → Git管理、環境一致、自動デプロイ
具体的な解決内容
- インデックス管理: GSI/LSIをCDKで事前定義、手動作成不要
- 複雑検索: OpenSearchで全文検索、ファセット検索が可能
- 環境管理: staging/productionが同一コードで管理
- コスト予測: AWS料金計算機で事前計算可能
- バージョン管理: インフラ変更もGitで追跡
// インデックスもコードで管理
const categoryIndex = {
indexName: 'CategoryDifficultyIndex',
partitionKey: { name: 'category', type: AttributeType.STRING },
sortKey: { name: 'difficulty', type: AttributeType.STRING },
};
// 環境別デプロイ
cdk deploy QuizApp-Staging
cdk deploy QuizApp-Production // 同一構成でデプロイ
移行時のコスト考慮
ただし、AWSも決して安くはありません。OpenSearchは最低でも月額$20-30程度かかります。
⚠️ 重要な注意点
Firebase + Algoliaで月額$50だったものが、AWSで月額$80になることもあります。
しかし、機能の柔軟性とコストの予測可能性を考えると、本格的なビジネス利用では価値があります。
RDBという選択肢
AWSではRDS(PostgreSQL/MySQL)を使う選択肢もあります。
// RDS PostgreSQL
const database = new DatabaseInstance(this, 'QuizDB', {
engine: DatabaseInstanceEngine.postgres({
version: PostgresEngineVersion.VER_15_3,
}),
instanceType: InstanceType.of(InstanceClass.T3, InstanceSize.MICRO),
});
RDBの利点
|
RDBの欠点
|
個人開発ならRDSも十分選択肢になります。特に複雑なクエリが多い場合は、NoSQL + 検索サービスより安上がりかもしれません。
いつFirebaseを使うべきか(独断と偏見)
これまでの経験を踏まえて、どんな時にFirebaseを選ぶべきか、逆にいつ他の選択肢を検討すべきかをまとめてみました。あくまで個人的な見解ですが、参考になれば幸いです。
✅ Firebaseが向いてるケース
|
❌ Firebaseが辛くなるケース
|
移行を検討するタイミング
- 「あれ?これFirebaseで実現できる?」と思った時
- 「なんでこんなに複雑になってるんだ?」と感じた時
- 「月額料金が読めない…」と不安になった時
💡 個人的な結論
– プロトタイプ・学習: Firebase
– 本格ビジネス(複雑クエリ必要): AWS RDS
– 大規模・高速処理重視: AWS NoSQL + OpenSearch
最初の選択が後々の開発効率を大きく左右します。
まとめ
Firebaseは素晴らしいサービスですが、適材適所が重要です。
- Firestoreの制約は想像以上に厳しい
- Algoliaの運用は個人開発には重すぎる
- 移行コストを考えると、最初の選択が重要
これから個人開発を始める方の参考になれば幸いです。
この記事は実際の開発体験を基に書いています。プロジェクトの要件や規模によって最適解は変わるので、あくまで一つの事例として参考にしてください。
コメント