テイスティングの記録が行えるサービス「Tasting Note」をリリースしました

## はじめに
2023年7月3日に自作サービス [Tasting Note](https://tasting-note.com/) をリリースしました！

<img width="650" alt="Tasting Note Logo" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/930395/e882d9e1-9899-f58f-1bec-e6121a3e87aa.png"/>

https://github.com/yuma-matsui/tasting_note

この記事ではサービスの概要、開発を通して得た経験についてまとめています。

## 対象読者
- 未経験からプログラマーへの転職を目指している方
- 自作サービスの開発に取り組んでいる方
- J.S.A.ソムリエ呼称資格認定試験 2次試験（テイスティング）対策をしている方

## 自己紹介
@yuma_matzui です。
昨年、2022年2月から[FJOROD BOOT CAMP（フィヨルドブートキャンプ）](https://bootcamp.fjord.jp/)（以下FBC）でWebプログラマーになるための学習をしています。

Tasting Noteのリリースをもって卒業となり、現在は就職活動中です。

## Tasting Noteの紹介

### Tasting Noteとは
ワインテイスティングの記録が行えるサービスです。
試験で使用されるマークシートを模した回答フォームを用意しており、
本番さながらのコメントシートでテイスティングの記録が行えます。

<img width="500" alt="Tasting Sheet" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/930395/122008c0-bf12-8033-f29e-5f648318da02.png">

### こんな人に使って欲しい
- ソムリエ呼称資格試験・2次試験の対策をしている方
- ワインが好きな方
- ブラインドテイスティングをされる方

試験対策のために記録をつけるもよし。
趣味で飲んだワインの記録をつけるもよし。
ワインバーで目の前のワインを評価するもよし。

右手にワイングラス、左手にスマートフォンをもって気軽にテイスティングの記録をしていただけたら嬉しいです。


### 使い方

#### 登録をしないで使用
- 「登録しないではじめる」を押下
<img width="400" alt="instruction1" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/930395/fffb60ca-1374-448a-1061-9fe11ec81e35.png">

- シート名、テイスティング時間、ワインの色を入力
<img width="400" alt="instruction2" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/930395/ee171b03-f904-a50f-1f88-453b3e827bc7.png">

- 外観、香り、味わい、まとめの順に回答を入力する（前へ戻ることも可能）
<img width="400" alt="instruction3" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/930395/898db884-e949-69f7-ba08-025ece3de403.png">

<img width="400" alt="instruction4" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/930395/f311638f-92ab-3f93-4581-7e675b23ffc3.png">

<img width="400" alt="instruction5" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/930395/c36f3625-a9ff-ba4a-2f64-0c3705e8dba4.png">

<img width="400" alt="instruction6" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/930395/c5f2cbac-40cd-65f6-fb74-5c1469badc0b.png">

- 回答を確認
<img width="400" alt="instruction7" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/930395/9b2c189d-09fa-d7e2-f3e3-d9cc040603c9.png">

#### 登録をして使用
- 「サインアップ」を押下
<img width="400" alt="instruction8" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/930395/fffb60ca-1374-448a-1061-9fe11ec81e35.png">

- メールアドレス、パスワードを入力してアカウントの作成
<img width="400" alt="instruction9" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/930395/88131de0-a2ac-4113-f7e4-8fdc6c8e383f.png">


- 「テイスティングをはじめる」を押下
<img width="400" alt="instruction10" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/930395/f6e03ef4-8b89-6ce3-c72d-e311afda1898.png">

- 「登録をしないで使用」同様のフローでテイスティングを記録

**テイスティング記録後にワインの登録が行えます**
- 記録したテイスティングの個別ページ内「ワインの登録」を押下
<img width="400" alt="instrocution7" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/930395/8494d396-d292-f5c6-dd0b-bede76737d5a.png">

- ワインの情報を登録（ワイン名、ぶどう品種、生産国、ラベルの写真など）
<img width="400" alt="instrocution8" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/930395/d95b6049-2fc2-cb58-4d2a-20ce33621b1c.png">

### このサービスが解決できること
- 記録を行う際に必要な紙、ペン、タイマーを準備する手間が省ける
- 記録した紙を持ち運ぶ手間が省ける
- 振り返りが簡単に行える

筆者がソムリエ資格を取得した際は自宅で紙とペン、スマートフォンのタイマーを使用して模擬試験を行いました。
本番も紙とペンを使用するのでそれが正しい姿ではありますが、以下のデメリットがありました。

- コメントシートを毎回印刷しないといけない
- 外出先で復習をしたい場合に記録した紙を持ち運ぶ必要がある

Tasting Noteではワインとグラスさえあれば手軽に記録が行えて、持ち運びにも困りません。
また、振り返りの際も絞り込み検索を使用することで目的の記録まであっという間に辿り着けます。

## 技術スタック
- フロントエンド
  - React 18.2.0
  - TypeScript 4.9.3
- バックエンド
  - Ruby 3.1.2
  - Ruby on Rails 7.0.4
- インフラ
  - Terraform 1.4.6
  - AWS
    - S3（Web Hosting）
    - Cloudfront
    - Route53
    - ACM
    - S3（画像保存）
    - ECR
    - ECS
    - ALB
    - RDS
- CI/CD
  - GitHub Actions
- 開発環境
  - Docker 23.0.5
  - docker-compose 2.17.3

## 開発中にやって良かったこと

### もくもく自作サービス開発会

FBCではチャットツールにDiscordを使用しており、様々なチャンネルが存在しているのですが、「もくもく自作サービス開発会」というチャンネルを自ら立ち上げて、自作サービス開発のプラクティスに取り組む他のFBC生と一緒に開発を行いました。
作業中は特に会話はありませんが、インターバル中に作業内容や詰まったポイントを共有することで、サービス開発に対するモチベーションを高く維持できました。

[もくもく自作サービス開発会 \- Speaker Deck](https://speakerdeck.com/yumatsui1020/mokumokuzi-zuo-sabisukai-fa-hui?slide=7)

こちらについてはFBC内のイベントにて登壇、発表も行いました！


開発後半は中々実施をすることができず、一人での開発がほとんどになってしまいましたが、今振り返るとやはり仲間と時間を共有していた時の方が開発スピード、モチベーション共に高かったように思います。

また、就職に向けた情報・意見交換ができたのがとても良かったです！

### Issueをできるだけ小さくした
https://github.com/users/yuma-matsui/projects/11

Issueを立てる際は細かいTaskに切り分けることを意識しました。
例えば「ログインページを実装する」というIssueがあった場合は以下のように切り分けます。

- LoginForm コンポーネントをつくる
- EmailInput コンポーネントを作る
- PasswordInput コンポーネントを作る

Taskを細分化することのメリット・デメリットは以下です。
#### メリット
- Issueをcloseする機会が多くなりモチベーションが上がる
- 作業時間が見積りやすくなる
- 詰まった場合でも自分が何に詰まっているのか特定しやすい
- 次にやることが明確で迷わない
- PRが小さくなりやすいのでレビューの負担を減らすことができる

#### デメリット
- Issueを立てるのに時間がかかる
- ぱっと見のTask数が膨大なので先が思いやられる

自作サービス開発はとにかく長い旅路です。
地図は少しでも細かい方がゴールまでのイメージが湧きやすく、モチベーションを高く維持できるのでおすすめです！

また、今回は基本セルフレビューでしたが、PRを作った際には必ず変更を一つ一つ確認していたので、Taskを小さく分けることで変更があまり多くならず、レビュー時の負担が小さくなったのも良かったと思います。

### インフラ構築
今回のサービス開発で一番楽しかったことがインフラ構築です。
Tasting NoteのインフラはAWS環境をTerraformで構築しています。

AWSは料金が割高なので、自作サービスには敬遠されがちですが、前から興味があり、また、IaCにも興味があったのでこの機会に頑張ってみようと採用しました。

#### インフラ構成図
<img width="500" alt="infrastructure map" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/930395/fbb056cb-e373-3096-2e3d-921f21241641.png">

#### インフラをコードで管理するメリット
- 再利用が可能になる
- 高速に構築・変更が行える
- コードレビューを行うことでミスなく構築・変更が行える

実装をしてみて一番強く感じたメリットはやはり構築の速さです。

今回筆者はステージング環境をマネジメントコンソールから作成し、本番環境をTerraformで構築するという手順を取りました。
いきなりTerraformで本番環境を構築するのはハードルが高いと感じたためです。
その過程でマネジメントコンソールからの構築よりもTerraformでの構築の方が圧倒的にスピードが速いことを体感しました。

コストの観点から本番環境構築後にステージング環境を手作業で削除しましたが、これにも少なからず時間がかかり、また、漏れなく不要なリソースを削除することに多少なりともストレスを感じました。
Terraformでリソースを管理していれば不要になったリソースの削除もコマンド1つで済むので、こういったストレスからも解放されます。

また、ステージング環境を再度構築したいと思った場合は本番環境を再利用することであっという間に環境が構築できてしまいます。

#### インフラ構築において最も大事だと思うこと
インフラ構築で最も大事なことは**設計**ではないでしょうか。

インフラをコード化する作業はテストコードを書くことに似ています。
インフラ構成をドキュメントとして残す作業なので、設計が固まっていないと手が動きません。

この点はテスト駆動開発をする際にある程度の設計が固まっていないとテストが書けない点と似ていると感じました。

また、Terraformではリソースの依存関係があり、これを把握していないとリソースが構築できません。
設計ができている状態であればそれぞれのリソースの依存関係も把握できている状態なので詰まることなく実装を進められるはずです。

### FBC生の自作サービスリポジトリを見る
自分と似通った技術スタックを採用しているサービスのリポジトリを確認することで、実装のイメージをもつことができたり、便利なnpmを発見できたりと、とても有益な情報を得ることができました。

仕事の際はオープンソースや他の人のコードを読む機会が多いと聞くので、人のコードを読むことに少しでもなれることができたのは良かったと思います。

## 開発中に苦労したこと

### フロントエンドのビルド時間がとにかく遅い
create-react-appはビルドにとても時間がかかるので開発中のストレスが大きかったです。
また、今回は開発環境にDockerを使用しており、バックエンドとの連携を行う場合はdocker-composeで複数コンテナを起動する必要があったため、CPUへの負荷がさらに掛かり最悪でした...。
サーバー起動後にコードを変更した場合も、変更が反映されるまでの時間がとにかく遅く、開発体験はあまりよくなかったように思います。

開発後半にViteの存在を知りましたが移行するにはハードルが高く、今回は諦めてしまいました。

後述の「開発中にやっておけばよかったと思うこと」でも述べておりますが、技術調査を事前に行なっていれば防げた問題なので技術選定時はその時に流行っているものを一通り確認するなど、調査を怠らないようにしたいです。

### コンポーネントの単体テストの数がものすごかった...
今回の開発はまずは動くものをつくって最後にテストを書く、テストラストで進めました。
バックエンドはそれで全く問題なかったのですが、フロントエンドはコンポーネント、カスタムフックの量がとても多く、テストを書くことにとても根気が必要でした。

テストを書き始めた時は楽しかったのですが、何日も同じ作業となると段々と辛くなり...
モチベーション管理の観点からも1つのコンポーネントを実装する毎にテストも書いておけば良かったと反省しました。

## 開発中にやっておけば良かったと思うこと
### 技術ブログの更新
自作サービス開発では開発環境の構築や本番環境へのデプロイ、新しく使用するnpmやgemなど、何かを学びながら即実装の連続でした。
こういった新しく触れる技術については開発を一時中断してでも技術ブログにまとめておけば良かったと後悔しています。

理由は**実装を行ったその時が一番その技術に詳しくなっている状態**だと思うからです。

とは言え全くできなかったわけではなく、開発初期にまとめたものもいくつかあります。

- [React SPA 〜S3 Web hostingで環境変数を仕込む方法〜 \- Qiita](https://qiita.com/yuma_matzui/items/288814660b638749fd54)
- [Wizard形式のフォームをつくる with react\-hook\-form \- Qiita](https://qiita.com/yuma_matzui/items/4d8e7feb28b3172bd347)
- [React \+ Typescript 〜react\-hook\-formを使って超簡単にフォームvalidationを実装する〜 \- Qiita](https://qiita.com/yuma_matzui/items/72570f597e1517438572)
- [Terraform \+ AWS 〜ECSを無停止で切り替えるPublic ↔︎ Private〜 \- Qiita](https://qiita.com/yuma_matzui/items/5a6326f1f3b547651202)

アウトプットまで行って初めて知識という自分の血肉になるということをFBCでの学習を通して学んだので、今後はマメにブログや記事にまとめていきたいと思います。

### 念入りな技術調査
技術調査が不十分であったという話です。

create-react-app（以下CRA）について、ビルド時間がとても遅いと前述しましたが、CRAの開発者も将来的に非推奨になる可能性を含め、CRAの今後について下記にて触れています。

> [Replace Create React App recommendation with Vite by t3dotgg · Pull Request \#5487 · reactjs/react\.dev](https://github.com/reactjs/react.dev/pull/5487#issuecomment-1409720741)

普段からこういった技術的なトレンドにアンテナを貼っておけば、開発初期の段階でViteを導入することを検討できましたし、そもそもNext.jsを使ってしまおうという選択もできました。

もちろん調査に時間を使い過ぎるのもよくないと分かっていますが、今回の課題は調査の時間を十分に確保しなかったことより、最新技術の情報収集に対するアンテナが低かったことだと考えています。

情報収集力もプログラマーにに求められる重要なスキルの1つだと思うので、公式サイトのブログを購読したり、発信力のあるプログラマーをTwitterでフォローするなど、常に最新の情報を取得できる環境に身を置くようにします。

## サービスの改善点

### 認証周り
Tasting Noteは認証にFirebase Authenticationを採用しており、メールアドレスとパスワードでの認証を行なっているのですが、これをGoogle認証に切り替えたいと考えています。

このサービスのコンセプトが**手軽にテイスティングを記録できること**であり、登録の手間を極力減らしたいと考えたためです。

そもそも何故、Googleログインを採用していないのかというと、`iOS16.1`や`Safari16.1`など、主要なブラウザ、OSでサードパーティクッキーがブロックされる仕様になっており、セッション管理が行えず、ログイン状態が保持できないというバグが発生したためです。

> https://github.com/firebase/firebase-js-sdk/issues/6636

サードパーティークッキーのブロックについて簡単にまとめると、同一ドメインでないサイトからのクッキーを全てブロックするというものです。

解決方法については[こちら](https://firebase.google.com/docs/auth/web/third-party-storage-mitigation?hl=ja)の公式ドキュメントに明示されているのですが、サービスの仕様上、いずれも採用ができず、やむを得ずメールアドレスとパスワードでの認証を採用しました。

唯一、解決策として採用できそうなのが、アプリケーションサーバーにプロキシを設定して、特定のパスにリクエストが来たらFirebaseの認証ドメインへリクエストを転送させるという方法でした。
これであればサードパーティークッキーと判断されず、ブロックを免れることができます。
（公式ドキュメントの緩和策3に当たる。）

ですが、Tasting NoteはSPAを採用しており、S3のWebHostingを利用して動かしているため、プロキシの設定が行えませんでした。

また、バックエンドはECSを採用しており、ECSの前段にサービスのサブドメインを割り当てたALBを配置しているので、Railsが動いているTask内にNginxコンテナを用意して、特定のパスへのリクエストが来たらFirebaseの認証ドメインへリクエストを転送させるという試みもしましたが、これもうまくいきませんでした...。

開発に費やせる時間も限られていたため、今回はメールアドレスとパスワードでの認証という消極的な選択肢をとってしまいましたが、これを改善したいと考えています。

CRAではなく、Next.jsを採用していた場合はNextが動くサーバーにプロキシの設定を行えば簡単に解決ができるので、Next.jsへの移行を検討しています。

### Next.jsの導入
CRAからNext.jsへの移行をしたいと考えています。
コードの量がそこそこあるので根気が入りますが、前述のCRAと認証の課題を踏まえ、また、最近とても流行っているということも鑑みて学習後のアウトプットとして挑戦したいと思っています。

今すぐにとはいきませんが、就職活動が落ち着き、Next.jsの基礎学習が済んだら始めてみようと思います。

## さいごに
これまでサポートをしてくださった@komagataさん、 @machidaさん、FBCメンターの方々、切磋琢磨してくれたFBC生徒の皆さん、本当にありがとうございました。

不思議と途中で諦めそうになることはなく、必ずやり切るという強い思いでここまできましたが、その思いを持ち続けることができたのはひとえに心強いメンターの皆様と同じ強い思いを持つ生徒の皆さんの存在があったからだと言えます。

FBCで皆さんから学ばせていただいた集大成として自分のキャリアを活かしたサービスをリリースできたことは大きな自信になりました。

この自信をもって一人前のWEBプログラマーになれるように引き続き精進していきたいと思います。

大変長くなりましたが最後までお付き合いいただきありがとうございました。