[個人開発]誰かの人生の1ページを覗けるアプリをGo&Reactでサーバーレスに開発

はじめまして！ご覧いただきありがとうございます。
都内の大学に通うtenshinです。エンジニアのインターンとして働き始めて、最初の頃よりはある程度できることも増えてきたので、身に付けた知識を使ってアプリを作ろうと思いました。前々からこんなアプリあるといいなーなんて思っていたアイデアを形にしてみました！ぜひ使ってくみてください！

UnknownDiary
[https://prod.unknown-diary.com/](https://prod.unknown-diary.com/)
create accout から 一意なユーザー名とパスワードでアカウントを作成し、ログインしてください。

日記を書くとかではなく、適当にPOSTしたり触ってみたりしたい場合は以下を利用していただけるとありがたいです。

```
username: テスト太郎  
password: 12345678
```

UnknownDiary-dev
[https://dev.unknown-diary.com/](https://dev.unknown-diary.com/)


（（何か致命的な問題点などありましたらこっそり教えていただけるとありがたいです））

[ソースコード](https://github.com/s-amano/unknown-diary)

# アプリの概要

>旅行をした帰りの電車の窓から流れる人を見たとき、その人も僕と同じように楽しんだり悲しんだり苦闘しながら生きているのだろうかと思いました。そんな全く見ず知らずの人の人生について考えている時に作りたいと思ったアプリです。ボトルメールをイメージして作りました。[ボトルメールのWikipediaはこちら](https://ja.wikipedia.org/wiki/%E3%83%9C%E3%83%88%E3%83%AB%E3%83%A1%E3%83%BC%E3%83%AB)
このアプリでは、貴方の感動した日、人生の転機になった日、良いことがあった日、失恋した日、奇跡が起きた日などを綴って日記としてPOSTして見知らぬ誰かに届けてください。
逆に貴方は見知らぬ誰かの想い出のあの日を見ることで、人生の1ページを覗いた気分になれます。

Githubのアプリ概要を引用として持ってきました。要はどこの誰に届くかも分からない日記を書き、逆に自分はどこの誰か分からない人の日記を見る事ができる、というアプリです。日記の続きが気になり想像を膨らませたり、はたまた偶然その続きらしき日記が見つかったり。そんなことがあれば面白いかなと思います。

## 機能

- 誰かの日記を取得することができる
- 日記を送信することができる
- 自分の書いた日記を一覧で見ることができる
- 自分の書いた日記の詳細を見ることができる
- (new)誰かが書いた日記にリアクションをする機能

です。
利用していただける人が多ければ多いほど楽しいアプリになりますので皆さんぜひ使ってみてください！！

今後、受け取った日記を保存しておく機能や、変な文章書く人を通報する機能、(できれば文章を自動で判定したい)なんかも追加したいと思っています。
そして何よりデザインもっと頑張ります。

# フィードバック(随時追加)
- 日記を書くモチベーションが低い気がする。日記が誰かに届いているという実感が薄い。

→日記にリアクションを付けられる機能を追加しました！


# 以下は技術やその構成についてです

## 機能の補足

### 誰かの日記を取得する機能
dynamoDBから全件取得したあと、authorが自分でないものをFilterして、ランダムな1件をresponseする

### 日記にリアクションをつけることができ、それを著者が確認することができる機能
日記のリアクションボタンを押すと、該当の日記をDynamoDBから取得する。押したUserがreactioners配列に含まれていれば、reacrtionの数を1つ減らし、reactionersからUserを排除する。
押したUserがreactioners配列に含まれていなければ、reactionの数を1つ増やし、reactionersへUserを追加する。

## 使用した技術

今回アプリはサーバーレスに作っています。

- React (UIフレームワークにMaterial UI)(フロントの開発環境はDockerで構築)
- AWS (serverlessframework + Cloudformation で構築)
  - Lambda (APIとして利用, 言語はGolang)
  - DyanmoDB (データベース)
  - Cognito (認証)
  - Route53 (名前解決)
  - S3　(Webホスティング)
  - CloudFront (CDN)

フロントエンドはS3 のWebホスティング + CloudFrontで、バックエンドAPIはLambdaで実装、データベースにはDynamoDBという感じです。
認証にはAWS cognitoを利用しています。Amplifyのライブラリを利用しているので、ログイン画面のUIと機能は全てAWSが行ってくれています。
また、デプロイ作業をなるべく簡略化できるようにMakefileを作っています。後々、CI/CD環境導入したいです。


## 雑な構成図

<img width="775" alt="infra構成図" src="https://user-images.githubusercontent.com/53635209/114696010-2ac1ed80-9d57-11eb-94d4-a0bf1a3505bf.png">

## DynamoDBテーブル設計
なるべくテーブルは少ない方が良いらしいので、今回はPOSTされる日記を中心に考えてみました。

| HASH Key    | RANGE Key |            |                  |                          |          |                                                        | 
| ----------- | --------- | ---------- | ---------------- | ------------------------ | -------- | ------------------------------------------------------ | 
| uuid        | post_at   | author     | receiver         | post_data                | reaction | reactioners                                            | 
| 12345.67890 | 988999898 | テスト太郎 | テストレシーバー | {"content":"テスト日記"} | 2        | [ { "S" : " テストさん" }, { "S" : "サンプルユーザ" }] | 

post_dataにはフロントエンドからpostする際にBodyに格納されているdata一式を登録しています。今後、titleなどが追加される可能性を考慮してjson文字列型(データの型としては単なるString型)で登録しておき、バックエンドで使いやすくしています。


## グローバルインデックス(GSI)
- author-status_post_at-index
HASH KeyをauthorにRANGE Keyをpost_atに指定。  
自分の日記一覧を取得する際に利用

## 技術選定の理由

まず、ゴールとして想定するアプリはそこまで多機能ではなかったこと、従量課金であることを理由にサーバーレスでやろうと思いました。また、インフラのコード化をしたかったのでServerlessFrameworkとCloudFormationで構築しました。

バックエンドAPIはLambda+DynamoDBの経験が多かったのでそこはすぐに決まり、言語にはGoを選びました。ある程度経験があったのと静的型付け言語でありながら書きやすい、ネットにサンプルコードが沢山あるなどが選定の理由です。

データベースには、Lambdaと相性が良い、初期コストが安価、多いレコードにも低レイテンシーを維持でき得るという理由でDynamoDBを採用しています。

ユーザー認証と認可が必要なアプリでしたが、AWS cognitoを利用する事でとても簡単に実装する事ができました。セキュリティに関わることなので、なるべくマネージドに管理して欲しいなという要望もありました。初めて使ったのでかなり詰まりましたが何とか組み込む事ができました。

フロントの言語にはReactを使用しました。過去に少しだけ利用した事があり、TypeScriptとの相性が良く(後々TypeScriptで書こうと思っている)、material UIを利用してある程度まとまったレスポンシブ対応なデザインで実装できるといった点でReactを選びました。(ただ正直に言うと、実務でVue触っていて、React忘れかけていたから学び直したいという理由が大部分です。)

# 大変だったところ

- DynamoDBの設計と検索機能
 - DynamoDBの設計が難しかった(そもそもDB設計したことなかった)
 - 特に、GSIやLSI、各種キーについての理解が足りていなかった。
 - 検索機能が弱く、結局全件取得してからフィルターするという方法を取っているので日記の数が増えたらどうしよう。
- cognitoの組み込み
- ServerlessFrameworkとCloudFormationの記述 


# 感想と今後

ある程度のスピード感を持って作れたと思います。やはり自分のアイデアを元にアプリケーションを作るのはとても面白いなと感じました。全く触った事がない技術もほんの少しだけわかる状態になるので今後も作りたいものがあったらどんどん作っていきたいです。また、このようなまとめを書くと復習にちょうど良いなと思いました。意外と自分で実装したのになぜそう書いたか、どのような文献を参考に実装したかを忘れがちなので、都度いいタイミングで振り返ることが重要だと感じました。

このアプリケーションに関しては、まだまだ妥協した点が多く改善の余地はあると思ってます。
Lambdaの開発環境を整えたり、フロントをTypescriptで書いたり、CI/CD環境を導入したり、様々な機能を追加したり、Reactがかなり雑に書かれていたり、dev環境にBasic認証つけたり、CloudFormationもっとちゃんと書いたり、ELBで負荷分散したり、デザインもっとマシにしたりと尽きません。

これら突き詰めてもっとよいアプリにしていこうと思っていいますので、ぜひぜひ使ってみてください！