firebaseでちゃんと開発してみた


1週間程度firebaseでちゃんと開発してみたので、その感想。
簡単なECサイトのようなものを構築しました。

フロントはNuxtでバックエンドはfirebaseです。
DBはfirestore。
Cloud FunctionsはNodeです。

今回はTSじゃなくてJSでやりました。

firebaseのいいとこ

  • インフラ見なくていい
  • 認証、データストア、ストレージなど必要なものの多くが揃っててブラウザでポチポチすれば使える
  • nuxt firebase moduleがあるので導入は簡単
  • 認証画面もfirebaseui使うことで簡単(Auth0よりも更に何も考えなくても導入できる)
  • GCPが想像以上に充実してるので、だいたいのことは何とかなる

基本的にはserverlessでアプリをさっくり作れるフレームワークといった印象。
運用もGCP内の別サービスや、他のSaaSを組み合わせればいいだけなので構築は簡単だった。
ただ、ここでいう簡単、というのは、firebaseだと劇的に簡単・・・!というわけではなく、普通にライブラリが公式のあるから選定に迷わないよね、くらいの簡単さ。

CloudFunctionsのログの監視はGCPのLogging->Sync->CloudFunctions経由でいろいろ処理できるし、 Export Collections to BigQuery っていうFirebase extensionで必要なものはBigQueryに流せるしで、まぁそんなに何かに迷ったりとか、最低限の運用体制の構築で困ることはなかった。

firebaseのよくないとこ

  • firestoreが良くない

firestoreが本当によくない。微妙。

スキーマの制限ができない

key-value storeだから当然じゃん、って話なんだけど、スキーマの制限が難しい。
クライアントに書き込み権限を与えると、どんなキーが発生しても不思議ではないし、逆にどんなキーが不足してても不思議ではない。

これはfirestoreがクライアント側に直接書き込み権限を与えることができることから発生してる根本的な問題。

じゃぁどうするかっていうと、

  • Rulesで超頑張って縛る
  • 書き込みはすべてCloud Functionsでやる

っていう2種類しか方法が思いつかなかった。

前者のRulesで縛る、というのが正攻法だと思うし、ググってもそうしてることが多いが、実際問題細やかなバリデーションをRulesで表現するのは無理がある。
世の中どうやってるかというと、

  • 複雑なRuleを定義してテストケースで保証する
  • 複雑なRuleが不要なコレクション/ドキュメントの構造にしておく

といったあたりっぽい。実際他に思いつかない。

じゃぁやればいいじゃん、って話なんだけど、たかがリクエストバリデーションのために難解なRulesを構築し、それをテストケースで様々なリクエストパターンを考慮した上で保証する、ってのはやりたいことに対してtoo muchな印象。
できるかできないかえでいえば、できる、が、やりたいことってそういうことじゃないし・・・。

また、書き込みのためにサブコレクションに分けていくことで、多少制限はしやすいが、そうすると今度は読み込み処理が面倒くさい。

といったあたりで、諸々勘案して安牌に倒そうとすると、クライアントからの書き込みは禁止、CloudFunctions経由でのみ書き込みでき、クライアントは読み込みのみ、といった方向に倒す以外の方法がベターな気がしている。ので今回はそうした。

少なくともバックエンドアプリ上でスキーマを制限できるので、アプリがバグらなきゃスキーマ保証できる。

スキーマが無い上にクライアント側で自由にキーの追加削除できてしまう、ということは、参照時にすべてキーチェックが必要になって、クライアント側のコードも本当に不要に煩雑になる。

参照がヤバイ

IDを指定した単一ドキュメントの取得、単一WHERE句による取得、単一キーによる並び替え・・・くらいはできる。

条件あんまりなくInfinityLoadするのもたぶん得意。

逆にソレ以外得意じゃない。

まず、複合条件・・・というかWHEREとかOrderByが2個重なる参照をしようとすると、その時点で「インデックスの作成」というのをブラウザ上でやらなきゃいけない。
name asc と age desc でインデックス作成 みたいなことをコンソール上でやらなきゃいけないわけだ。
しかもドキュメント数が少ない(100以下)の状態でも、インデックス作成には5分くらいかかる。めっちゃ遅い。

クライアント側で「並び替え機能を作るぞー!」とか「検索機能を作るぞー!」となると、様々なパターンに合わせてのインデックス作成が必要になる。超だるい。
「インデックス作成」がされてないと「クエリが遅い」とかじゃなくて インデックスないからクエリたたけ無いよ!throw Error()!! みたいな感じでクライアントが死ぬ。じゃぁ作るかっていうと5分かかる。だるい。

まぁでもこれはまだ軽い問題。だるいだけだから。

割と絶望的なのが != 演算子がないことと in 使った場合に10件ずつしか取得できないこと。

つまり、 status != 'inactive' みたいなことはできない。軽い気持ちでstatusでフィルタ、みたいなのは無理。
status in ['active', 'foo', 'bar'] みたいな感じでいけるか・・・!と思ったんだけど、そうすると「1度に取得できるのは10件までだよ」みたいなエラーが出た。意味不。

ソートはできない、検索はできない、大量取得もできない、結構辛い。

たぶんもうfirestoreはそういう役割じゃない前提で、データをElasticsearchなりBigQueryなり、なんでもいいから外部のデータストアにぶんなげて、そういう検索とかはそっちでやってね、という割り切りしかない。

ただそうすると、何のためにfirestoreみたいなマネージドサービス使ってるのかどんどん分からなくなってくる。

結論

というわけで1週間かけて作った結論としては、firebaseは悪くないけど、firestoreが微妙にもほどあるから、総じて微妙。
backendにRDB使ってaws lambdaなりGoogle Cloud Functionsなり使ってserverlessアプリ作ればいいんじゃないかな・・・という気持ちしか出てこなかった。

firestoreには向き不向きがあるんだよ!!!みたいな話は分かるけど、ちゃんと作ろうと思った途端に普通の開発よりも多大な謎コスト(Rulesとか)が発生するのが辛い。

とにかく「firebase使うと簡単に構築できる」というのは、ある一定までは合ってるんだけど、最終的な開発コストを鑑みると微妙な部分が多々あるので、十分に注意が必要。

特に参照系に関しては「え!?コレできないの!?」みたいな驚きがあるので、せめて事前に適当なデータセット作って、クエリできるか試してから「マジでfirebase導入するのか」というのは検討してほしいなと思いました。

自分の肌感としては、「うーん、あんま使うことないかな☆」っていう気持ち。

マスタデータ系だけをfirestore持ってて、一般ユーザーには更新なしで、検索とかもなくて、全データひっぱってきて使うだけ、みたいな使い方が一番あってると思う。ソレ超えると辛い。