Firebase + Algoliaの限界:個人開発でAWS移行した2理由と体験談

IT開発

クイズ共有アプリを個人開発して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の利点

  • 役割分担: シンプルクエリはDynamoDB、複雑検索はOpenSearch
  • コスト効率: 必要な時だけOpenSearchを使用
  • パフォーマンス: 各サービスが得意分野に特化
  • スケーラビリティ: 将来的な成長に対応
RDSと比較したデメリット

  • 複雑性: 2つのサービスを管理
  • 学習コスト: DynamoDBの設計思想を理解する必要
  • データ同期: DynamoDB→OpenSearchの同期処理

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の利点

  • 複雑なクエリが自由自在
  • JOINや集計が簡単
  • データ整合性が保証
RDBの欠点

  • コストが高い(月額$20-50)
  • スケーラビリティに限界
  • レスポンス速度でNoSQLに劣る

個人開発ならRDSも十分選択肢になります。特に複雑なクエリが多い場合は、NoSQL + 検索サービスより安上がりかもしれません。

いつFirebaseを使うべきか(独断と偏見)

これまでの経験を踏まえて、どんな時にFirebaseを選ぶべきか、逆にいつ他の選択肢を検討すべきかをまとめてみました。あくまで個人的な見解ですが、参考になれば幸いです。

✅ Firebaseが向いてるケース

  • 超短期プロトタイプ(1-3ヶ月)
  • 個人開発・趣味プロジェクト
  • シンプルなデータ構造
  • 学習・ポートフォリオ目的

❌ Firebaseが辛くなるケース

  • 複雑な検索が必要
  • データ分析・集計が重要
  • チーム開発(4人以上)
  • 本格的なビジネス利用

移行を検討するタイミング

  • 「あれ?これFirebaseで実現できる?」と思った時
  • 「なんでこんなに複雑になってるんだ?」と感じた時
  • 「月額料金が読めない…」と不安になった時

💡 個人的な結論
プロトタイプ・学習: Firebase
本格ビジネス(複雑クエリ必要): AWS RDS
大規模・高速処理重視: AWS NoSQL + OpenSearch
最初の選択が後々の開発効率を大きく左右します。

まとめ

Firebaseは素晴らしいサービスですが、適材適所が重要です。

  • Firestoreの制約は想像以上に厳しい
  • Algoliaの運用は個人開発には重すぎる
  • 移行コストを考えると、最初の選択が重要

これから個人開発を始める方の参考になれば幸いです。


この記事は実際の開発体験を基に書いています。プロジェクトの要件や規模によって最適解は変わるので、あくまで一つの事例として参考にしてください。

コメント

タイトルとURLをコピーしました