【Flutter】非エンジニアがFlutter×Firebaseで「ゲームの記録・レビューSNS」を作った話

初めまして
ゲームレビューSNSアプリ「GamerNote」をリリースしました。
非エンジニアの私が、初めてアプリ開発をしたので簡単にですが記録を残します。

[▼Android版](https://play.google.com/store/apps/details?id=net.gamedx.gamerNote)
[▼iOS版](https://apps.apple.com/jp/app/gamernote/id1565170628)
![iOS の画像.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/816749/1a92eddf-ac58-94f7-1b76-ab07ce799310.png)

#はじめに
簡単に自己紹介。

プログラミング歴：**ゼロ年**
　→もちろんエンジニアとしての経験も**ゼロ年**です。

本職はwebマーケティングで主に広告領域を担当してます。

そのため、Javascriptで書かれた広告タグやを取り扱うことはありますが、自分で何かを作り上げるようなプログラミング経験は殆どありません。（Progateは挫折しました）

</br>
今回記事を投稿しようと思ったのは、
・非エンジニアでもアプリ開発できるんだという事
・「Flutter×Firebase」はそれを実現させてくれる
という2点を初学者に伝えられればと思ったからです。

#GamerNoteの紹介
まず、私が作ったアプリGamerNoteの紹介です。
簡単にいうと、ゲーム検索エンジンサービスにレビュー機能や記録・クリップ機能を付け加えたアプリです。
今のところ12,800以上のタイトルに対応していて、今もなお増え続けています。

また後でも説明していますが、先ほどリンクを貼ったGameDX.netの一部機能を切り取ったアプリでもあります。


##リリースまでにかかった時間
学習（Udemy）：1ヶ月
開発期間：9ヶ月

毎日仕事終わりに1分〜5時間（平均3時間）ほど。
（0分の日があったら負けというルールを自分の中で作った。）

また、土日はずっと触ってました。こんなにゲームを我慢して作業するのは中学受験以来で、本当に禿げるかと思いました。

</br>
GamerNoteの根本はゲームタイトルを扱うWebページを対象とした検索エンジンサービスなので、画像の利用はサムネイルとしての利用にとどまり、全ての画像が出典元のページに対応し、遷移できるようになっています。
この仕様を実現するためのクロールは思っているほど簡単にはいかず、かなりの工数がかかることになりました。

##GamerNote主な機能
主な機能は5つのカテゴリーに分かれています。

1. 検索機能
2. SNS機能
3. レビュー機能
4. クリップ機能
5. ニュース機能


###①検索機能
![E3F1VImUUAEuM_Q.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/816749/c0821b7e-79ac-aa7d-d2ec-83ea5bc5129b.jpeg)

GamerNoteの根幹となる機能で、この検索機能を取り巻くようにして後に紹介する機能がついています。

Firebaseのドキュメントでは、Firestore内のドキュメント検索についてはAlgoliaをお勧めしてたのですが、今後グロースしていくことを考えてElasticSearchにしました。

Ngramを使った検索も実装しているので、サクサク検索できるようになっています。

###②SNS機能
<img width="200" alt="GamerNote_timeline" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/816749/95e2d7c8-dc40-6d50-574a-ee710b039113.jpeg"> <img width="204" alt="GamerNote_timeline" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/816749/48f877c1-eb9b-523e-41e0-bb277e6f8ffd.png">


これはもう簡単に想像できるかと思いますが、
「フォロー・フォロワー」「タイムライン」「マイページ」「各種通知機能」
など、Twitter的な機能です。

GamerNoteでは、後ほど紹介するレビュー・クリップなどの機能をもとに他のユーザーを知ることになるので、ユーザーの詳細を確認するためにマイページを用意しました。（Twitterのプロフィールにあたります）

</br>
また、ユーザーのゲーム歴を知るため、わざわざレビューを全て読むわけにはいかないので、「触ったことのあるゲーム機」も登録できるようになっています。

単に「ゲーマー」といっても**レトロゲームが好きな人**もいれば**最新機種しか遊ばない人**もいるので、これを見れば世代やユーザーの傾向を知ることができます。
<img width="150" alt="GamerNote_link" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/816749/94b16d18-8e26-e5df-d5ef-022d75bf8a65.jpeg">
ゲーム機以外にも、「ベストゲーム」「ゲーマーアカウント」も設定することができるので、Switchを持ってる人・フレンド募集中の人・ゲストゲームの趣味が合う人など、マイページだけでゲーマー属性を素早く汲み取れるようになっています。
<img width="150" alt="GamerNote_bestgame" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/816749/b61ff5ea-d2d4-a2a1-a04d-0aab1d6f8beb.jpeg">　<img width="141" alt="GamerNote_account" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/816749/1cc4c0d5-41b5-863f-54a1-7e0dd09dfd27.jpeg">
###③レビュー機能
まんまです。ゲームのレビューをします。

「レビューを投稿する = プレイしたゲーム」
としてGamerNoteでは記録されます。

ただ、レビューのコメントを必須にすると投稿がだるいので、文字なしでも投稿できるようにしました。
その場合は評価点数のみとなりますが、それすら面倒な人がいると思うので、評価を設定しない場合は2.5点で投稿されるようになっています。

あえてコメントなしレビューも計算に加えることで、コメントを入れたいほど熱意を持ったゲーマーの多いゲームが評価ブーストかかりやすいようになっています。（逆もしかり、マイナスブーストもあり得ます）

</br>
また、レビューを好んで投稿してくれそうな人をTwitterで調べてみると、ゲームブログに感想を綴っている方がほとんどでした。

TwitterみたいなSNSだと文字数制限があるのでブログへ流れるのは当たり前ですが、そういった方々に改めてGamerNoteにレビュー投稿をしてもらうのも申し訳ないので、レビューにブログのリンクを設定できるようにしました。

サイトリンクを設定してもらえればレビューの一覧にOGPが出るので、サイト流入にもつながるようになっています。
<img width="200" alt="GamerNote_link" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/816749/170a529f-8124-6145-f5e9-4bffab0cfff0.jpeg">
**この考えに至ったもう1つの背景として、個人運営の攻略サイトや個人レビューブログが絶滅危惧種になっている問題があります。**

これは、[KENTさんのnote](https://note.com/kentworld/n/na931839d30f7)を読んで考えさせられるものがあったので、少しでもゲーマー界隈に貢献できればと思い、この機能を実装しました。

大手に占領されてしまった今でも、ゲームの情報を発信してくれる人たちには頭が上がりません。

</br>
話は戻りまして、レビューには「いいね」「コメント」「シェア」「通報」「ブロック」ができるようになってます。

※iOSの場合、ユーザー生成コンテンツには通報・ブロック機能を付けないと審査にはじかれてしまいます。
　実際にGamerNoteもはじかれました。

###④クリップ機能
GamerNoteがノートとして活きてくる機能です。

・買ったゲームを詰んでる
・買おうと思ったけど忘れてた
・「え？これもう発売してたの！？」
これ全部ゲーマーあるあるですよね。

私は[XboxGamePass](https://www.xbox.com/ja-JP/xbox-game-pass/games)に加入してからこの現象が加速してます。
常に500タイトル詰まれてますからね…。


なので、気になったゲームをクリップできるようにしました。
後でレビューしようと思ってるゲームをクリップしてもいいですね。

###⑤ニュース機能
これもGamerNoteをゲーマー必須アプリとしていくための機能の１つです。

ゲーム最新情報って案外まとまっていなくて、それが原因でコピペブログへ人が流れている面もあるかなと思っています。
なので、GamerNoteのニュースタブをひらけば直近のゲームニュースを一覧で見れるようにしました。

本当はFeedlyのように指定したサイトをまとめられる機能にしようと思ったのですが、私の力不足で時間切れ。実装できませんでした。

年末までにはGamerNoteに登録してくれている人のサイト一覧や、Feedlyのようなサイト指定機能・おすすめニュースのレコメンドなどを実装しようと頑張っている段階です。


#アプリ開発〜リリースまでの流れ
私の場合は以下の通りでした。

1. アプリの方針を考える
2. アプリの機能を考える
3. UdemyでFlutterについて学ぶ
4. まずは画面とデータの送受信を作る。
5. CloudFunctions、プッシュ通知、DeepLinkなどを実装する
6. バグ取りと思いついた機能を追加していく
7. フォロワーさんにテストしてもらう
8. リリース

非エンジニアなのでリリースまでの手順は自己流です。

今になって考えて見れば、最初にUI設計などをしっかりすべきだったと凄まじく後悔しているので、これからアプリ開発始める方は納得いくまで時間をかけてUIについて考えた方がいいと思いました。

## ①〜②アプリの方針・機能を考える
アプリを作るきっかけとなったのが先ほど紹介した[GameDX.net](https://gamedx.net)の存在です。

このサイトではGamerNoteを遥かに超えるスペックで、
・ブログ投稿
・レビュー投稿
・グループ作成
・イベント管理
・大会管理機能
を搭載しています。実質ゲーム版のFacebookです。
元はと言えば、GamerNoteはGameDXのアプリ版として計画が始まりました。

ただ、GameDXはあまりにも機能が多すぎるので、GameDXの機能を一部切り離してアプリにすることにしました。
これがGamerNoteの始まりです。

そのため、必然的に機能もSNS・レビュー投稿に定まっていました。
（GameDXのその他の機能については既に制作を始めており、追ってリリースします。）
</br>
ただ、GamerNoteの方針については、「世界中のゲームを調べるためにはGamerNoteで検索すれば見つかる」というコンセプトがあったので、根幹にあたる機能を検索エンジンとし、それに対応するように上記機能を付け加えていきました。

##③Flutterについて学ぶ
なぜFlutterにしたかというと、
・Google開発
・Firebaseとの相性が良さそう。
・クロスプラットフォームでの作成ができる。
この3点だけです。

初学者は学ぶべきではない云々記事やYoutube動画を見ましたが、後々対応するCloudFunctionsも抵抗なく対応できたので、アプリ開発所信shあこそFlutterで良いんじゃないかと思っています。

学習にあたってはUdemyのアンジェラ先生の講座を見ました。
https://www.udemy.com/course/flutter-bootcamp-with-dart/


それ以外は学習用にサイト・書籍・動画を見るということは殆どなく、実装したい機能にチャレンジしてエラーや不具合が起きたらStackOverflowとGithub、Qiitaを見ていました。

GamerNoteを作る程度であれば、StackOverflow、Github、Qiitaで全て解決できました。

##④画面とデータの送受信を作る。
だいたい約4ヶ月くらいかかったと思います。

###画面
まず画面、構成はGameDXの主要機能から、
「タイムライン」「ゲームリスト」「検索」「ニュース」「マイページ」
を作ると決めました。

![Flowchart.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/816749/4e9a3ad0-9fba-919b-e13b-ce528b3359f4.png)

これはGameDXを作った時に用意したものですが、グループを一般的なソーシャル要素に置き換えただけで、特に変更はありません。

UI/UXについては先ほども書いた通り「試しに作ってみるか〜」の流れから最後のリリースまで行ってしまったので、配色・配置・画像サイズなど、全て行き当たりばったりで今だに後悔しています。
</br>
最初はダークモードを実装してたのですが、自己満なので削除しました。
こういう、他の開発者が実装してるのを見て、「真似して実装→使わないから削除」が4・5回ありました。
こうならないためにも、最初にUIはしっかり組み立ててから作り始めることをお勧めします。

</br>
こんなのもあったりするので、次は活用してみようと思います。
[「Adobe XD」のデザインを「Flutter」のコードに変換するプラグインが一般公開](https://forest.watch.impress.co.jp/docs/news/1279609.html)


###データの送受信
これはCloudFirestoreを使いました。

特に私から言及することはないのですが、Firebaseさえあれば様々な機能が簡単に導入できるので、個人開発で使わない手はないなと思っています。特に私のような初学者には神のようなツールでした。

Udemyの講座の中でも使い方の説明があったので、導入は簡単にできました。

時間がかかったのはFirestoreのコレクションとドキュメントの構成です。

SNSということなので、
ユーザーをコレクションとして扱うのか、ユーザーコレクションにユーザーを格納するのか。
フォロワーリストは、自分に書き込んで相手に読み込ませるのか、相手に書き込んで自分が読み込むのか。それともuidで管理して都度全ユーザーを取得するのか…などなど


こういうのを考えてる時間がかなり長かったです。


##⑤CloudFunctions、プッシュ通知、DeepLinkなどを実装する

####CloudFunctions
これは時間がかかりました、Flutter以外の言語「node.js」を取り扱う必要があったからです。

④で作ったFirestoreですが、ユーザー同士でお互いに情報を書き込みしあう状況だとセキュリティーに問題があると思ったので、「フォロー」や「いいね」などの他人とデータのやり取りが必要になる機能はこのタイミングで大幅に刷新しました。

これも先に必要な機能をまとめておくと並行して作業できたかなと、今になって後悔しています。

【フォローした時】
▼改善前の挙動
・自分のFolloweeと相手のFollowerにフォローした人が書き込む。

▼改善後の挙動
・一度自分のドキュメントにフォロー相手の情報を書き込む
・それをトリガーにしてCloudFunctions起動
・CloudFunctionsで相手のドキュメントに自分の情報を書き込む

こんな感じで、直接他人のコレクションとやり取りが発生しないようにしました。

※参考
[Cloud Firestoreで「いいね」機能を実装するときの勘所](https://tech-blog.sgr-ksmt.org/2019/12/31/160623/)

タイムラインも同じような感じなのですが、フォロワーが多いほど書き込む相手が増えるので、本当にこれでいいのかと不安になり、何度もGithubやStackOverflowで事例を探しました。

結果的には、やはり大量の書き込み、もしくは読み込みが発生させるしかないらしく、Twitterが長い間赤字経営を続けていた理由を身をもって実感しました。

CloudFuncsions導入で、自動処理できるようになったのでアプリとしての完成度も急激にアップしました。


####プッシュ通知
これもCloudFunctions導入のおかげで実装することができました。
・いいねする
・いいねをトリガーにFunctions起動
・相手への通知を処理

コメントやフォローに関しても同様です。

FirebaseCloudMessagingのドキュメント通りに実装しただけなので、数日で対応できました。


####DeepLink
これが地味に苦労しました。
起動してもパラメータをうまく受け取れず、遷移しなかったり。
詳細は省くのですが、これもタイミングを見て記事にしようかと思います。
（私の失敗例しか書けることありませんが・・・。）


##⑥バグ取りと思いついた機能を追加していく
これも良くなかったところ。

UIもまともに設計しないまま突き進んだので、やっぱり後から実装したい機能やデザインが湧いてきたりしました。
最初実装するか迷ってたベストゲームは、Filmarksさんでも実装しているのを見つけて実装を決意したり・・・。

そうなってくると、実装のたびに他の画面からの遷移やデータの保持をどうするかとかCloudFunctionsどうするだとか、そういうのを2021年に入ってからずっとやってました。長かったし、無駄な時間がかなりありました。

あとTestFlight出してからも、スクロールの挙動が変だとか、ディープリンクで遷移しないとか色々あった。

##⑦フォロワーさんにテストしてもらう
フォロワーさんにテストしてもらったというだけなのですが、
androidのアイコンが出ないというトラブルがありました。

[【Android】開発中のアプリのアイコンがホーム画面に表示されない場合の対処法
](https://develop.hateblo.jp/entry/android-app-icon-home)

これ以外は特に問題なく、参考資料も多かったのでテストはスムーズにできました。

一番の懸念だったFirestoreの読み込み・書き込みの量も安定していて、無限ループだったりとかも発生しないことが確認できたので、リリース前にユーザーテストを小規模でも実施できたのはかなり良かったかなと。

##リリース後
リリースしたら、あとは施策回していくだけだと考えていたのですが
ユーザーからの問い合わせやバグ修正に追われてしまい、リリース後しばらくはほとんど寝れない状態に…。

今もなおバグ修正等は続いておりますが、ユーザーさんにかなり我慢してもらっている状況が続いています。

#感想
FlutterやFirebaseのおかげで工数的には助かったものの、ほんとしんどかったです。

朝5時半に起きて出社し、17時に家に帰ってからご飯を作り（自炊派）、食べ終わってから黙々と作業。

作業というか、全てが未経験でわからないことだったので、ずっと勉強してる感覚でした。
でも分かってくると**アプリ開発マジで楽しい**という気持ちも並走してました。

昨年12月に入籍したのですが、家のことが少し疎かになってしまい嫁に迷惑をかけてしまったかなと思っています。
そこは大いに反省。

個人開発を長年続けている方々、本当にすごいんだなと痛感した10ヶ月でした。

#最後に

GamerNoteはまだまだスタート地点です。
まだ実装できてない機能や構想が山ほどあって、その必要最低限をリリースした状態です。
なので、目標のゲーマー必須アプリを目指してアプデを重ねていきます。

個人開発なのでユーザーのサポートを十分にできるのか不安ですが、皆様から届いている励ましの声で頑張れています。

また、私がアプリをリリースまでたどり着けたのは、多くの方のサポートがあったからこそです。

・Qiitaに投稿してくださっている先輩方
・Flutterオープンチャットの皆様
・素敵なFlutter Packageを公開してくださっている皆様
・β版のテストに参加してくださった皆様
・そしてゲーム業界に携わっている皆様

本当にありがとうございました。
そしてこれからもよろしくお願いします。