未経験・独学でポートフォリオを作成しました【Laravel/AWS(ECS)/Docker/Nginx】

## 0. はじめに
未経験からエンジニア転職をするため、仕事の傍ら独学でポートフォリオ（Webアプリケーション）を作成しました。

本記事では、作成したアプリの紹介の他、リリースまでの経緯や学習フローについても触れられたらと思います。

~~アプリのURL: https://onedari-app.com~~
(停止中です)

GitHub: https://github.com/mittsu0/portfolio

## 1. 簡単な自己紹介

* 25歳、社会人3年目
* 2022年3月から本格的に学習開始（未経験・独学）
* 趣味はアニメと漫画とスノボ
* 最近ジムサボりがちなので頑張りたい

## 2. アプリの紹介
特定の地域において、ユーザーが欲しい物やサービスを共有するアプリです。
サービス名は「オネダリ」とし、コンセプトは「地域の需要を可視化する」としました。

### 2.1. 概要

#### 投稿一覧画面（ホーム画面）

![index.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1344095/b80a6461-5d2a-d894-6b7a-6d7f895d2168.png)

![index_popularity.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1344095/97c807f7-65f6-803d-b29c-408fb8c893c5.png)

![index.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1344095/94f5e853-4343-d4ba-56fc-b06a9dfd1a91.gif)

* ユーザーの投稿を一覧表示します。
* ヘッダーナビの検索ボタンから投稿の絞り込みができます。
（絞り込み条件：キーワード、エリア、カテゴリ）
* 新着順、もしくは人気順(Good順)で投稿の並べ替えができます。

#### 新規投稿画面

![create_new_post.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1344095/f99eb422-6d91-6563-a7fb-87bae5618e83.png)

![new_post.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1344095/e427e29d-1fa9-e3f7-6b66-ef00226799f4.png)

![new_post.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1344095/29f31725-0d11-a4ab-7a19-10b2f0081f96.gif)

* ヘッダーナビの投稿ボタンから新規投稿画面に移動できます。
* タイトル、エリア、カテゴリ、本文、ID表示の有無を選択して投稿します。

#### 投稿詳細画面

![post_details_good.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1344095/aaf787e3-b77d-561d-85ab-4bba7fb00f75.gif)

![post_details_comment.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1344095/c77aa49f-e3ae-522c-3ab2-3c95eb2ae5f7.gif)

* 一覧画面で個々の投稿をクリックすると詳細画面に移動します。
* 投稿に対してGoodやBadをつけたり、コメントを投稿したりすることができます。


### 2.2. 機能一覧
* 投稿一覧表示
* 投稿絞り込み
* 投稿並べ替え
* 投稿一覧のページネーション
* 新規投稿
* 投稿詳細表示
* 投稿へのGood / Bad
* 投稿へのコメント
* お問い合わせフォーム

### 2.3. 作成した背景
本アプリを作成した背景には、地方と都会両方の暮らしを経て感じた「地方と都会でのモノやサービスの多様性の差」があります。

私は地方で生まれ育ち、地方の大学へ進学しました。
大学を卒業後就職した企業では、東京での研修を経て初配属で地方勤務となり、その後の２度目の異動でも地方への配属を告げられ現在に至ります。

東京近郊で過ごしたのは研修期間の2ヶ月間のみですが、その僅かな期間だけでも、都会でのモノやサービスの豊富さには驚きました。

* 地方にはない様々なお店や施設がある
* 基本的に近場で事足りる
* 毎週のように何かしらイベントが開催されている
* デリバリーサービスがすごい（中本の蒙古タンメンをUbereatsしたときは感動しました）　など

もちろん地方には地方の良さがありますが、物足りなさや不便さを感じる瞬間があることも事実です。そして、同じように感じている人が少なからずいるのではないかと思い、アプリの着想を得ました。

本アプリでは、地域ごとに欲しいモノやサービスを投稿したり、他の人の投稿に対してGoodやBadをつけることができます。これにより、「どこで」「どれだけの人が」「どんなものを」望んでいるのかを可視化できると考えています。

もし、ある投稿に対して多くの人が共感し、それが行政や企業など各所の目に触れれば、地方の街づくりの一助になるのではないかと考えました。

## 3. 使用した技術

### 3.1. フロントエンド
* HTML
* CSS
* Bootstrap 5.1.3
* Vue.js 2.6.14

### 3.2. バックエンド
* PHP 8.0.23
* Laravel 8.83.23
* MYSQL 8.0.28

### 3.3. 開発環境
* Docker 20.10.17 / Docker Compose 2.7.0
    * Nginxコンテナ
    * Appコンテナ
        * PHP
        * laravel
        * vue.js
    * DBコンテナ
        * MYSQL
    * MinIOコンテナ（画像を保存するためのストレージ）

### 3.4. 本番環境
* AWS: ECS(Fargate), RDS, Route 53, ALB, ACM, S3, VPC, IAM 

### 3.5. 使用ツール
* ソースコード管理: Git / GitHub
* IDE: VS Code
* ER図, インフラ構成図作成: Draw.io

### 3.6. DB設計

ユーザー登録機能がないのでusersテーブルはありません。その代わりに、各テーブルにuidカラムをもたせることでユーザーの紐付けを行っています。uidは、クライントのIPアドレスと日付等から生成しています。

![er.drawio.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1344095/995f2d19-3699-def8-a53c-4c0ad9d4eccd.png)

### 3.7. インフラ構成

開発環境でDockerを使用していたので、本番環境のAWSでもECS（Fargate）を利用し、Webサーバーとアプリケーションサーバーのコンテナを立てました。

データベースはRDS、画像保存用の外部ストレージはS3を使用しています。
ELB（ALB）はACMを利用してhttps化することと、Fargateのヘルスチェックのために使用しています。
出費がかさみそうなので負荷分散は行っていません…

![structure.drawio.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1344095/43bd12a5-0822-aa87-f782-40383fd2dec7.png)

## 4. 苦労したこと・工夫したこと

### 4.1. フロントエンド

* Vue.jsをしっかり学ぶことなく着手したので、思うようにレイアウトを実現できず苦労しました。画像をアップロードした際のプレビューの表示や、Goodボタンを押したときの色の変化など、やりたいことを都度調べて実装していきました。

* サイトのデザインを0から考える難しさを知りました。色々なサイトを見て回り、最終的には某掲示板サイトのデザインを参考にさせていただきましたが、自分でも0からレイアウトを考えられるようになりたいです。

### 4.2. バックエンド

* 本アプリは都道府県を指定して投稿を行うため、ユーザーがセキュリテイ面で不安を感じてしまう懸念がありました。そのため、メールアドレス等の入力が必要となるユーザー登録機能は省き、匿名で投稿できるようにしました。
しかし、なりすましの防止やGood数を管理するには、IDを発行するなどしてユーザーを識別する必要がありました。IDによってユーザー管理をする方法は参考資料が少なく、「どのタイミングでIDを発行するか」「どのようにIDを生成するか」など実装に時間を要しましたが、その過程で勉強になることも多かったです。最終的には、ミドルウェアやセッションを利用し、クライアントのIPアドレスや日付等からIDを生成・管理する方法を取りました。

* 一覧表示ページの絞り込み機能と並べ替え機能では、「絞り込んでから並べ替える」「並べ替えてから絞り込む」など、それぞれの結果を保持する必要がありました。
レイアウトの都合上絞り込みボタンと並べ替えボタンは離れたところに位置していたので、どのように実装するか悩みましたが、formタグのid属性・buttonタグのform属性と、セッションのフラッシュデータを用いて解決しました。

* GoodボタンとBadボタンは、「片方が押されている状態でもう片方を押すと、押されている方を取り消してから新しく押された方を反映させる」というように、GoodとBadを同時に押すことができない仕様にしました。

* N+1問題の解消、ORMのクエリの生成方法、SQLインジェクション対策（POST送信時やキーワード検索時）など、DBのパフォーマンスとセキュリティにはなるべく気をつけました。

### 4.3. 開発環境

* dockerでの開発環境の構築は、qiitaに親切なハンズオンの記事があったおかげで、他と比べると比較的苦労せずにできました。しかし、開発環境がすんなり完成したが故に、Dockerについてあまり調べなかったので、後にECSにデプロイするときに痛い目を見ました…

* 開発用と本番用でDockerイメージを使い分けるため、Dockerfileとdocker-compose.ymlファイルを2つ用意し、イメージをビルドする際にファイルを指定する方法を取りました。

* GitとGitHubを用いてソースコードを管理していましたが、開発序盤〜中盤まではうまく活用できておらず、気が向いたらコミットするような使い方をしていました。それが原因でデバッグに時間がかったこともあったので、開発後半ではGitの使い方を見直し、GitHub Flowを意識して取り組むうようにしました。

### 4.4. 本番環境

ECS Fargate上にコンテナをデプロイする際、コンテナが起動と停止を繰り返してしまう問題に直面しました。そもそもコンテナがうまく立ち上がっていないので、コンテナの中に入ってデバッグすることもできず非常に困りました…
そこで、主に次の方法で原因を探りました。

①CloudWatch Logsにコンテナのログを出力する
②awscliを利用してサービスやタスクの停止理由を確認する

その結果、
①起動コマンドのマイグレーションが失敗している
②npmのビルドコマンドが、コンテナのメモリ不足で失敗している（そもそもビルドしてからECRにプッシュすればいいので余計なことをしていました）
③ECSでコンテナの起動コマンドを指定したことで、DockerイメージのCMDを上書きしてしまい、php-fpmが起動していない

といったことがわかり、時間はかかりましたがデプロイすることができました。

## 5. 今後の課題

課題は山程ありますが、ひとまず優先的にやりたいことを記載します。

### 5.1. 基礎の学習

Linuxやネットワークについて曖昧なところが多いので、資格勉強などを通して体系的に学ぶ予定です。

### 5.2. AWS, GCP, Terraform

AWSには、今回使用したもの以外にも無数のサービスがあると思うので、AWS SAA等の資格勉強を通して体系的に学びたいと考えています。今回は学習しやすいAWSを使用しましが、ビッグデータの分析やマルチクラウド化の需要から、GCPの学習も始めたいです。Terraformにも興味があります。

### 5.3. Javascript, Vue.js

PHPやlaravelについては、動画教材や参考書を用いて勉強しましたが、Javascript及びVue.jsについては勉強する時間を取ることができませんでした。サーバーサイドだとしても、現在ほとんどのサイトで使用されているJavascriptとそのフレームワークを学ぶことは必要だと思うので、一度学習の時間を取りたいと考えています。

### 5.4. テストコード

本アプリではテストコードを実装できませんでしたが、実務では必須のスキルだと考えます。テスト駆動開発に興味があるので、教材等を用いて学習する予定です。

### 5.5. CI/CD

テストコードについて学んだ後は、CI/CDについても学習したいと考えています。AWSにデプロイする際、「ローカルでDockerイメージを更新→ECRにプッシュ→Fargateタスク定義→サービス起動」という手順がなかなか手間で、ソースコード1行の変更を反映させるのにも10分くらいかかりました…CI/CDが使えたらなあと何度も思いました。

## 6. 学習フロー及び使用教材

学習フローと使用教材をざっくり紹介します。本格的な学習は2022年の3月から始めました。自分は社会人かつ独学ですので、同じように社会人で独学されている方・これから学習を始めようとしている方の参考になれば幸いです。

### 2022年3月: Linuxコマンド, C言語

https://42tokyo.jp/

3月は、42 Tokyoというエンジニア養成期間の、Piscineという入学試験に取り組みました。試験期間は1ヶ月ほどあり、LinuxコマンドやC言語の課題に取り組みます。

Piscineでは、参加者同士で回答のレビューを行うため、進捗が周りから遅れるとどんどんやりづらくなる（進捗が早い人が何を言ってるのかわからなくなる）という特徴がありました。このように否が応でもやらなきゃいけない環境だったので、ときに睡眠を削りながら必死に勉強し、なんとかやり切ることができました(合格はできませんでしたが…)

Piscineに参加したことにより、大きく次の3つのメリットがあったかと思います。

* PCを開いて勉強することに慣れた
* 自分で調べて解決することに慣れた
* LinuxコマンドやGitの基本を学べた

ほとんど何も知らない自分が仕事と両立しながら周りについて行くのは大変でしたが、それ以上に課題を解く楽しさや解けたときの喜びが大きかったです。また、Piscineを最後までやり切れたことで、プログラミングを独学することへの自信も付きました。エンジニアに興味がある方は、お試しでPiscineに参加してみてもいいかもしれません。

### 2022年4月: 各種プログラミング言語基礎

https://prog-8.com/

4月はプログラミング学習サイトのProgateで、HTML、CSS、PHP、SQLの基礎を学びました。あまり時間をかけすぎず、大枠を掴むようなイメージで学習に取り組みました。

### 2022年5月: PHP

https://www.udemy.com/course/php7basic/

5月はUdemy等でPHPの学習をしました。このコースでは、掲示板サイトの開発を通して、フォーム処理やSQLについて学びました。

### 2022年6月: Laravel,Docker

https://www.amazon.co.jp/PHP%E3%83%95%E3%83%AC%E3%83%BC%E3%83%A0%E3%83%AF%E3%83%BC%E3%82%AFLaravel%E5%85%A5%E9%96%80-%E7%AC%AC2%E7%89%88-%E6%8E%8C%E7%94%B0-%E6%B4%A5%E8%80%B6%E4%B9%83/dp/4798060992

https://www.techpit.jp/courses/11

https://qiita.com/ucan-lab/items/56c9dc3cf2e6762672f4

6月はLaravelとDockerについて学びました。まずDockerでLaravelの環境構築を行い、その後書籍を使って基礎を学びました。Dockerでの環境構築は、上に記載のハンズオンの記事が非常に丁寧なので、そちらに沿って実施することですぐにできました。

書籍を一通り学んだ後は、TechpitでWebアプリを作りながら、Laravelでの諸機能の実装方法や、Vue.jsの使い方、Bootstrapの記法について学習しました。

### 2022年7月~9月中旬: ポートフォリオ制作

https://www.udemy.com/course/unscared_git/

https://www.udemy.com/course/aws-and-infra/

https://www.udemy.com/course/ecsfargate/

https://qiita.com/hirai-11/items/241df305a90af3ccf973

7月からはポートフォリオの作成を始めました。作業を進めていく中で必要だと思った知識（AWSやGit）も都度学習していきました。

## 7. 最後に

アプリ制作を通して、開発の難しさや楽しさの一端を感じることができました。途中何度もつまづきましたが、試行錯誤しながら１つずつ課題をクリアし、アプリをリリースできたときは大きな達成感がありました。しかし同時に、自分が作成したアプリはまだまだ実用には程遠く、自信のスキル不足を痛感しました。

今後エンジニアとして働いていくためには、数え切れないほど学ぶべきことがあるかと思います。きっとこの先苦労することが山程ありますが、徐々にスキルを高め、できることが増えていくことが楽しみでもあります。

これから転職活動を始めていく所存ですが、今回独学でここまできたことを糧に、転職後も日々勉強・成長していけるよう努めていきたいと思います。

最後までお読みいただきありがとうございました！

## 8. 追記

Webアプリ公開後、XSS攻撃を受けました。
投稿を表示する際はサニタイズを実施しているため、スクリプトの実行は防ぐことができました。
投稿は削除済みです。

![index_xss.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1344095/21ba5341-b2d1-ae23-fab8-182d0ba506cd.png)