Firebase×Reactでプログラミングお題サイトをつくった話

# Firebase×Reactでプログラミングお題サイトをつくった話
この記事は、[ひとり開発 Advent Calendar 2019](https://qiita.com/p1ass/items/1dfb77d5d978568686a1)の13日目の記事になります。

## プログラミングお題サイトの紹介
個人開発が趣味の人ならあるあるだと思いますが、なんとなく開発したいけど何を作ろうかな～でも特に思いつかないな～:thinking:なんて迷ったりすることありますよね

そんな迷える個人開発者やプログラミング初心者向けのプログラミングお題サイトFirebase×Reactで作ってみました！
:point_right::point_right::point_right:[プログラミングお題サイト](https://programming-odai.web.app/):point_left::point_left::point_left:
![プログラミングお題サイト.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/120823/aa55c517-c6ed-b83f-7718-cd5fe5f356df.png)

ソースコードはこちら
https://github.com/yakipudding/programming-odai

### 特徴①自分に合ったお題を探せる！
プログラミングお題サイトでは、人気のお題や特定のタグのお題を探すことができます
![人気のお題.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/120823/948705a5-a5e5-efde-2172-9aa3fc5a8a3f.png)

![お題ページ.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/120823/bd5c509b-c9bd-925a-32eb-753653f88385.png)

気に入ったお題に対して「いいね」をしたり、「つくってみたれぽ」を投稿することができます！

### 特徴②お題を投稿できる！
プログラミングお題は自分で投稿することもできます！
![お題投稿.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/120823/00c62585-c0de-b60d-b2b4-4a76a2f2498e.png)

Markdown記法でブログ記事のように書けるので、体裁を気にせず気楽に投稿することができます！
チュートリアルでやった良い題材を投稿したり、自分のアイデアを共有してみんな作ってみて！ということもできます。

### 特徴③つくってみたを投稿できる！
お題に対して、C○○kpadの「つくれぽ」ならぬ「つくってみたれぽ」を投稿することができます

![つくってみた投稿.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/120823/5c1057e7-0cd6-8fab-d45e-ab30c25069a4.png)

お題をつくったブログ記事やGitHubレポジトリを投稿することで記事を見てもらうきっかきになったり、初心者プログラマが参考にしたりすることができます！

作ってみた系や個人開発系の記事はQiitaだろうがブログだろうがスルーされやすい:sob:全然いいねつかない:sob::sob::sob:（気がする）ので、つくってみたれぽを公開して他の人に見てもらう機会を増やそう！というコンセプトもあったりします笑

## プログラミングお題サイトを作ってみて
我ながらなかなか良いアイデアのWebアプリが作れたな～と、わりと気に入っています、、、が
なかなか苦労した点も多くありました

### いいね機能、意外と奥が深い件
SNSっぽくいいねつけられるようにしよう！と思ったのですが、いざ実装しようとすると意外と大変でした。

「いいね」機能を実装するためには、「誰が何にいいねした」「どの記事に何いいねついているか」「自分がなんの記事にいいねしたか」などの情報を取得できるように、いいね情報をDBに登録する必要があります

- お題に「いいね」をしたとき
    - いいねテーブルにユーザーID・お題IDのレコードを挿入
- お題の「いいね」を削除したとき
    - いいねテーブルのユーザーID・お題IDのレコードを削除（または削除フラグ）
- お題一覧をみたとき
    - お題ごとにログインユーザーが「いいねしているかどうか」をいいねテーブルとJOINして取得

たかだか「いいね」機能ですが、必要なDB処理はそこそこあるな、、という感じに。。。
さらにDBはFirebaseのRealtime Database※を使っていた関係でJOINができないため、手動JOIN（お題IDでループで回して取得）する必要があったりして…:innocent::innocent::innocent:
RDBの偉大さを知ったのでした。。。

DB設計に関してはお題に対していいねユーザーを紐付けるなど様々なやり方がありますが、いいねしたお題一覧も見たい（未実装）な～と考えたりしたのもあり、別テーブルとして保持することにしました

※FirebaseのDBはRealtime DatabaseとFirestoreがあり、機能としては後者のほうが良いです（クエリ機能が充実しているなど）
Firestoreを使わなかった理由は、課金単位が1日単位であり、かつそこそこシビアな上限だからです。こういうアドベントカレンダーで公開するようなサービスだと公開日にアクセスが集中してしまうと（しなかったら悲しい）上限に達してしまうため、ちょっと向いていないかもな…と避けました。ちなみにFirestoreもJOINはできません。。。

### タグ機能、なかなか実装がつらかった件
お題に対してタグ（複数可）をつけて検索できるといいよね！とかる～く思ったのですが、、意外とタグ機能は要件がエグかったです。。。

- タグの情報をどうやって保存するのか問題
    - お題に対して複数登録できるタグの情報を保存しておく必要がある
        - タグ項目を1つ用意しておき表示時に分割する？
        - お題に対して登録したタグのテーブル（1-N関係）を用意する？
    - タグで検索できるようにする必要がある
        - このタグが付与してあるお題一覧を取得する、というクエリが必要
            - タグのもたせ方によって検索がエグくなってしまう

という問題があったため、DB設計に関して工夫が必要でした。
ちなみにRealtime DatabaseはLike検索ができません:innocent::innocent::innocent:

結局、
    
- お題テーブルにタグ項目（1項目でスペース区切り保持）をもたせる
- お題投稿時、お題タグテーブルに対してタグID・お題IDのレコードを登録
- タグ検索時、お題タグテーブルからタグIDで抽出して検索

という形で無理やりなんとかしました。。
RDBではないので正規化はしません:point_up:

### 世の中のWebサービスすごいってなった
個人開発レベルやいいね機能とタグ機能をさくっと実装しようとしてもこんなに大変なのに、ユーザー数多いWebサービスって本当にすごいな…と思いました。
こういった「世の中のWebサービスでよくある機能」を個人開発で実装してみるのも、実装の難しさを肌で感じたりできるので楽しいですよ！

### RDBすごいってなった
タダより高いものはない精神でNoSQLのFirebeseのRealtime Databaseを使っていましたが、やはりJOINができなかったりLike検索ができない関係で、リッチな実装は限界があるなぁと感じました。
DBを無料で使えるという強力すぎるアドバンテージですが、実際の運用を考えるとかなり設計を工夫しないと難しいんだろうな～と思います。。

普段はRDB（SQL Server）を使っているのですが、RDBが便利すぎて設計はあぐらをかいていたな～というか、楽をしていたんだな～と身にしみました。
RDBであってもデータの参照のされ方を意識して、JOINやWHEREのキーを意識したりインデックスを考えた設計にしないといけないな…と改めて思いました:thinking:

### 締め
というわけでプログラミングお題サイトの紹介でした！
いろいろ苦労もありますが、趣味の一つとして個人開発はやっぱり楽しいですね。今後もいろいろ作っていこうと思います。