実務案件に参加した未経験の奮闘録

## はじめに
はじめまして、現在、開発実装をするエンジニアを目指している25歳です。
日々個人で学習していたのですが、この度幸いなことに実務案件に携わらせていただくことになりました。

本記事はその過程でどのように考え、実行していったのか、その体験のアウトプットになります。
ただ内容としては、きれいなサクセスストーリーではありません。
実務に挑戦していく中で上手くいかないことも多々ありましたし、悔しいと感じる結果になった部分もあります。

そのため、もし転職までに実務経験を積んでみたいと考えておられる方に少しでも参考になれれば幸いです。

ちなみに参考までに、僕が実務案件を開始した時点でのスキルレベルは次の程度です。
・PHP、JavaScript、HTML、CSS、MySQLで簡単なCRUDアプリ（カレンダーアプリ）を作った
・フレームワーク（Laravel）を使ったことがない
・Dockerを使ったことがない
・Gitもほぼ使ったことがない 
・AWSに触れたことがない

このようなレベル感の私が案件にどのように食らいつき、壁にぶつかり、どのように成長できたのか。
ちょっとした読み物として楽しんでいただければと思います。

## 案件との出会いとチャレンジ
今回参加させていただいた案件は、開発エンジニアの仕事について調べていた時に、たまたま募集を見かけたものでした。
「面白そうだな」と思う反面、「私が参加できるのだろうか」という思いもありました。
しかし、「もし参加させていただけるならきっと今以上に成長できるに違いない」という気持ちや、以下の目的もあり、思い切って応募することにしました。

- 現時点での自分のレベルを把握したい
- 開発実装をするエンジニアになる上で、今の自分に足りないものを把握し、埋めたい
- 仕事として活動した時の、想像とのギャップを無くしたい

案件を見つけた時に、開発エンジニアの仕事について調べていた目的も、「実際の業務のことをもっと知りたい」ということだったので、これは何かの縁だと感じました。

そして、応募フォームに今の自分に書けるだけの想いを書いて送信しました。
数日後、大変ありがたいことに、「ぜひお願いしたい」ということで参加させていだくことになりました。

## 案件の概要
今回の案件は「日報の共有と蓄積ができるシステム」のAPIを開発するというものでした。
クライアントが運営するコミュニティでは、会員は日々の活動記録を「日報」としてSlackに投稿しています。
ただ、Slackの性質上、過去の投稿を遡り辛く、一部ではSpreadsheetを利用し、そこに記載してもらっており、管理がまちまちになっている状態です。
そこで今回、日報データを一元管理できる仕組みを作って欲しいという要望でした。
また、現時点で具体的な運用や展開は未定とのことで、柔軟に対応できるようにAPIとして用意して欲しいとのことでした。

これを踏まえ、以下が案件の概要になります。

- 背景
    - クライアントが運営しているコミュニティにて、会員が日々投稿する日報の管理方法を模索している

- 課題
    - 現状Slackに日報を投稿してもらっているが、アプリの性質上流れてしまう（遡って確認し辛い） 
    - Spreadsheetにも記載してもらっているが2重管理になる

- 期間
    - 要件定義～実装まで含めて2ヵ月
    
- 要求成果物
    - 日報の保存と連携ができるシステム（API）

※プロジェクトはオープンソースとしてGitHubに公開

## 要件定義
案件の背景を掴んだ後は速やかにヒアリングに入り、要件定義を行いました。
直観で「このフェーズをしっかりやっておかないと後々トラブルの元だな、、、」と感じていたため、不明瞭さを無くすべく、以下に注意して実施しました。

- システムに関係する登場人物は誰がいるか
- 「何」ができる必要があるか(must)
- 「何」ができればより良いか(better)
- 「何」が無くても問題ないか

洗い出した要件定義は以下になります。

- 機能要件
  - 任意のサービスから日報を投稿できる（少なくともSlackに対応）
  - 任意のサービスへ日報を送信できる（少なくともSpreadsheetに対応）
  - 日報をMySQLに保存できる
  - 日報の修正、削除ができる
  - 組織を作成、修正、削除できる
  - ユーザーを作成、修正、削除できる
  - 組織にユーザーを所属させることができる
  - 管理者が組織、全ユーザーの修正削除ができる

- 非機能要件
  - 費用は月2万円
  - 認証されていないユーザーは日報を投稿できない
  - 誰でも書かれている通りに実行すれば環境を構築できる
  - 機能をアップデートしたら本番環境に容易に反映できる
  - サーバが落ちた時手順書を見て復旧できる

## 技術選定&システム構成設計  
要件定義が決まったので、次は技術選定を行い、システム構成を設計しました。
ここがまず1つ目の関門でした。
と言うのも、現状注意すべき点は費用が月2万円以内であるという点のみであり、多様な選択肢から適切なものを選ぶ必要があったためです。

そこで、このフェーズでは以下のステップで取り組みました。
1. システム構成要素の洗い出し
2. 選択肢の調査、分類
3. 選択肢の絞り込み

### 1.システム構成要素の洗い出し 
まず、どのようなサービスを利用するかを決める前に、要件を実現する際に必要となる（役立つ）要素を洗い出しました。
結局、サードパーティで用意されている様々なサービスもコアとなる要素を実現する手段でしかなく、ここから始めないと手が進まないと感じたためです。

具体的には以下のような列挙をしました。

- Slack等から送信するメッセージはインターネット（web）を経由して送られてくる
- ということは、webサーバを用いることになりそう
- 加えてメッセージを処理する必要があることからAPサーバも使いそう
- また、日報データ等を保存するためのDBサーバも必要となる
- webサーバを使うということは名前解決のためのドメイン取得する必要がある
- HTTPS通信を行うための証明書を取得する必要がある
- ホストが稼働するネットワークを用意する必要がある
- アプリケーションとして実行する言語を決める必要がある
- 開発～デプロイを容易にする環境があった方が楽になりそう

このような洗い出しから整理すると以下の要素が必要になると考えました。

- WEB/AP/DBサーバ
- ネットワーク
- ドメイン
- 証明書
- コンテナ仮想化
- CI/CD
- 開発言語
- ソースコード管理

### 2.選択肢の調査、分類
次に行ったのは、選択肢の調査と分類です。
上の工程で洗い出した要素を実現するサービスは複数あります。
この中から選択するためには、何が合ってどのように分けられるか明確にした方がやりやすいと考えました。

調査の結果実現パターンは以下に分類できることが分かりました。

- オンプレミスで物理機器搬入、ラックマウントをし、その後サーバ構築をしていく
- レンタルサーバを借りてサーバ内部を1から作っていく
- パブリッククラウドで提供されているサービスを利用して構築していく

### 3.選択肢の絞り込み 
結論から言うと、「パブリッククラウド」を利用することにしました。
オンプレミスで物理機器から構築するのは費用面、時間面で非現実的ですし、レンタルサーバを借りてサーバ構築を行うパターンは、費用面はクリアできてもネットワーク面などで工数が掛かる見込みという点で除外しました。

昨今のトレンドを鑑みると、正直ここはほぼ自明なのかなと思いましたが、ただ流行っているからという理由ではなく、それを選ぶ理由は持っておいた方が良いと思いこの過程を踏みました。

また、「パブリッククラウド」というジャンルでも「Azure」「AWS」「GCP」等がありますが、今回は「費用面」と「ドキュメント面」を考慮し、「AWS」を採用することにしました。
（各ベンダーで似たような構成を取った場合を試算したところAWSが安く、またシェアNo1であることからドキュメントにも期待できると考えた次第です。）

### システム構成 
このような過程を経て、決定した主な技術選定とシステム構成図は以下になります。

- 技術一覧
![image](https://user-images.githubusercontent.com/89679815/153198758-32399c3d-a933-40c6-9a7e-866ab964cc74.png)

- システム構成図
![image](https://user-images.githubusercontent.com/89679815/152805204-4f08a3b9-d018-4630-8d2b-aa4cd084ba1c.png)

システムフローは以下になります。

- 送信元が日報APIのエンドポイントをコール
- 認証を行いクリアした場合、データ送信
- データベースに保存
- 連携先にデータを送信

ここまでの過程を資料にまとめ、クライアントと認識合わせを行い、無事ＯＫをいただくことができました。

## インフラ構築
インフラの設計図が固まったので、ここからは一つずつ構築していくフェーズになります。
このフェーズは今回の案件の中で2番目に苦労しました。（一番はまだ来ていない。。。）

と言うのも、技術選定で採用したものの多くは、役割を理解し採用したもの、触ったことがないものばかりでした。
そのため、限られた時間の中でそれぞれ仕組みを理解し、構築手順とパラメータを明確にした上で作っていく必要があり、本当に苦労しました。

着手当初からこのフェーズは大変であると予想できたため、次の優先順位で着手することにしました。
1. インフラの大枠となる要素に着手する
2. サービスのコアになる部分に着手する

このステップに分けたのはなるべく「手戻り」を減らすためです。
全体の内の大枠となる部分から作っていけば、ここはフィックスできる。そうすれば後はコア部分にだけ集中できる。
このように考えました。

### 1.インフラの大枠となる要素に着手する
まず一番の大枠になるのは何か、これはネットワークだと考えました。
今回はAWSを採用しているのでVPCをはじめとする、ネットワーク周りの学習と構築を行いました。

他の項目とも共通ですが、学習する際はなるべく1次情報から得るようにしました。
個人ブログやメディアで書かれている内容は嚙み砕いて説明されており、わかりやすいのですが、よく見ると間違っていると言ったことがあり、結局公式のドキュメントをよく見るの方が早かった経験があったためです。
個人ブログ等は最初に全体像を掴むところや具体的なイメージが欲しい時に参照する形で利用させていただきました。

これが功を奏したのか、VPC構築において、内部に配置するDBインスタンス（RDS）のネットワーク仕様を確認していると以下の記述がありました。
> DB インスタンスをホストするには、VPC は特定の要件 (2 つ以上のサブネットを保持しており、各サブネットは個別のアベイラビリティーゾーン内にあることなど) を満たす必要があります。
[引用元](https://docs.aws.amazon.com/ja_jp/AmazonRDS/latest/UserGuide/CHAP_SettingUp.html)

つまり、VPC内で複数のサブネットを用意していないとRDSは作れないようです。
また、VPC内のアベイラビリティゾーンも分けておくことを求められています。

このことを考慮し、設計したVPCが以下になります。
![Untitled (9)](https://user-images.githubusercontent.com/89679815/153084831-bf6a07ff-3d11-4b94-9515-41c94548e096.png)

次のようなポイントを意識して作成しました。

- ネットワークアドレスは少し余裕を持って/22で切る
- 各サブネット内はAWS側で取られる部分を除いても200以上のIPは確保しておく
- パブリックとプライベートを2つずつ用意する（パブリックの2つ目は将来的に拡張できるように）

このようなプロセスでRote53,ACM,ALBの構築を行った結果、この時点では以下の構成になりました。
![Untitled (7)](https://user-images.githubusercontent.com/89679815/153085739-f2781e0c-4337-48e2-aa3b-8f2cdce39940.png)

先にこの後の展開について触れておきますと、次の項目でかなり苦戦します。
その結果、スケジュールに影響がで始め、このままだと先に進めないということで構成変更をすることになります。
しかし、この部分は一部修正が必要となりましたが、命名やパラメータを少々触る程度で済んだので、先に大枠から作るアプローチは良かったと思います。

### 2.サービスのコアになる部分に着手する
で、いよいよ問題の章です。
サービスのコアになる部分とは、具体的には「DockerコンテナとECS」になります。
ここの構築（特にECS）にかなり苦戦しました。

簡単にそれぞれの概要を触れますと、Dockerはコンテナ仮想化を提供してくれるもので、ECSはそのコンテナをAWS上で管理実行するサービスです。
それぞれ導入仕様と考えた目的は、「デプロイのしやすさ」「OS管理の省力」になります。

Dockerを用いることで、これまでサーバ内に直接インストールして構築していたものをイメージとして扱うことができ、このイメージを別環境にデプロイすることでマルっとコピーできるので、開発から本番への移行がスムーズになると考えました。
ECSの方は、「Fargate」というタイプを想定しており、その特徴である「OS部分を管理しなくて良くなる」点に魅力を感じ、採用しました。

### 着手順のミス
これが、ここで詰まってしまった大きな原因だったと思います。
前の「1.インフラの大枠となる要素に着手する」に引っ張られてか、次のような順番（上から）で取り組んでいました。

- ECSの仕様を調べる
- ECSを触ってみる
- Dockerの仕様を調べる
- Dockerを触ってみる

大枠であるECSから調査していました。
ECSはコンテナの管理、実行を行うサービスを提供します。
つまり、前提としてコンテナの知識が不可欠なのですが、その部分を意識せずにECSの仕様を単体で調査していました。

概念は以下の通り把握できたのですが、肝心のコンテナ部分の構築についての理解が曖昧であり、ECSコンソール上で表示されるエラーが果たしてDockerコンテナに問題があるのか、ECS上の設定に問題があるのか切り分けできていない状態でした。

途中で順序の問題に気づき、Dockerの方から着手するようにしました。
ECSの仕様調査と構築の部分で想定以上の時間を有してしまったこともあり、Dockerの調査は具体ベースで行うことにしました。
その理由として、コンテナ稼働のために用意するものは結局のところ、サーバ構築に必要なパラメータであるため、実際に設定ファイルで書かれているものを参考に公式ドキュメントを遡っていった方が効率的に学習できると考えたためです。

今回、Dockerコンテナとして必要なものは「webサーバ（NGINX）」「APサーバ（PHP）」（「DBサーバ（MySQL）」）でした。
これらの組み合わせは、よくあるweb3層の構造であり、同じような構造で作成している人はいると思い調べてみたところ、複数見つかりました。
それらを参考に、まず、各サーバで必要な設定ファイルの書き方を公式ドキュメントを参照し作成しました。
以下は実際に作成したNGINXの設定ファイルです。

- default.conf

```conf
server {
    listen 80;
    root /var/www/dailyReport/public/;

    add_header X-Frame-Options "SAMEORIGIN";
    add_header X-Content-Type-Options "nosniff";

    index index.php;

    charset utf-8;

    location / {
        try_files $uri $uri/ /index.php?$query_string;
    }

    location = /favicon.ico { access_log off; log_not_found off; }
    location = /robots.txt  { access_log off; log_not_found off; }

    error_page 404 /index.php;

    location ~ \.php$ {
    fastcgi_pass app:9000;
    fastcgi_index index.php;
    include fastcgi_params;
    fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
    fastcgi_param PATH_INFO $fastcgi_path_info;
    }

    location ~ /\.(?!well-known).* {
        deny all;
    }
}
```
次に、各Dockerfileを同様のステップで作成しました。
そして最後に、各コンテナを一括管理するためにdocker-compose.ymlを作成し、開発環境におけるDockerコンテナを何とか作り挙げることができました。

### 迫るスケジュール、焦りと冷静さ
このような状況の中で、時間は容赦してくれません。刻一刻と迫るスケジュールに焦りを感じていました。
「このままでは次に進めない、何とかしないと...」
いつの間にか、焦りで全体を見失っていることに気づきました。

そこで、改めて状況を整理して、そもそもどうなっている必要があるのか（ゴール）を見直すことにしました。
現状、インフラの大枠部分はできており、開発環境のセットアップは完了、後は本番環境のアプリケーション実行レイヤを構築すれば完了するところまで来ていることを再認識しました。

### かくなる上は...見出した打開策
一度冷静になってゴールと現在地を見直した結果、次の疑問が生じました。
「そもそもECSでないといけない理由は？」
「ECSで構築できないなら、普通にEC2インスタンスを立てて、そこでDockerコンテナを動かせば良いのでは？」

インフラ構築の根本のゴールは、本番環境でこれから実装していくアプリケーションが稼働できる環境を作ることです。

>サードパーティで用意されている様々なサービスもコアとなる要素を実現する手段でしかなく
技術選定の時に意識していたこのことを見失い、「ECS」という一要素に集中しすぎていました。

集中する余り、全体が見えなくなっていた点は反省です。

そうと分かれば、早速クライアントに相談をしました。
現状、ECSの構築で詰まっていること、代案としてEC2上にDockerコンテナを立てる形で構築したいこと等経緯と今後の案をお話しました。
その結果、了承をいただき、最終的な構成は以下になりました。

![image](https://user-images.githubusercontent.com/89679815/153197904-3ea12fcb-ab83-4a52-a4e7-cfbc011fbbe0.png)
![image](https://user-images.githubusercontent.com/89679815/153198517-8cbce042-c1dc-4114-aeba-456ca67339a2.png)

主な変更点は以下になります。

- ECSの利用からEC2インスタンスに変更
- CI/CDツール(CircleCI)の導入は見送り
- CloudWatch LogsはEC2変更により、インスタンスのログを確認すればよいので不要

開発からデプロイをスムーズにするためにCI/CDツールも導入したかったのですが、スケジュールの都合で割愛しました。
代わりに、EC2にGitをインストールする形でソースコードをデプロイし、DockerイメージはECRを経由してデプロイすることにしました。

## API設計
構成の変更はあったものの、何とかインフラ構築まで完了させることができ、いよいよAPIの設計に入りました。
が、一難去ってまた一難とでも言うのでしょうか、ここが個人的に最大の山場でした。

これまでAPIをコールするアプリは作ってみたことはありましたが、API自体を作ったことは無く、必要な前提が欠けていました。
そのため「Web API The Goog Parts」という本を読み、API設計の基礎を学習しました。

この本は、タイトルの通りWebAPIを設計する上で必要な要素を分かりやすく書かれており、中でも以下の点は非常に参考になりました。

- エンドポイントは「覚えやすく機能が一目でイメージできる」繋がりにする
- 短く入力しやすいURIにする
- 複数形の名詞を利用する
- JSONデータ構造はなるべくフラットにする
- クエリパラメータは一意なリソースを表すのに適し、パスパラメータは省略可能なパラメータに適している

WebAPIの全体像を掴んだので設計に入りました。
まず機能要件を満たすリソース（エンドポイント）はどのようなものになるか考えました。

- 機能要件
  - 任意のサービスから日報を投稿できる（少なくともSlackに対応）
  - 任意のサービスへ日報を送信できる（少なくともSpreadsheetに対応）
  - 日報をMySQLに保存できる
  - 日報の修正、削除ができる
  - 組織を作成、修正、削除できる
  - ユーザーを作成、修正、削除できる
  - 組織にユーザーを所属させることができる
  - 管理者が組織、全ユーザーの修正削除ができる  

考えたのですが、ここで2つの課題が生じました。
1. 認証機能をどうするのか
2. 任意のサービスから任意のサービスへの連携をどのように実現するのか

### 認証機能について
今回認証で最も詰まった点は「APIのみで完結させる点」でした。
例えばOAuthのフローで、あるアプリAのリソースに、ユーザー1の権限でアクセスしたいアプリBがいたとします。
この場合、アプリA（もしくはアプリB）はユーザー1に許可画面をリダイレクトし、ユーザー1の許可があった場合のみ、アプリBはアプリAへのアクセスが可能になります。

しかし、今回のAPIではリダイレクトUIは原則不要であり、この状態でどのようにしてユーザーの認証を行うのかイメージが掴めずにいました。
UIがない状態で各ユーザーはどのようにログインをするのか、ここがずっと引っかかっていました。

### 任意のサービスから任意のサービスへの連携について
また、任意のサービスから任意のサービスへの連携をどのように実現するのか。ここもかなり悩みました。
送信元が任意になるということは、送られて来るデータ形式も様々であり、どんなデータが来ても対応できる受け口をどのように作れば良いのか、そのイメージが持てずにいました。

この2つの課題に対して、あれでもない、これでもないと考えているうちに、また刻一刻とスケジュールが迫ってきました。

### 設計変更
これらに対してどのように対処したのか。
結論から言うと、インフラ構築時の教訓から残りのスケジュール的に間に合わなくなるため、クライアントにお詫びと相談を行いました。
現状上記の課題に対して、期限内に解決できそうにない旨、機能要件の内のコア機能の実装にフォーカスさせていただきたい旨をお伝えしました。（コア機能とは、SlackからDBに日報を保存し、Spreadsheetへの連携ために必要な部分になります。）

以降のスケジュール感をお伝えし、納期までにコア機能を実装する形で了承をいただきました。

非常に申し訳なく感じましたし、私自身とても悔しい気持ちでいっぱいでした。
ですが、納期まにできることはあり、そこに全力で挑もうと改めて決心しました。

最終的に作成したAPIの設計は以下になります。
![image](https://user-images.githubusercontent.com/89679815/153234473-177ca7db-29c7-4328-899e-ad5b97901d46.png)

SlackからSpreadsheetへの連携を行うために、Slack側の情報とSpreadsheet側の情報、そしてそれらをマッピングさせる情報が必要だと考えました。そこで、各情報を登録するエンドポイントを設け、その状態でSlackメッセージに投稿されるた際に連携される仕組みです。

また、合わせて上記API設計を基にDB設計を行いました。
![image](https://user-images.githubusercontent.com/89679815/153235249-2ce60966-ca8f-4e69-bae5-0c8b40db673a.png)


## コード実装
APIの設計も固まり、いよいよコードを書いていくフェーズに入りました。

### SlackとSpreadsheet連携の概要
SlackからSpreadsheetへ連携する流れは以下になります。

- Slackからメッセージを受け取る
- 送信元データに記載されているユーザー情報が登録されているか確認する
- （登録されていた場合）DBに日報データを保存する
- 事前に指定したSpreadsheetのシートに日報の内容を書き込む

![image](https://user-images.githubusercontent.com/89679815/153614445-19984013-c154-4e0d-9701-e0b4e5fd49c4.png)

### SlackEventAPIの利用
まず、連携元のSlackに投稿されたメッセージを取得するために、「SlackEventAPI」を利用しました。
流れとしては、SlackEventAPIの機能を有効にしたSlackアプリを作成し、それを連携したいSlackワークスペースにインストールします。
この状態でメッセージを投稿すると「メッセージ投稿イベント」が発火し、指定したURLへJSONデータが送信されます。

SlackEventAPIの仕様で、送信先が存在しているか判断するためにチャレンジリクエストが最初に送られます。そのため、これに対してレスポンスを返す必要があります。
その後、Slackイベントの内容を表すJSONデータが送られてくるので、この処理を実装していきます。

### GoogleSheetsAPIの利用
連携先であるSpreadsheetに書き込むために「GoogleSheetsAPI」を利用しました。
こちらはライブラリとして用意されており、PHP版もあります。

### 実装の学び
実装を行うあたり、初めて扱うLaravelを利用することにしたので、その学習も行いました。
ドキュメントを基に各ディレクトリの役割や書き方と言ったお作法を理解していきましたが、そもそものMVCの考え方に関心しました。
というのも、1つのアプリケーションの中で役割ごとにファイル（ディレクトリ）を分けておくことで、どこに何が書かれているかが明確になるのが個人的に画期的でした。

これまで素のPHPで学習していた際は、機能単位（ログイン、ログアウト等）で処理を書いていたので、1つのファイルが長くなることや見づらくなる書き方だったのだなと気づきました。

また、「モデル」という概念とその便利さも面白いと思いました。
厳密には「O/Rマッパー」の概念の方ですが、オブジェクトとRDBを対応づけることで、DBの情報を「オブジェクト」として扱えるのは「なるほど！！」となりました。

Laravelは「Eloquent」が標準で用意されており、これを利用することでPHPライクで（＝SQLを余り意識せず）DB操作ができるのは便利かつ新鮮でした。
ただ、内部でどんなSQLが実行されているか見えなくなるので、この部分も理解した上で使わないと困ることもありそうで、ただ便利だから使えばいいという分けでは無いんだなと思いました。

また、コードの書き方についても改めて学習しました。
今回特に意識して挑戦したのが「宣言的に書く」ことです。
これは、「どんな処理をしているか」を書くのではなく「何がしたいのか」を書いていくことで、上から下に読めば大体何がしたいか（＝全体の流れ）が掴めるというものです。
https://qiita.com/Hiroyuki_OSAKI/items/f3f88ae535550e95389d

この書き方をすることで、可読性があがるということを聞き、ぜひやってみようと思いました。
というのも、「納品＝今後修正なし」ではなく、また今回はオープンソースで公開するということなので、第三者が触れる可能性あるため、読みやすさは特に重要だと思ったためです。

ただ、これには少し苦労しました。
これまでの個人学習では上述の「どんな処理をしているか」という「命令的」な書き方で書いていたため、初めは「宣言的」のイメージが掴めませんでした。

実装し始めた時の処理例が以下になります。
これはSlackのユーザー情報を登録する処理なのですが、かなり長くなっています。

```php
    public function store(Request $request)
    {
        $team_id = $request->input('team_id');
        $channels = $request->input('channels');
        $users = $request->input('users');

        $MAE = new MultidimensionalArrayEditor;
        $channel_ids = $MAE->createNewArray($channels,'channel_id','slack_channel_id');
        $user_ids = $MAE->createNewArray($users,'user_id','slack_user_id');
        
        $slack_team_model = new SlackTeam;
        $slack_channel_model = new SlackChannel;
        $slack_user_model = new SlackUser;

        $team_id_record_existence = $slack_team_model->getTeamIdExistence($team_id);
        $channel_id_record_existence = $slack_channel_model->getChannelIdExistence($channel_ids);
        $user_id_record_existence = $slack_user_model->getUserIdExistence($user_ids);
        
        if($team_id_record_existence&&$channel_id_record_existence&&$user_id_record_existence)
        {
            $exception = new Exception("Record_Existence",400);
            throw $exception;
        }
        
        DB::beginTransaction();
        
        try{
            $result_of_save_record = $slack_team_model->create([
                'slack_team_id' => $team_id 
            ]);
            
            foreach($channel_ids as $channel_id){
                $result_of_save_record->associateSlackChannels()->create($channel_id);
            }
            
            foreach($user_ids as $user_id){
                $result_of_save_record->associateSlackUsers()->create($user_id);
            }

        }catch(Exception $e){ 
            DB::rollBack();
            throw $e;
        }

        DB::commit();

        return response()->json_content('201','Resource_Created');
}
```
それぞれの処理を読んでいかないとわからない状態ですね。
これを、処理を外に出して、それを呼び出す形にすることで以下のようにシンプルに記述することができました。

```php
 public function store(SlackRequest $request)
    {
        $validated = $request->validated();

        SlackTeam::registerSlackResources($validated['team_id'], $validated['channel_id'], $validated['user_id']);

        return response()->json_content('201', 'Resource_Created', 201);
    }
```
https://github.com/kazu24z/DailyReport/blob/main/src/app/Http/Controllers/SlackPostsController.php

## 納品
最終的に、本番環境での動作確認を終え、期日までに何とか納品することができました。

今回の実務で納品させていただいたものは主に以下になります。

- インフラ構築手順書
- ソースコード

また、途中で成果物のゴールが変わったため、改めて作成したシステム全体像とソリューションを以下に記載します。

- システム全体像
![image](https://user-images.githubusercontent.com/89679815/153197904-3ea12fcb-ab83-4a52-a4e7-cfbc011fbbe0.png)

- ソリューション
  - Slackに「日報」として投稿したメッセージをDBへ保存し、Spreadsheetに連携する
  - Slackには「日報」以外の投稿も行われるため、事前にキーワードを設定しておき、その文字列（正規表現も可）を含むメッセージが投稿された場合のみ連携


## 案件を終えて
2ヵ月間の実務案件に参加させていただき、本当に様々なことを学びました。

技術面では、2ヵ月前まで触ったことがないものに対して、基礎を学び、ある程度自分でも使えるようになりました。

次、Dockerで開発環境を作ってくださいとなったら、シンプルなものであればそれほど迷わず作れると思います。
Gitでコンフリクトが出ても落ち着いて対処できると思います。（初めてコンフリクトした時はめっちゃ焦りました。）
Laravelでアプリを作ろと思った時、今回で学んだことに加えて、今度はもっとLaravelの機能を使って作れると思います。

ただ、技術面でもかなり大きな資産になったなと思いますが、それよりも「認識面」で大きく変化できたと思います。
これは、大きく「作り手」と「作るもの」という面での変化です。

### 作り手としての認識の変化
実務と個人学習（趣味）とでは作り手の役割がまるで異なる、まずこれを痛感しました。
実務の場合、前提としてクライアントがいて、その課題を解決するために作るという背景があるため、作り手に要求される要素が多くなり、そのハードルも高くなるということです。

これは何も技術面での話だけでは無くて、「課題の把握とその解決策としての成果物の提案」「全体のスケジュール管理」「クライアントとの合意形成」といった「案件の流れ」に関わる部分もしっかりと意識して取り組む必要があると思います。

これらの要素はどちらかと言えばマネジメント側の仕事で、1メンバーが意識することではない様に一見思えます。
しかし、各メンバが自身のタスクに対して全体の流れを意識しておくことで、チームとしての作り手の質も高まっていくと思い、普段から個人でも意識した方が良いなと思うようになりました。

### 作るものへの認識の変化
作り手として求められるものが異なるならば、作るものへの認識も必然的に変わってくると思います。
今回特に学んだことは「運用性」と「保守性」です。

作るときに、既に未来のことを考えたものを作る意識が重要だと思いました。
その作成物がどれだけ使いやすくて、かつメンテナンスもしやすいかは、作る時次第。
ここで手を抜くことは未来に爆弾を送り込むことと同義で、トラブルの素になるため作るもの品質に妥協はできないと思いました。
そのため、この前提に立った時に、コードの命名1つにしても「これで本当に良いのだろうか」という意識を持って取り組もうと思うようになりました。

## おわりに
まず初めに、今回の実務案件を受けさせていただいたき、本当にありがとうございました。
この場をお借りしてお礼を申し上げさせていただきます。

それと同時に、自分の力が及ばない所があり、当初想定していたものと比べるとシンプルなものになった点はとても悔しかったです。
ただ、今回納品したものはオープンソースで公開されるということで、自分も1参加者として今回実装できなかった機能にチャレンジしてみたいと思います。

また、案件参加時に掲げた以下の目的についてどうだったか振り返ってみます。

- 現時点での自分のレベルを把握したい
- 開発実装をするエンジニアになる上で、今の自分に足りないものを把握し、埋めたい
- 仕事として活動した時の、想像とのギャップを無くしたい

### 現時点での自分のレベルを把握したい
参加当初のレベル感ですと「本当に何も知らないやん、自分」でした。
ある程度個人でアプリを作ってみても、実際の業務で必要とされるレベルや技術要素には遠く及ばないんだなと痛感しました。
これは気づけて本当に良かったです。

参加後のレベル感ですと「何も知らないから、少し知れた」という感触です。
本当に業務で必要とされている考え方や取り組む姿勢について、身をもって体験できたのは今後の活動でも活かして行きたいです。

### 開発実装をするエンジニアになる上で、今の自分に足りないものを把握し、埋めたい
技術面はまだまだいくらでも学ぶ余地はあり、むしろ学んで行くことは今後の楽しみです。

また、この実務を通して自分の弱点も明確になりました。
具体的には、「抽象と具体の行き来」です。
今回詰まってしまった「ECSの構築」において、そもそもこれを行う前提（一つ上の抽象）を思い出せば、より早い段階で「EC2」でも良いということに気づけたと思います。

### 仕事として活動した時の、想像とのギャップを無くしたい
挙げた目標のうち、これが最も大きい収穫でした。
実際に仕事として、プロとして開発実装を行っていく時に必要な心がけ、苦労を少しでも実体験できたと思います。
また、その上で改めて開発実装ができるエンジニアになりたいと強く思うこともできました。

新しいことを学び、それを活かしてクライアントの課題を解決することに貢献できるのは何とも言えない楽しさを感じることができました。

よって、個人的には概ね目標は達成できたと思います。

最後になりますが、今後の展望として、まずは今回の実務を通して分かった自分の課題解消に取り組みつつ、技術知識面をさらに磨いていきたいと思います。
この経験を活かして、開発実装ができるエンジニアとして活動していけるようにさらに精進していきます。

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