【ポートフォリオ】React × Laravel でポートフォリオを制作した時に考えたこと

![cover.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/628616/f0b89ff0-5411-0e82-29bd-928e5cab7ce2.png)

## はじめに
React / TypeScript / Laravel で SPA のポートフォリオを作成した時に考えたことや一連の流れを全てまとめました。
私自身も、Qiita の多くのポートフォリオ関連の記事を参考にさせていただいたので、この投稿もこれから学習を開始したり、ポートフォリオを作ろうとされている方のお役に立てれば幸いです。

## 前提
- 当方、全くの未経験からではなく WEB 制作のキャリアがそれなりにあり、HTML / CSS / JS は不自由なく書ける段階からのスタートです。（Reactやバックエンドやデータベースは未経験からのスタートです。）
- 色々な考え方があるかと思いますが、あくまでポートフォリオとして作成したものとなります。
- ここでのポートフォリオとは「自分の作品を集めたサイト」ではなく、あくまで「一つの作品をポートフォリオと呼んでいる」ものになります。   
- 私自身、カリキュラムなど何も無く「次に何をやるべきか」を常に考えながら進めましたので、決してここに記載している方法が「正しい手順」ではないということは自覚しております。

上記ご了承いただき、Qiita 初投稿となりますので是非お手柔らかにご覧いただければ幸いです。

## URL
すみませんが、公開URLは後日記載とさせてください。
[Git リポジトリ](https://github.com/kentsunekawa/rodoma-frontend)

## 画面（公開時）
ページが重くなるので最低限、イメージが掴める程度のものですが。
![a923z-6dn9z (1).gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/628616/df16535c-7352-92b6-bc50-ac21087aef46.gif)

## 本題

### 企画
#### コンセプトと背景

コンセプトはアプリケーションを開発する上で最も大切な「目的」です。
今後、数週間から数ヶ月、開発してデプロイするまで（あるいはその先もずっと）このコンセプトを叶えるためにコードを書いて開発することになりますので、最後まで自分が向き合えるものをしっかり納得がいくまで固めました。
特に意識したことは以下の3点です。

- オリジナルであること
- 課題解決型であること
- ユーザーにとってメリットがあること

これに「マネタイズできる可能性があること」をプラスしたいところですが、ハードルがかなり高くなるかと思いました。

<details><summary>コンセプトと背景を見る</summary><div>

```
【コンセプト】
挑戦する人を応援する、学習ロードマップのシェアサービス

【背景】
人生100年時代。
新卒で入社した会社や、20代で培った知識だけで定年まで逃げ切るような時代じゃない。
30代、40代、ときには50代で新しいことに挑戦したい（しなければいけない）ケースが増えてくることが予想される。

書店にいけば一つの分野の書籍が何十冊と並んでいるし、学習動画はネットでは数千円程度、youtube では無料で見ることができる。
しかし教材がいくら溢れていても、何を、どのように、どういう順番で学ぶべきか、あるいは何を捨てるべきかを判断し、
適切な目的達成までのロードマップを作れる人はどれくらいだろう。
「点」での学習がこれほどまでにハードルが低くなったのに、それらを繋ぎ合わせて「線」にする方法はまだまだ情報不足な状態だ。

もっと気軽に先輩たちの歩んできた道のりや、おすすめの学習方法にアクセスができて、
自分に最適な学習プランを立てることができたなら、もっと多くの人がより速くスムーズに新しい分野への挑戦を成功させられるに違いない。
```

</div></details>

### 設計

コンセプトから逆算して、必要な機能を洗い出しました。

#### 機能一覧

| 分類                 | 機能                                                                                 |
| -------------------- | -------------------------------------------------------------------- |
| ユーザー             | 新規登録、サインイン、サインアウト、オートサインイン、ユーザー情報編集、メール認証、パスワードリセット |
| 投稿                 | 閲覧、新規作成、保存、公開、限定公開、アイキャッチ画像設定                           |
| 投稿検索・ソート     | キーワードで検索、カテゴリで検索、ソート（Like 数 / Mark 数 / 作成日）               |
| ユーザー検索・ソート | キーワードで検索、カテゴリで検索、ソート（フォロワー数 / 登録日）                    |
| コメント             | コメント作成、コメント削除                                                           |
| Like（ライク）       | 良いと思った投稿に Like する、Like の解除                                            |
| Mark（マーク）       | 後で見たい投稿に Mark する、Mark の解除                                              |
| フォロー             | フォロー、フォロー解除                                                               |
| その他               | 無限スクロール、ライトモード / ダークモード、新規登録時の初期設定サジェスト                                          |

#### ER図
機能が決まれば、それを実現できるデータベースの設計です。
書籍で調べながら人生初の ER図を Draw.io で作成しました。（見にくくて恐縮ですが・・・）
簡単な WEB アプリケーションを作る上で、必要最低限というところでしょうか。
![ER.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/628616/1aa7de54-f046-5602-91fa-527c2b64e556.png)

#### その他ドキュメント類

機能をコードに落とし込んでいくにあたり、決めなければいけないことを文章や表にしてGoogleスプレッドシートにまとめていきました。地味な作業ではありますが、ここであらゆることを明文化することでコーディングの段階がスムーズに進みます。ここではその主なものと一部抜粋を記載します。

##### ルート一覧（API）
必要なAPIのエンドポイントのパスと、対応するメソッドと必要なパラメータ、またそれぞれに対するバックエンドでの挙動を洗い出しました。
![rootingTable-api.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/628616/4a182d60-3a17-3290-5204-d5326226f3b0.jpeg)

##### ルート一覧（フロント）
フロントのパスと、それぞれの画面で叩くAPIや、レスポンスによって発火させる挙動などを洗い出しました。
![rootingTable-front.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/628616/73543530-70a9-ebb6-8286-3deb92f3a899.jpeg)

##### 単語定義表
地味なことですが、アプリケーション内で使う単語を統一するために単語定義表を作成しました。例えば「サインイン」なのか「ログイン」なのかと言ったことを明文化することで、一貫したUIを提供できますしコーディングの段階でも命名に悩まずに済みます。
![tangoteigi.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/628616/66c6f24f-1765-2512-f3fd-3244b169ef26.jpeg)


### デザイン
まずロゴやカラーシステムといったベーシックデザインを行い、サービスの温度感やテンションやトンマナを確定しました。
その後、Adobe XD を用いて、ワイヤーフレームと UI デザインを行いました。
#### ベーシックデザイン

<details><summary>ベーシックデザインを見る</summary><div>

![basicDesign.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/628616/1ccca1b0-6c4a-775f-814b-61511a436a06.jpeg)
記事用にかなり簡潔にまとめたものです。
ここで設定したカラーやグラデーションを、styled-components でテーマカラーとして設定したり CSS の mixin として定義し、コード内で使い回せるようにします。

</div></details>

#### ワイヤーフレーム
ワイヤーフレームを書く意味は、デザインの下書きだけではなく画面設計や画面遷移、導線設計などの意味合いがあることに気づかされました。
またこの段階で必要なページとそのURLを全て洗い出すことができました。

<details><summary>ワイヤーフレームを見る</summary><div>

![グループ 198@2x.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/628616/b204bf0e-fe30-01a2-bd47-2f7b3ce75b6e.jpeg)

</div></details>

#### UI デザイン
コンポーネントを意識してパーツ単位でデザインし、XD のコンポーネント機能で管理しました。
そうすることで、フロントのコーディングをする段階でそのまま React のコンポーネントに落とし込んでいく機械的な作業となりスムーズでした。

<details><summary>UI デザインを見る</summary><div>

##### 画面単位
![グループ 199@2x.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/628616/371d7d74-4202-ba82-f4fa-8ba64c4ebbf9.jpeg)
##### 部品単位
![グループ 200@2x.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/628616/bc6979f7-fa64-7263-1129-09a3737aec75.jpeg)

ここで作成した部品を React のコンポーネントとして定義していきました。

</div></details>

### 開発

##### SPA + API
サービスのコンセプトにある通り新しいことに挑戦する人には、画面遷移やサーバーからのレスポンス待ちといったストレスが少しでも少ない利用体験を提供する必要性があることから、フロントは SPA で構築。 それに伴ってバックエンドは、フロントからのリクエストに対して必要なだけの情報を随時返す API サーバーとして構築しました。

#### フロントエンド
メインの言語は、API と連携することでデータの受け渡しが多く発生することから型宣言による安全性という恩恵を受ける為に TypeScript を、また ライブラリは TypeScript との相性という面から Vue.js ではなく React を採用しました。
スタイリングに関しては 既存の UI ライブラリは導入せず、styled-components でオリジナルのコンポーネントを開発しました。
これは、求められるデザインの要件上、既存の UI ライブラリ（Material UI など）では結局大きなカスタマイズをする必要があり、オリジナルで開発した方が開発にも維持にもコストがかからないと判断したためです。

使用技術一覧は下記の通りです。

|分類|名称|
|--------------------|----------------------|
|言語                 | TypeScript 4.1.2|
|ライブラリ           | React 17.0.1           |
|状態管理             | Redux（Redux Toolkit） |
|スタイリング         | styled-components      |
|http クライアント    | axios                  |
|アニメーション       | GSAP                   |
|コンポーネント管理   | Storybook              |
|バリデーション       | Vest                   |
| テストフレームワーク | Jest                   |
| リンター          | ESlint                 |
| コードフォーマッター | Prettier               |

##### Storybook

コンポーネントは Storybook で管理しました。
Storybook はサンドボックス環境の中でコンポーネントがどのような挙動をするかをテストできる便利なツールです。
![storybook.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/628616/7bbd9120-2975-ca8c-4ead-a371d5c77a38.jpeg)

##### テスト（Jest）

テストはテスティングフレームワークである Jest を用いて、関数のテスト、コンポーネントテスト（コンポーネントに与える props によって正しくレンダリングされているか）、スナップショットテストを行いました。
が、WEB 開発のテストについて調べれば調べるほど奥が深く「理想的なテスト」を構築することは、その道のかなりの経験が必要だと感じました。

#### バックエンド
初学者がバックエンドを構築する際の選択肢としては、PHP、Ruby、Python などが挙げられるかと思いますが、開発期間と開発開始時点での理解度とそこからの学習コストなどを鑑みて、PHP を採用しました。
フレームワークにおいては PHP のフレームワークの中でも Laravel が最もシェア率が高く、ドキュメントの豊富さと将来性を考慮し採用しました。  
使用技術一覧は下記の通りです。

| 分類           | 名称         |
| -------------- | ------------ |
| 言語           | PHP 7.4.15   |
| フレームワーク | Laravel 6.20 |
| データベース   | MySQL 8.0.23 |

#### インフラストラクチャー

##### ネットワーク構成図
![network.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/628616/91ac8956-4a7c-8d14-cbd9-9ca988d4e460.jpeg)

ローカル開発環境は Docker Compose で、本番環境は Heroku を採用しました。
また、GitHub Actions を利用し、main ブランチに push されれば自動でテストが走り問題なければ heroku にデプロイされる構成にしました。
画像配信は AWS S3 を利用しております。

使用技術一覧は下記の通りです。

| 分類                     | 名称                    |
| ------------------------ | ----------------------- |
| 本番環境                 | Heroku                  |
| コンテナ（開発環境のみ） | Docker / Docker Compose |
| バージョン管理           | Git / GitHub            |
| CI/CD                    | GitHub Actions          |
| 画像配信                 | AWS S3                  |
| リバースプロキシ         | Cloudflare              |


## さいごに（感想になってしまい大変恐縮ですが。）

以上が、私がポートフォリオを制作する上で行った一連の流れです。

本当に多くの気付きや学びがあったのですが、何より興味深かった点は、
コンセプトという極めて「ふわっ」としたものが、設計やデザインや開発というフローを経て最終的にはデータベースのデータという文字や数字にまで落とし込まれるという点です。逆に言えば、データベースに格納されているデータがプログラムを経て最終的に UX としてユーザーに届いているという点です。

ポートフォリオ制作においては、
どの分野にどこまで力を入れるかは人それぞれかと思いますが、
この記事が一人でもこれからポートフォリオを作ろうとされている方の参考になれば幸いです。

最後まで読んでいただきありがとうございました。
（間違っている点や、今後もっとこうした方がいいというご指摘いただけましたら幸いです。）