【ポートフォリオ】独学/未経験が10週間でランニング促進Webアプリを作成しました。【Rails / Unicorn / nginx / AWS】


## はじめに
はじめまして、Itoiと申します！
当記事は独学・実務未経験者が、エンジニアの方からレビューを受けながらポートフォリオ（以下PF）を作った記事になります。
「未経験から、現役エンジニアのようにPFを作るには」という観点で制作を行いました。

##### 自己紹介
- 31歳、大卒の経理・物品管理事務の国家公務員 
- デジタル・アナログ問わず、技術やモノ作りが大好き
- 独学で業務の自動化プログラムを３つ（VBA）、プライベートで株価スクレイピングプログラム（Python）、それを元に株選定を行うプログラム（VBA。実際に資産運用中）を作成
- 「モノを作る仕事をしたい」と思い立ち、転職活動のためのポートフォリオ作成を始める

今回紹介するPFの作成期間は10週間（2022年2月〜4月中旬）です。

### 目次
1. [作成PF紹介](#作成pf紹介)
2. [使用技術](#使用技術)
3. [技術選定理由](#技術選定理由)
4. [PF作成スケジュール](#pf作成スケジュール)
5. [振り返り](#振り返り)
6. [終わりに](#終わりに)

## 作成PF紹介

### Virtual Map Runner
ランニング促進アプリです。
https://chizu-aruko.com(閉鎖)

GitHubリポジトリ
(閉鎖)

スクリーンショット
![スクリーンショット 2022-04-20 8.37.59.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2633406/ee4b66ac-0412-7a51-7071-496886d87bff.png)

![動作gif.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2633406/fc042589-af6e-e4c2-3e9c-d6cfbed5f47d.gif)



##### 動作
- ブラウザでGoogle Mapが開きます。
- Googleでサインインすると、ユーザーのGoogle Fitから「今まで移動してきた総距離」を取得します。
- ３つのルートの中からひとつ選ぶと、総距離の長さ分だけそのルートが強調されます。 未到達のルートはグレーで表示されます。


##### なぜ作ったのか
PF作成にあたって「誰かの課題を解決するものを作ろう」と決めました。友人に困っていることはないかヒアリングして出てきたものが「ランニングがマンネリ化してきた」というもので、「こんなアプリはどうかな？」と提案したところ「ぜひ使ってみたい！」と言ってもらえたので、作成に至りました。

##### 誰のどんな課題を解決するのか
飽き始めたランナーに新たな目標を提供します。

「ランニングアプリを使ってランニングが習慣化した。でも毎回同じような結果しか表示されなくて、マンネリ化してきた…」
→このアプリで新しい目標を提供することで、新たなモチベーションにしてもらいます。

## 使用技術
* フロントエンド
    * HTML/CSS
    * JavaScript
    * Ruby on Rails 5.2.6（テスト込）
    * ESLint/Prettier（コード解析ツール）
* バックエンド
    * Ruby 2.6.9
    * Ruby on Rails 5.2.6（テスト込）
    * Rubocop（コード解析ツール）
    * Google API
        * Maps JavaScript API
        * Directions API
        * Fitness API
* インフラ・開発環境
    * AWS（VPC, EC2, RDS, Route53, ELB）

#### インフラ構成図
最小規模のサービスとしてインフラを構築しました。Heroku等は便利ですが、きちんとインフラを扱う経験を得るためにAWSにしました。（技術選定については後述）
![インフラ構成図.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2633406/cc448a2c-b7be-6231-5454-6175f994a2c9.png)

#### DB設計
扱うデータは少なく、相関なしのごくシンプルなものです。
![ER図.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2633406/08f8c2f3-5373-afcc-4fe6-2f1d712d8f37.png)


## 技術選定理由
<b>技術選定する上で最重要な要素</b>
- 迅速に組み上げるための情報ソースの多さ

<b>完成しなければ何もないのと同じ</b>です。Web開発は初めてだったため、できる限り参考にできる情報源が多いものを選びました。

#### フレームワーク： Ruby on Rails
役割：開発用フレームワーク
他選択肢：Laravel, Django, Vue.js＋Rails等
採用理由：
- 日本語ドキュメントが豊富
- Railsは直前にProgateを一周していたため他FWより馴染みがあった

#### インフラ： AWS
役割：今後の運用を含めたデプロイ先
他選択肢：Heroku, GCP, オンプレミス
採用理由：
- Herokuはインフラ知識が付きにくい
- オンプレミスは初期コストが高すぎる
- GCPは実装例が少なく、参考にできるQiita記事数はAWSの方が豊富


## PF作成スケジュール
スケジュールは１週間単位でタスクを区切りました。

### １週目　PFテーマ決め

#### 目的
- エンジニアとして解決できる課題の発見する
エンジニアとは、技術で誰かの課題を解決する職業だと考えているので、このPFでもそれを体現しようと考えました。
#### 実行したこと
- 知人にヒアリング
10名ほどの知人に「困ったことはないか」をヒアリングしてテーマを決定しました。
ヒアリングするときに気づいたテクニックですが、いきなり「困ったことはないですか」と聞かれても意外と思いつかないものです。そういうときは状況を絞ると思いつきやすいです。
　・「仕事で解決したい課題はなんですか？」
　・「趣味で『この作業めんどくさいな』と思っていることありますか？」
こうした状況を限定した質問にすると、結構課題が出てきました。

### ２週目　設計
#### 目的
- 何を作るかを定める
どんなアプリを作るかは決めましたが、何を使ってどう作っていくかという課題があります。何も決めずに取り掛かると、間違いなく余計な作業をしてしまい、いたずらに制作期間が延びます。目的をはっきりさせ、それを防ぐものが設計だと考えています。

#### 実行したこと
- 参考書を元に設計する
2週目末尾の参考書にならって下記のものを設計として準備することで、アプリのイメージ像を明確にしました。
    * 機能要件
    * 非機能要件
    * 業務フロー図
    * 画面遷移図
    * ワイヤーフレーム
    * テーブル定義書
    * システム構成図

##### 機能要件
目的：利用者に対してどんな機能をつけるか明確にする
- ユーザー
  - 「Googleでサインイン」機能でログインできる
  - 地図が見られる
  - ヘルスケア(Google Fit)情報を渡すと、地図に仮想ルート上の軌跡が自動で作られる
  - Map画面から直感的に操作できる
  - 仮想ルートを選択できる

- 管理者  運用/保守
  - 仮想ルートを追加できる
  - Google Maps APIの利用回数を抑え、維持費を抑える

##### 非機能要件
目的：上記機能要件以外の要件を明確にする
- 独自ドメインを利用する
- WebサービスをHTTPS化する
- データ漏洩がない（自分以外のユーザーが自分のデータにアクセスできない）
- CI/CDを組み込み、テスト/デプロイを自動化する（執筆時現在、実装中）

##### 業務フロー図
目的：動作を明確にする
初めはこの3倍くらいの処理がありましたが、コア機能に絞るためにどんどん削ぎ落としてこの形になりました。
![VMRフロー.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2633406/bf6fdddc-f7db-2c8f-f7e5-d8ef1c71a23e.png)

##### 画面遷移図
目的：何の画面を作る必要があるか明確にする
![VMR画面遷移図.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2633406/a59d0d07-ac65-2162-2ce7-af7ae12409a2.png)

##### ワイヤーフレーム
目的：各画面ごとにどこに何を置くかということを決める＋何のデータが必要かを知る
![VMRワイヤーフレームトップ.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2633406/7b193837-aeb5-661a-fe4f-a8070fc8d68e.png)

##### テーブル定義書
目的：データベースに何を保存するか定義する
![スクリーンショット 2022-04-21 11.49.34.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2633406/f7621474-f893-ef41-76e4-41ccfcc67aa6.png)

![スクリーンショット 2022-04-21 11.49.05.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2633406/a9e66e14-8b38-f94d-c519-29fef11c6de5.png)

##### システム構成図
目的：どの部分で何の技術が必要か明確にする
![システム構成図.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2633406/5e02f3c9-f58e-8d82-7521-38d3b0d2b3fb.png)

参考にした本
はじめよう! プロセス設計 ~要件定義のその前に
https://www.amazon.co.jp/dp/4774185922/ref=cm_sw_em_r_mt_dp_CEHBP07QCDSMXWHCDEG4
はじめよう! 要件定義 ~ビギナーからベテランまで
https://www.amazon.co.jp/dp/4774172286/ref=cm_sw_em_r_mt_dp_171RR3MGBTZ4GKJGQG2K?_encoding=UTF8&psc=1

### ３・４週目　モックアップ作成
#### 目的
- コア機能が動作する状態まで完成させ、インフラに載せられるようにする
設計が終わってコードを書き始めました。このときの課題は、限られた時間で成果を出すことでした。
そのために教わったことがスケジュール管理とエラーの解消手順でした。

    - スケジュール管理
repsonaというガントチャートアプリで管理しました。
「闇雲にコードを書き続けて期限内に終わるか終わらないか感覚で判断する」というのでは今後の作業を計画的に進められなくなります。1日単位で何をするのかを明確にすることで、スケジュールに頭のリソースを割かずに済み、目の前のタスクに打ち込めました。
ちなみに、この週は作業量を見誤って何度もガントチャートを修正しました。しかしその甲斐あって、副次的に自分のできる作業量を見積もれるようになりました。

    - エラーの解消手順
（これは5週目に教わったことですが、ここに書くのが流れとして自然なので先に記載します）
これまでの制作では、エラーに当たるとその文をすぐググり、対処療法的に解決していました。この方法をエンジニアの方に伝えると「それでは技術力が上がらないし時間が無駄になる」と教わりました。
そしてエラー解決の手順として下記のように教わりました。
　　1. 何をしたいか明確にする
　　2. エラー箇所を特定する
　　3. エラー原因を特定する
　　4. 仮説を列挙し、一件ずつ検証する
　　5. それで分からなければ質問する
最後の質問をする際の心構えについて、今までは「相手の時間を奪うのが申し訳ない」と感じていました。しかし、「1番の目的は<b>"成果を出すこと"</b>。その萎縮は成果を出すことに意識がいっておらず、結果成果も出せない」と言われ、大きな衝撃を受けました。
相手に(回答コストを下げるよう配慮した上でも)迷惑だとか、できない奴だと思われるのが嫌だとか、全て自分で解決したいというプライドとか、そういうものよりも成果を出すことが大事だと理解しました。

#### 実行したこと
- 下記コア機能のみ実装
スケジュールやエラー解消手順に従いつつ、限られた時間で設計を元に実装しました。
    * マップページの作成
    * DBの作成
    * Fitness APIから距離データを取得
    * Direction APIで経路検索
    * 距離の長さ分、ルートを色付けする機能の実装

### ５・６週目　インフラ構築
#### 目的
- インフラを構築し、アプリをデプロイする
アプリのコア機能はできたので、インフラを構築してデプロイします。過去に作成してきたプログラムはサーバーなどを置かない一回きりで動けばいいものばかりだったので、インフラは未知の領域でした。
未知の技術を取り入れる際気をつけたのは、技術をきちんと理解することです。
HTTPやDNSの仕組み、Webサーバーの仕組みを学ぶことから始めました。その基礎知識を身につけた上で、AWSの各サービスが何を解決するサービスなのか学んでいきました。
インフラ・AWSを学ぶ上で非常に役に立ったのがUdemyの講座でした。参考にした講座は、そもそもインフラとは何か、AWSとは何か、そして各サービスが何をするものなのかなど、背景をしっかりと説明してくれているので、基礎知識を得ながらインフラ構築を学べました。

参考
AWS：ゼロから実践するAmazon Web Services。手を動かしながらインフラの基礎を習得
https://www.udemy.com/course/aws-and-infra/

#### 実行したこと
- インフラ構成図を作成しAWSにデプロイ
- 独自ドメイン取得、https化

### ７・８週目　完成まで

#### 目的
- 人に見せるPFとして完成させる
7週目時点でPFをレビューしてもらいましたが、非常にたくさんのコメントをもらいました。一部抜粋します。
    - コードに関して
        - インデントや改行が無駄に多すぎる
        - 不要なコメントアウトが多すぎる
        - デバッガーpry-byebugのbinding.pryがコメントアウトで残っている（デプロイでは絶対消す）
        - gem pry-byebugはproduct環境に入れない
        - 可読性が低い
    - サービスに関して
        - ファーストビューでどんなアプリか分からない
        - 使い方も分からない
        - トップページがダサすぎる（ターゲットを意識しておらず、結果としてかなり高年齢向けに見えた）

コード部分の課題については、とにかく改行・コメントアウトを消しました。そして命名について参考書から学び、変数と関数を命名し直し、関数を小分けにしてリファクタリングしました。

参考
（命名について参考にしたもの）
WEB+DB PRESS VOL.110
https://www.amazon.co.jp/dp/B07QXHLSJZ

サービス部分の課題についての対処法は「模倣する」ということでした。
既存のサービスからデザイン、HTML&CSSを参考にしました。実装が難しすぎるものが多いですが、配色と配置についてはシンプルなサイトを参考にできました。

参考
SANKOU!　Webデザイン制作の参考になる国内のステキなサイト集
https://sankoudesign.com/

#### 実行したこと

- 主要機能に付随する下記機能を追加
    * トップページの作成
    * アプリ説明、利用規約、プライバシーポリシーの作成
    * マップページにUIを追加
    * リファクタリング
        * HTMLファイルに書いていたJavaScriptを.jsファイルに分離
        * からまったJavaScriptを機能ごとに分離
        * 何をする関数かひと目でわかるように命名し直し

### ９・10週目　ブラッシュアップ・テスト

#### 目的
- サービスとして完成させる
機能を充実させ、テスト仕様書を作成し、テストを作成しました。
テストがなければリリース後に思わぬ事故が起きるかもしれません。ページごとに正常な動作、異常な動作を書き出し、全てチェックしていきました。一部はRailsチュートリアルを参考にテストコードを作成しました。
![スクリーンショット 2022-04-22 13.28.42.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2633406/4143fb28-7bb7-7fee-025a-7643df24e3b0.png)


#### 実行したこと

* 管理者のためのDirection APIの利用料金抑制機能の実装
* ユーザーが選択できるルートを追加
* マップページのUI刷新
* テストの作成、実施


## 振り返り

###### 命名の重要さに気づく
コードが増えるにつれて「あれ？どこに書けばいいんだ？」とコードを読み直す時間がどんどん増えてしまっていました。それを解決したのがリファクタリングと命名でした。
例えば関数が
```javascript
function put_start_marker(34.60275,135.00774){...
```
こうなら、「スタートマーカーを置く関数だ」とすぐ分かります。
コードを書き始めるときも、命名によって「何をするか」が明確なら「何を出力するか」という目的もはっきりし、余計な機能も付けなくなります。
機能を小分けにリファクタリングし、しっかりと命名することで、開発速度は2倍以上になったと思います。

###### 作成順序
サーバーを設置するwebアプリ制作は初めてだったので、目の前に出てきた課題をどんどんこなしていくという過程になってしまいました。
かなり出来上がってからインフラ構築したり、CI/CDを導入しようとしたり、テストを書いたりしましたが、作業コストが高くつきました。
次のアプリはテスト、CI/CD、インフラ構築を可能な限り早く済ませようと考えています。

## 終わりに
週の終わりごとにエンジニアの方からPFのレビューをもらっていました。その方から学んだことは「一番大事なことを見失わないこと」「終わりから逆算すること」「期間内に絶対に成果を出すこと」など、たくさんありました。

実は、5週目インフラ構築時点で、AWS CodeDeployでCI/CDを導入しようとして失敗しています。どうしてもエラーが解消できませんでした。
このとき私は「途中で投げ出して他の技術に乗り換えるような奴は、現場でも同じことをして逃げる」と考えていて、同じエラーに3日間取られていました。
そしてエンジニアさんにレビューを受ける際のついでに、ようやく質問しました。（今ではこれは遅すぎると理解しています）
そのときの回答の一言目が「Itoiさんにとって一番大事なことはなんですか？」というものでした。
「一番大切なことは『PFの完成』では？CI/CDはあくまで補助。そしてCI/CDを絶対実装したいのなら『途中で投げ出し〜』なんて気にせず、別技術の利用も視野に入れた方がいいのでは」と教えてもらいました。

この経験があってから「一番大事なことを絶対に守る」ということを徹底して、余計なことをしなくなり、かなりコミット量が増えました。

これから転職活動を始めますが、PF作りと同様に重要なポイントをしっかり押さえてコミット量を増やそうと思います。
読んでいただきありがとうございました！