Categories: 勉強会

#FJUG Firebase Realtime Meetupに参加してきたまとめ

firebaseの知見をオンラインで共有するFirebase Realtime Meetupに参加してきたのでそのまとめです。

TypeScriptから使いやすいFirestore-simpleを紹介します

  • 普通に書くとcollectionを書いたりdata()書くのが大変。キャストの型ミスもありうる。
  • 自分でクラスを作るパターンだと、キャストミスがなくなったり、collectionやdataを毎回書かなくてすむが、別のコレクションとか作るとなるとコピペが必要になってくる

冗長なコードを省く

  • 冗長なコードを書かなくて住む
  • FirestoreとTypescript側でキーや方が微妙に違う場合。createdAtがDate/Timestampと別れてるなど
  • firestoresimpleにはdecodeとencodeがある
    • decodeはfirestore→typescriptからもってくる時のコンバーター
    • encodeはtypescript→firestoreへのコンバーター
  • fetchAll:すべてのドキュメント取得
  • bulkAdd, bulkSet, bulkDelete: いい感じにバッチ処理してくれる

強力な型補完

  • withConverterを使うと結果に型が作れるが、キー名のtypoという凡ミスが起きたりする
    • firestore simpleを使うと補完ができます
    • typoを起こすとエラーになる

素のfirestoreから乖離しすぎない

  • ActiveRecord風にはしない
  • 外しやすいライブラリを目指している。あくまでfirestoreの補助として使うようにする。
    • 使い方が大きく変わるライブラリは外しづらい
  • jsでドラフト中の構文は使わないようにしている
  • ただ、firestoreがもっと便利になれば自作して使う理由もなくなる

間違いを起こしやすい機能へのサポート

  • batchとtransactionは間違いを起こしやすい
  • serverTimestamp, increment, collectiongroup, where IN, emulatorなど新しい機能もカバーしている。

最近のv7アップデート

  • web SDKにも対応した
    • npm i @firestore-simple/admin
    • npm i @firestore-simple/web

Firestore-simpleのターゲットユーザー

  • TypeScriptで型をちゃんとつけたい
  • UIフレームワークとは疎結合にしたい。
  • Firestore層のテストを書きたい。
    • Firestore-simple自体のテストコードを参考にできます
    • テスト並列化などの高速化のノウハウもつまってます

今後の予定

  • WebSDKの一部機能(get onSnapshotなど)はまだ未対応
  • APIドキュメント生成

FAQ

  • Converterとの兼ね合いについてはどう思われているのだろう
    • 名前も揃えるべきか悩んでいる
    • 現行のwithConverterは機能が足りないので、simpleで出来る機能もある
  • Pringとの比較
    • 思想が違うので好み次第
  • updateは防げるのか?
    • whereは型レベルでは防げない
    • 後で調べます
    • (おそらく下記が回答?)

Build the SNS like instagram with Firebase

  • Follow Meは有料版インスタグラム。
    • 開発期間は2019/10から徐々に開発開始して3,4ヶ月くらいで完成した
  • 技術的構成
    • iOS: google/promises, VIPER
    • web frontend: Next.js x TypeScript
    • Firebase: TypeScript
  • 構成
    • クライアントの通信相手はAuth Firebase, Cloud Storage, Algolia, CloudFunctions, CloudFirestore
    • CloudFunctionsのログはStackDriverLoggingに集約していて、ErrorReportingしてログと監視をしている
      • fatal errorなど通知を送るようにしている
    • firestoreやログやアナリティクスのデータをBigQueryにいれて、ataStudioで表示して分析をしている
    • webはfirebase hostingに静的ファイルをおいていて、Cloud Runを挟んでCloudFirestoreからのレスポンス返答をしている

設計方針

  • 体験が少し悪くなるので、できるだけ直接functionsは呼ばずに原則クライアントからfirestoreを触る。どうしようもないときはCallableで呼び出す
  • firestoreのruleをテストと合わせて書く
  • Triggerを活用して同期処理は可能な限り避ける
  • 一位なデータにするためにCollectionGroupでの取得は避ける

各機能と設計

フォローとタイムライン

  • 自信をフォローするために必要な金額が設定できる。フォローするとコンテンツが見れる。FolloweeのタイムラインにFollowerの投稿が流れる
  • フォローの処理
    • アプリで決済はしる→Callableでレシート送信→レシート懸賞→フォロー関係を作成→FoloweeのIDtokenを更新→レスポンスを返してアプリはIDTokenをrefresh
  • タイムラインへのpostのコピーが重いが、フォロー関係が作成されたときにonCreateで作成してコピーでもいいが、フォローしても見れないという可能性があるので、同期的にしかたなくコピーしてる。
    • ただし、コピーはなるべく小さくして、CliendSideJoinで取得している
    • タイムラインへのコピーは投稿するときにフォロワーのタイムラインにコピーをするが、写真や動画をアップロードして、postsにcreateしているが、onCreateで非同期でフォロワーのタイムラインに対して投稿をコピーするようにしている
  • 何を同期的にやらなければならないかを常に考えて設計する

Postのいいね、コメント

  • postsのcollectionにlikes, commentsをおいている
  • お知らせ、通知
    • いいねやコメントへの通知がおくれる
    • /users/{userId/notifications/{notificationID}
    • お知らせで表示したいものを保存していく
    • 通知種別、通知日時、メッセージや遷移先などをフィールドに持つ
    • /notificationSettings/{userID}に通知設定がある
  • notificationIDに意味をもたせている
    • documentのIDを自動にしていると、お知らせのコレクションはいいねのお知らせで埋まってしまう。
    • 日毎でまとめるために、{postID}likesYYYYMMDDというIDでおくっている
    • 日毎にまとまった通知を作ることができる
    • onCreateだけでプッシュ通知を送ることもできる
  • プッシュ通知
    • /users/{userID}/deviceTokens/{token}
    • ログアウト時に現在のものを削除
    • onCreate/onDeleteでTopicを購読させる
    • Topicに紐付いてる名前のユーザに一斉に通知を遅れる
    • トピック名に対して通知を遅れる
    • {フォローしているUserのID}_postsでフォローしてる人が投稿したときに通知がくるTopic
    • Topicに対して送信すればdevice tokenのリード数を減らせる
  • Topicの活用方法
    • RemoteConfig更新をクライアントに知らせるためにも使える
    • Topic名=uidにしてtoken登録おけば、そのユーザに対するプッシュ痛通知はTopicだけに送ればいいので、トークンのReadが不要になりそう

売上の管理

  • /users/{userId}/sales/salleDetail/{sailDetailID}
  • saleIDはYYYYMMとして月ごとの売上情報をフィールドに持つ
    • 個々の決済情報を持つ
    • 1個の決済のIDをtransactionIDにしている
    • saleDetailsのonCreateでsalesの値を更新する
    • 売上確定バッチでsaleDetailsをとってきて再計算している
  • バッチ処理
    • pub/subでcron jobを設定できる
    • 重めの処理x月に一回起動だと制限時間内に処理が終わらない可能性がある
    • バッチ処理をしたい対象を抽出するのと、実際にする処理を分けている
    • 1つ目のfunctionで処理対象を絞り込んで、/tasks/{taskID}に保存する
    • taskのonCreateをTriggerにバッチ処理すると100件ずつ処理できる
    • ただし、処理は何回実行しても同じなるようにcontext.eventIdなどをつかって一回しか処理しないようにしておく

画像処理

  • 画像にブラーをかけている
    • StorageTriggerを使ってCFで処理している。
    • sharpというpackageを使って画像処理はしている

RemoteConfig活用

  • 工数やコスト感も考えて強制バージョンアップデートを採用
    • フィーチャースイッチ
    • firestoreで持つほどじゃない定数の管理

Testing

  • テストは必要最低限
  • rulesのテストは絶対に書いている
  • 決済処理周りはテストをかいている
  • 不安な部分にテストを書いている

CI

  • github actionsを活用
  • push時にテストを回す
  • アプリ側のテストは一切書いてない

運用コスト

  • 使用状況は読み取り2618万、書き込みは66万
  • 費用は3800円くらい
  • 他のライブ配信などの費用の方が高い

Firebaseの良し悪し

いいところ

  • 必要なものが揃っていてとにかく早く作れる
    • 大体自分のデータだけ読み取れるみたいなのを書くだけでいい
  • コストが安い
  • スケールしてくれるので安心
  • オーナーが期待するスピード感についていける

大変なところ

  • 設計パターンがまだ枯れてない
  • firestoreのrulesが肥大化していく
  • サーバでデータ加工してクライアントに返すのが難しい
    • こういう権限の人はメールアドレスは見せないとかが大変
    • リード用のコピーを作るマイグレーションなどもあって管理が大変
  • 24/365で動いているサーバが一台欲しくなる

FAQ

  • topicは作ってすぐプッシュ通知遅れるのか?
    • 確か遅れるが許容してる
    • 通知のデータは作られるがプッシュ通知が届かないだけ

モバイルアプリ開発者社からみたFirebaseの便利機能と活用例

  • 認証、クラウド連携、クラッシュログ、頻出機能の開発効率向上などはfirebaseで解決できる

モバイルアプリのユースケース

  • TODOを管理するアプリを作ってみた

認証

  • 既存アカウントを利用可能に
  • ログインなしでも利用可能に
  • 認証情報をまとめて管理
  • firebaseでauthentication作る時はpurojectを作るが、どの認証を使うかを選べるようになっている
  • facebookの場合はアプリを認証対応させるためにfacebook側でapplicationIDとsecretを払い出してもらって設定する必要がある
  • ユーザーUIDをユーザアカウント識別子として使っている

データ管理

  • データバックアップ対応
  • android/ios両対応たい
  • オフラインでも使用可能
  • firestoreを使うことでDBが使える
  • cllectionの中にcollectionはもたせられない。documentに持たせる
  • ruleを使って認証ユーザのみread/write許可するようにする

まとめ

  • モバイルアプリで欲しい機能が大体ある
  • 浮いた工数をUI/UX改善に回せる
  • 開発効率向上

FAQ

  • userとuserdataを同階層にもってreference型で参照するのは悪手ですか?
    • 階層をもったほうがセキュリティルールを書くのが楽

@mogmetの所感

まだまだ知らないノウハウなどを知れてとても勉強になった勉強会でした。

また、改めてコストがとても安く、素晴らしいmBaaSだというのも実感することができました。

改めてどんどんfirebaseを使ってサービスを作っていきたいと思います!!
mogmet

View Comments