Firebaseを利用したAndroidアプリをリリースしたお話

# はじめに
初めてAndroidの個人アプリをリリースしたことを契機に、Qiita始めてみました。
この記事では、以下についてお話します。

- どんなアプリをリリースしたか
- リリースまでの稼働時間は？
- Androidアプリ開発に活用したサービスやツール
- Firebaseを採用する前に知っておきたかったこと
- その他、反省点


# どんな個人アプリをリリースした？
冒頭に、作ったアプリの宣伝だけさせてください...！
匿名で質問を投稿できるアンケートアプリ「***Anshare***」をリリースしました:raised_hands:
ぜひ使ってみてください。そして辛辣なご意見お待ちしてます。

https://play.google.com/store/apps/details?id=com.crabsan.anshare

## アプリの機能
- ユーザは、2~4択の質問を投稿できる
    - 質問の投稿者は、回答の統計データを知ることができる
        - 回答の各割合
        - 回答したユーザの年齢層
        - 回答したユーザの地域
- ユーザは、質問に対して各ユーザは1回だけ回答できる
    - 回答者は、回答の各割合を知ることができる

## アプリのイメージ
こんな感じの画面、挙動です！！

| 投稿画面 | 回答画面 | 集計画面1 | 集計画面2 | 集計画面3 |
| :-: | :-: | :-: | :-: | :-: |
| <img width="480" alt="Anshare投稿画面" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/424303/545c9143-7f8c-93b9-1527-91200c6b8c1d.png"> | <img width="480" alt="Anshare回答画面" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/424303/89e9ae80-4d7b-f6f6-edf0-d9d14c207065.png"> |  <img width="480" alt="Anshare集計結果画面の回答別" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/424303/9e684052-c0d0-b66b-308c-0485932de44e.png"> | <img width="480" alt="Anshare集計結果画面の年齢別" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/424303/bf20ba93-8f68-6699-e739-bbb0e054215a.png"> | <img width="480" alt="Anshare集計結果画面の地域別" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/424303/940849d8-af40-77e3-0192-cd26d0537665.png"> |





## 利用したFirebaseプロダクト
- Authentication
- Firestore
- Functions
- Remote Config
- Cloud Messaging
- Crashlytics
- AdMob

# リリースまでの稼働時間は？
2020年から着手して、リリースまで1年2ヵ月掛かりました。
土日の隙間時間でコツコツという感じです。（~~2020年の8月から年末まで別の開発に浮気してたりしてます(笑)~~）
実質7~8ヵ月といったところでしょうか。

| 2020 | 2021 |
| :-: | :-: |
| ![contributions_in_2020.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/424303/e51574e8-5bba-c6ad-6b75-03cb79e4effa.png) | ![contributions_in_2021.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/424303/b15f6cc2-0d94-a2ef-0db9-08a3942470c3.png) |

# Androidアプリ開発に活用したサービスやツール
個人アプリ開発で活用したサービスやツールをご紹介。（githubやandroid studioに付随するツール、adb等は省きました。）
僕が知らないだけで、世の中にはもっと作業効率を向上させるアイテムがあるはず。
（色々コメントで教えていただけると嬉しいです！）

| サービス / ツール | 利用用途 | イメージ |
| :-- | :-- | :-: |
| [Adobe XD](https://www.adobe.com/jp/products/xd.html) | UI/UXデザインツール。<br>僕は画面構成だけでなく、サービスアイコンも全てXDで作りました(笑) | <img width="640" alt="xd-image" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/424303/30b66b1d-ab6f-3900-94f2-e087a5bebbf6.png"> |
| [Draw.io](https://spc-jpn.co.jp/blog/14748/) | フローチャートやシーケンス図をオンライン上で作成できるサービス。<br>情報整理に最適。<br>僕は処理フローの整理（右の画像が実際のフローの1部）やFirestoreのデータ設計等で利用しました。 | <img width="640" alt="draw-io-image" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/424303/5fc7c37c-366a-0fe4-2fb0-8073d566b1c1.png"> |


# Firebaseを採用する前に知っておきたかったこと
## Firestoreの検索機能は弱い
Firestoreをデータストアとして利用しようと考えておられる方、こちら**要注意**です。
例えば、以下のような条件でデータを取得することができません。

- 自分(userA)が投稿したデータでない
- 3/2以降のデータ

```
// 下記のようなドキュメント構成を仮定
{
  title: '質問'
  category: 'game',
  uid: 'testUser'
  createdAt: '2021/3/3 12:00:00'
}
```

```
// Selectしてみる
mFirestore.collection("questions")
                .whereNotEqualTo("uid", 'userA')
                .whereGreaterThan("createdAt", '2021/3/2 00:00:00')
                .get();
```

```
// エラー...。
2021-03-03 22:59:49.807 25606-25606/com.crabsan.anshare.debug W/xxx: onError, Firestore select error.
    java.lang.IllegalArgumentException: All where filters with an inequality (notEqualTo, notIn, lessThan, lessThanOrEqualTo, greaterThan, or greaterThanOrEqualTo) must be on the same field. But you have filters on 'uid' and 'createdAt'
        at com.google.firebase.firestore.Query.validateNewFilter(Query.java:561)
        at com.google.firebase.firestore.Query.whereHelper(Query.java:431)
        at com.google.firebase.firestore.Query.whereGreaterThan(Query.java:204)
```

そうなんです。**Firestoreでnot検索をする場合、複数項目を検索条件に持つことはできません**:sob:
この仕様を把握できていなかったので、色々と仕様を変更して制約とするハメになりました...。
他にも制約があったりするので、採用前は念入りに確認をオススメします。

[クエリの制限事項](https://firebase.google.com/docs/firestore/query-data/queries#query_limitations)
> 複合クエリにおいて、範囲（<、<=、>、>=）と不等値（!=）の比較は、すべて同一のフィールドに対するフィルタである必要があります。

改善策は、[Algolia](https://www.algolia.com/)や[ElasticSearch](https://www.elastic.co/jp/elasticsearch/)といった別サービスと組み合わせる必要があるそうです。※1
お金を極力かけたくなかったため、こちらは断念しました。


## Firestoreの読み取り回数問題
例えば、下記 `answerd_users` サブコレクションに入っているドキュメント数を取得したい場合です。
ドキュメント数を取得するにはサブコレクション配下を全件取得するしか方法がなく、読み取り回数は`4request`となります。`1request`ではないのです。
そのため、データ増加に沿ってリニア的に読み取り回数が増えることに...:crying_cat_face:

対応策としては`サブコレクション自体`にカウンターを持たせて対応しました。
ドキュメント追加時にカウンターをインクリメントすることで書き込み回数は増えますが、データ数取得時は`1request`だけとなるためトータルで見ると読取コストを削減することができます:middle_finger:

| 修正前 | 修正後 |
| :-: | :-: |
| <img width="500" alt="firestore-caution-image1" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/424303/63ffe91e-5f85-c539-46e4-37550fc237b9.png"> | <img width="500" alt="firestore-caution-image2" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/424303/ad450ac9-fc70-ff4e-937e-7109ffd5684f.png"> |


## 利用料金の上限リミッターを設定できない
FirestoreやFunctions等は、無料枠はありますが利用した分だけ青天井でお金を支払わないといけません。
プラットフォーム側で上限を設定可能と思っていたが、出来ないのです。
課金額が閾値を超えたらアラートを送信する機能はありましたが、機能を制限してを課金を止めるリミッターはありませんでした。
Firestore宛にメールで問い合わせてみましたが、結果は同じで要約すると以下のような回答でした。

- 制限機能は無い
- Firestoreのベストプラクティスの推奨事項に従うことをオススメする

対応策として、`RemoteConfig` を利用してアプリをメンテナンスモード（起動不可制御）に変更できるような機能追加をしました。
リリース後、収入 < 支出となった場合にはこの機能を活用してサービス停止するかもしれないです。（~~弱気~~）

<img width="1000" alt="firestore-support-contact" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/424303/2e4835ca-688b-5f37-e17c-660103555acd.png">

# その他の反省点
## デザイン・機能を固めてから開発すべし
Adobe XDでぼんやりUIを作って、後は開発しながら考えようと始めた結果、無駄な開発、修正をすることが多かったです。
事前にガッチリ計画する時間を取った方が、必要工数は間違いなく短縮できたと思ってます。

下図は当初作ったUI/UXの1部。
画像の2択アプリを想定して投稿機能まで実際に開発したのですが、予算や休日1人で運用することを考えたら厳しいと実感して断念。今リリースした内容に方向転換しました。次は失敗しないぞ:innocent:
<img width="1000" alt="adobe-xd-img" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/424303/a46a0730-d891-1e65-dd53-66c17adf0c0e.png">

## KotlinやJetpack等、Android純ライブラリをもっと活用すべきだった
JavaオンリーでRxjava、butterknife等の外部ライブラリを活用しつつ開発していたのですが、下記のようなGoogleが用意してくれているライブラリで代替できる場合が多かった。
時代に取り残されている感がすごいので、次は積極的に使っていきたい。

- Kotlin（コルーチン）
- hilt
- databinding
- viewmodel
- livedata
- lifecycle


# まとめ
リリースしたアプリは全てFirebase内に完結しており、Firebaseはとても便利であることを実感。
けれども、しっかりと事前調査しておかないと僕の二の舞になるということだけ覚えていただければと思います...！
他の個人アプリを作る機会があれば、この失敗を糧にしていきたい:muscle:

# 個人アプリ開発で得た知見共有
https://qiita.com/takashikatt/items/e17401ff301b71e821cd



# 参考にさせていただいたドキュメント
※1 https://qiita.com/1amageek/items/d606dcee9fbcf21eeec6