見出し画像

個人開発でやらかした失敗と、そこから学んだ実装の難しさ

この記事は Firebase Advent Calendar 2019 の 23日目の記事です。

こんにちは、ふじけん(@kenshir0f)です。
2019年ももうすぐ終わりなので、今年いろいろと挑戦してきたなかでも個人で開発している日報サービス Stella の開発中にやらかした失敗をご紹介します。来年はきっと忘れているので戒めに...

日報サービスStellaとは?

Stellaは、個人でゆるく開発している日報サービスです。

昔 wikihub という日報のサービスがあり、開発やデザインで学んだことを書いてアウトプットしていたのですが、いつしか「毎日書くために何かしらアウトプットする」というモチベーションが湧き、毎日勉強する良いサイクルが生まれました。
すごい愛用していたサービスでしたが、いつしかwikihubにログインできなくなり、現在はWebサイトにアクセスすることもできなくなったので、自分自身で日報が残せるサービスが欲しくて作りました。

この日報サービスはFirebaseを利用して作られているのですが、実装時にFirebase関連でやらかした失敗をお話ししたいと思います。

やらかしたことその1:無限ループでFirestoreにリクエストを投げてしまう

日報サービスを作り始めて、一番最初にログイン/ログアウトの処理を書いていたときの出来事です。
ヘッダーに「非ログインだったらログインのボタンを表示させ、ログインしていたらユーザーアイコンを表示する」実装していたとき、手順としてはページが表示されるときに、

1. Firebaseにログイン情報(Auth)を取得する
2. Authがなかったらログインボタンを表示する
3. Authがあったら次にUserの情報を取得する
4. Userの情報があったらUserのアイコンを表示する

という流れで最初書いていたのですが、新規登録時はタイミングによってはUserの情報が作られていないため、4の手順が失敗することがありました。
本当はUser作成成功のイベントを非同期で待ってから処理を書くべきだったのですが、当時はその知識がなく色々と試行錯誤しているときに誤って書いてしまったのが、

5. Userの情報を取得したらUserの情報を取得する

という無限に実行されてしまう処理です。
普通に書いていたら気づくのですが、もともとは「Userの情報がなかったらUserの情報を取得する」ところを間違えてtrue/falseの条件を変えてしまいました。
しかも僕はこのとき、のんきに近くのコンビニにでかけてたという...
帰ってくるとパソコンが異常なファンの音と共に熱くなっていて、慌ててブラウザを閉じて確認したのですが、わずか数分の間に無限ループでUser情報を取りに行っていたため、FirestoreへのRequestが一瞬で10万回を超えていました。
テンパっていて「これ多額の請求来るのでは...」なんて思っていましたが、請求はたったの 1円 。本当によかった...

スクリーンショット 2019-12-23 0.18.45

今回は大惨事にならなくて済みましたが、もしこれに気づかずリリースされていたらユーザーさんのブラウザは固まるし料金もかなり膨らんでいたと思うと本当に恐ろしい出来事でした...(Firebaseが安すぎるというのもある...)

やらかしたことその2:開発環境と本番環境のデータ数の違いで処理が失敗する

日報の全データを(v1からv2に)移行したときに起こった出来事です。
Stellaはログインユーザーであれば日報に対して「リアクション」することができます。

スクリーンショット 2019-12-22 23.03.59

このリアクションは当初「👍」だけできるようにしていたので、さくっと実装するためセキュリティルールを担保した上で日報の Document の Field を Update して保存していました。
そこから他にも「💯」「❤️」など複数のリアクションを増やしていったところでFieldに保存するのは辛くなってきたので SubCollection への置き換えを検討します。(そもそも著者以外が日報を更新できるのは健全でないので...)

ただ全日報のリアクションをSubCollectionに変更するのに失敗し、万が一ユーザーさんの日報が壊れてしまったらとても怖いので、いつでもロールバックできるよう全てのデータを複製し、v1からv2に移行してからリアクションのデータを変更することにしました。ダメだったらv1に戻せばいいので安心してトライできます。

色々と考慮した上で考えたことは以下の通り。

1. データの移行はバッチ処理で一気にv1からv2に移行する
2. データ移行後にv1に日報が作られ、v2を見に行くと日報が消えたように見えてしまうので、データ移行後速やかに全てのFunctionの読み取り/書き込み先をv2に変える
3. 本当はメンテナンス状態にしてやるべきだが、その実装時間が惜しいので当時日報が投稿されにくい時間帯の平日深夜(2:00)にこっそり変える

開発環境で何度もv2への移行をテストして上手く移行できたことを確認し、いざ深夜に本番環境でbatchを実行。しかし、エラーが発生して何度やっても失敗する自体に...

あれ?なんで...おかしいな...開発環境と違うこと...データの数...?

改めてbatch処理のページを見てみると、普通に原因が書いてありました。

1 回のトランザクションまたはバッチ書き込みでは、最大 500 のドキュメントに書き込みを行うことができます。書き込みに関連するその他の制限については、割り当てと上限をご覧ください。

日報数は1000を余裕で超えているし、開発環境はせいぜい50...なるほど...
現在、深夜3時...いまからbatch処理書き直す...?えー...やるか〜〜

てな感じで処理を500件ごとに分割し、再びテストし直してv1からv2にデータを移行しました。
無事にDocumentのValueからSubCollectionを生成し、過去のValueにあったリアクションは使わないようにできました。(このとき朝5:00くらい)

SubCollectionにするとCollectionGroupで簡単に付けたリアクション数の計算や、コメントにもリアクションを付けられるようになるのですが、移行後にまだやれてません... 🙄 

学び
・ドキュメントちゃんと読もう...(読んでたけど抜けてました...)
・深夜に頑張らない。ちゃんとメンテナンスモードを作ろう。

やらかしたことその3:移行手順を間違えて本番のデータが壊れる

やらかしたことその2の続きで、v1からv2への移行するときに、移行手順を間違えた出来事です。

Stellaでは日報にコメントが付けられ、コメントが付けられた日報の著者にお知らせが飛ぶようになっているのですが、裏側では以下のような設定になっています。

1. コメントが作られると自動(onCreate)で未読のお知らせ(notification)が作られる
2. ヘッダーには未読のお知らせ数が表示される
3. お知らせ詳細を見ると未読が既読になる
4. お知らせ一覧は作成日(created_at)順に並ぶ

開発環境では1の関数(onCreate)を一旦停止してからコメントを移行し、移行が完了したらonCreateを再開するようにしていましたが、作業時は夜中4時ごろでぼけていたため、本番環境ではonCreateを止めずにコメントを移行してしまったのです...

その結果、コメントを移行 → onCreateで未読のお知らせが即座に発行されてしまい、ユーザーさんのお知らせが突然「未読数20」みたいな状態になってしまいました。
しかもお知らせが移行のタイミングで新規で作られたため、「全てのお知らせの作成日(created_at)が同じ時刻」になってしまう自体に...

まずい...どうする?お知らせを全て削除するか?いや、いまからその関数を書いてテストするのはさらに事故りそうだな...v1のデータを見るかぎりほとんど既読になっているしひとつずつコンソールから既読に変えていくか...それならなんとかなりそう!でもあれ、お知らせの順番がぶっ壊れてる...まずくない?そんな影響ないとはいえまずいよな...どうしよう...
......ダメだ、謝ろう!!!

ということで、日報でユーザーさんにごめんなさいしました🙇‍♂️
ユーザー数が少ないのと個人開発ということで多めに見てもらえましたが、本当はメンテナンス状態にしてやり直すべきでした...すみません...

学び
・データの作り変えや移行時はCloud Functionsで書いたFirestoreのトリガー(onCreateやonUpdateなど)は必ず確認しましょう...
・移行手順をきちんと文字に起こして確認しながら進めましょう...個人開発なんで手を抜いたのがよくなかった...

おわりに

Firebaseで作っているサービスでやらかした話をしました。
個人開発していると、本当に色々と学ぶものがあります。
データを書き換えることの難しさと責任と失敗したときの恐怖と、みんな当たり前のように実装していて本当にすごいなって思いました...
そして時間と提供したい価値とのバランスと、デザインと実装力と...何もかもが足りない😇

直近はフロントエンドの開発依頼が多くてstellaの開発が止まっているのですが、落ち着いてきたら個人開発また再開したいです。あ、でも国道も作りたい...
とにかく、サービスつくるの(難しいけど)本当に楽しい!!!!

ではでは👋

うちのごまお(ブリティッシュショートヘア)のおもちゃとチュールになります🐈