CloudFirestoreでアプリ設計してみた(初心者)

アドベントカレンダー初参加なので、お手柔らかにお願いします。
この記事は、Firebase #2 Advent Calendar 2019の8日目の記事です。


## まずどんなアプリか

一言で言うと、「朝、友人が起きてるか分かるアプリ」です！

複数人(友人)で予定(グループ)を作り、
各々が起床時間を設定して、その時間に起きてるかどうかを予定詳細画面で確認できる。
みたいな感じです。

起きてるかどうかの判定としては、


①起床時間を設定
↓
↓※起床時間に通知を飛ばす。(起きてる〜？)
↓
②通知を踏む or 通知後にアプリを開く (起きてる判定完了)


起きてる場合にはユーザーに起床済みのチェックがつく。

アプリの説明はこんな感じで実際にやっていった内容に入っていきます。

## 昔の反省

実はCloudFirestoreでアプリ作るのは2回目なんですね・・・。

### クソアプリ(Booze!)
https://apps.apple.com/jp/app/booze/id1445135576

1回目に作ったアプリは社会人になり、RDBをかじっていたので、ドヤ顔で正規化しまくりました。
飲み会誘うための補助として使えたらと思って…

もうメンテも何もしてないので、当時のデータ構造を載せます。


```
users
    └user_id
         ├ ユーザーの情報(名前とかメールとか)
         ├ group_Id(array(key:value))
         ├ friend_Id(array(key:value))
         └ calendar_Id(array(key:value))

groups
    └group_id
         ├ グループの情報(名前とか)
         ├ user_Id(array(key:value))
         └ calendar_Id(array(key:value))

calendars
    └calendar_id
         ├ カレンダーの情報(日付とか)
         ├ user_Id(array(key:value))
         └ group_Id(参照用)

```

もう正規化してるのか、非正規化をしているのかわからなくなりました・・・。
当時の自分はわからない・・・。

これだと、自分が所属するグループのメンバー取得するときとか

①ユーザーが所属するグループのIDを取得（検索）
↓
②グループからユーザーIDの一覧を取得
↓
↓ユーザーのIDでFor文回す
↓
③ユーザー情報を取得

みたいな感じになっていたわけです。
(なんかFor文書きまくったなぁ・・・・)

まぁ当時の反省はこのくらいにして、
今回は頑張ってCloudFireStoreぽく設計しようと思ったわけです。


## 今回の設計について

雑ですが、画面デザインしたのがあるので
載せておきます。

![Slice.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/514870/36912de7-8a32-6a55-7f64-6b16dcc67ee4.png)


とまぁざっくりこんな感じなのですが、
ざっくりメインどころとしては、

・Home画面で自分が参加している予定が一覧でみれる。
・サイドバーから友人の一覧画面をみれる。
・自分に届いた通知の一覧が見れる。

といった要件があります。（まぁよくあるやつだと思います。）


※CloudFirestoreでは見えるのものは全て非正規化するべき

この考え方を僕はこう解釈しました。
→取りたい情報は１クエリで取ってこれるようにして、For文はなるべく回さない。


最初に設計したのはこんな感じになりました。
みづらくてすみません。。

```
#FireStoreでのデータ構造
#Collection-Document-Field(Collection)-Document-Field(Collection)-Document-Field

users
    └ user_id
          ├ ユーザーの情報(名前とかメールとか)
          ├ plans(SubCollection)
          │                     └ plan_id
          │                          ├ 予定の情報
          │                          └ users(参加するユーザー)
          │                                              └user_id
          │                                                    └　ユーザーの情報
          ├ friends(SubCollection)
          │                     └ user_id
          │                          └ ユーザーの情報
          │
          └ notifications(SubCollection)
                                └ notification_id
                                     └ 通知の情報
```

ユーザーに全部持たせちゃえば、よくね？
となったわけです。（非正規化の鏡）

CloudFireStoreは書き込みに時間かかるっていうし、まぁいいよね
って思っていたわけですが、気づきました。

さすがに、ユーザー情報とか変更した時にだるすぎない？

例えば、自分の友人が名前一つ変更しただけで
そのその変更を他のユーザーのグループ情報に毎回書き込みにいくわけです。
予定はどんどん増えていくので、この感じだと微妙すぎる。
と感じたわけです。（というかユーザーごとに予定の情報持つ意味あるか？って話ですね、はい）

目に見えるものは全部持たせる・・・・（あいまいすぎた・・。）


というわけで、予定に参加するメンバーは
全員で同じ情報を参照するように変更しました。（ユーザーにも予定の詳細情報は持たせています。）


```
#FireStoreでのデータ構造
#Collection-Document-Field(Collection)-Document-Field(Collection)-Document-Field

users
    └ user_id
          ├ ユーザーの情報(名前とかメールとか)
          ├ plans(SubCollection)
          │                     └ plan_id
          │                          └ 予定の情報
          ├ friends(SubCollection)
          │                     └ user_id
          │                          └ ユーザーの情報
          │
          └ notifications(SubCollection)
                                └ notification_id
                                     └ 通知の情報

plans
    └ plan_id
　　　　　　 ├ 予定の情報
           └ users(参加するユーザー)
                               └ user_id
                                     └　ユーザーの情報
```

だいぶスッキリしました。

この設計にしたおかげで、予定作成時の書き込み処理がだいぶ早くなりました。
さっきの設計だと予定の参加メンバーとか20人とかいたら結構時間かかりそう・・・。


## 設計してみて

今回は一応上の構造でおさまったのですが、
結構やりながら構造が変わっていったというのが本音です。（上の設計が正しいと思っていた時もあった。）

その辺柔軟に変えていけるのもFirestoreのいいとこだなと思いました。

なにより、サーバーレスなところがいい！(サーバー側全然知らない)

初心者でも割と簡単にアプリ作れるので本当にオススメです！

実際のアプリは12月中にはリリース予定なので
完成したらまた更新します！
[IOS#2のアドベントカレンダー](https://qiita.com/advent-calendar/2019/ios-2)にも参加してるので、
そっちにはもっとアプリの概要を詳しく書いていこうと思います。

もしこうした方がいいなど意見あれば優しく教えてください！
今回は拝読いただきありがとうございました！


##　参考
基礎から実施までCloud FirestoreによるiOSアプリ開発
https://booth.pm/ja/items/1034900

いろんな記事見たりもしたのですが、一貫して一個のアプリを作って設計してと
全体感がわかるためには本だ！ということでこちらを元に今回作成しました！

CloudFunctionの使い方とか、セキュリティールールの書き方とか
初心者が飛ばしたくなる内容も丁寧に書いてあって
とても参考になりました！