初めてのWeb開発はハードルを下げよう

# とある日のちびまろ
ちびまろはWeb開発者として働いてから約5年、テストを2年、開発に関わって約3年経ちます。
経験を軽く話すと、既存システムの保守運用をメインで担当し、ごくたまに新規機能の実装を行ってきました。

<br>

<font color="blue">ちびまろの同僚</font>「ねぇちびまろ、君はこのままでいいと思ってるの？」
<font color="green">ちびまろ</font>「思ってない！！」
<font color="green">ちびまろ</font>「もっと最新技術に触れて、もっと誰かのために役に立てるもの作りたい！<font color="#f8f8f8">~~なによりもお金が欲しい！~~</font>」
<font color="green">ちびまろ</font>「フレームワーク使って開発したい！（少しは楽したい...）」
<font color="blue">ちびまろの同僚</font>「じゃあやるしかないな！」
<br>
ここ数ヶ月<font color="red">**AIも出てきているのにこのままの技術力で良いのか**</font>と感じていたため、まずは比較的簡単だと言われている**Todoアプリ**を設計から実装まで行おうと決めました。

世の中に出さない場合、大雑把にわけて3つの工程があります。

---
**１. 設計**
- 何のシステムを作るか考える
- そのシステムにはどんな機能があるのか考える

**2. 実装（コーディング）**
- 設計で決めた内容をコードに起こしていく

**3. テスト**
- 実装した機能を一つ一つちゃんと動くか確認する
---
ひとまずこれらの工程についてふわっとしたイメージのままで行動しようとすると**何したらいいか分からない**という状況に陥ってしまいます。
「読むことはできるけど、実装はできない」という状況です。（私がそうでした）

今回扱う技術は以下の通りです。
**バックエンド**
- PHP
- Laravel

**フロントエンド**
- Blade
- TailwindCSSv

今回は少しでもハードルを下げるため<a src="https://chat.openai.com/">ChatGPT</a>にも助けてもらいながら進めました。

<font color="green">ちびまろ</font>「ChatGPT最高。」

<font color="blue">ちびまろの同僚</font>「てかそもそも、何でTodoアプリ作るの？」

# 0→1初心者は「Todoアプリ」がおすすめってホント？
結論から言うと、おすすめって意味では<font color="red">**ホント**</font>です！（異論は受け付ける😇）
Todoアプリを作成する工程で、Webアプリの基本、**CRUD機能**の実装を諸々行えます。

 - C「作成（Create）」
 - R「読み出し（Read）」
 - U「更新（Update）」
 - D「削除（Delete）」

もちろん天才でない限り、1回作っただけで覚えることはできませんが、「お〜だいたいこんな感じか〜」って感覚を味わうことができます。

この「お〜」という感覚は<font color="red">**本当に**</font>大切です！
この感覚を味わうことで、自信をつけることができ、モチベーションにも繋がります。

必ずしも「Todoアプリ」を作成する必要はありませんが、世にサンプルとなるものが沢山あふれているので機能を参考にすることで、<INS>考えるべきことがかなり激減</INS>して楽になります。

つまり、<INS>ハードルを下げる</INS>ことができます！

そう！<INS>**コーディングだけ**</INS>に集中ができるのです！

<font color="green">ちびまろ</font>「最初からハードルをあげるとしんどいよね〜」
<font color="green">ちびまろ</font>「モチベーション続かずに後々嫌にもなってくるんだよね〜」

肩の力を抜いて、焦らず１歩ずつ着実に確実に進んでいきましょう。

## chatGPTを使って作るアプリの一覧を提案してもらった
最初は調子に乗って100本ノック！などと考えていましたが、ちょっと時間的にも余力的にも無理だと思ったので、その中の一部だけ抜粋して載せます。（Todoアプリ以外を作るかどうかは悩んでます）

![image001_todoForOneHundredKnocks.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/431046/597247d0-6d2c-a740-c7e9-625cc6a1bd0b.png)

要件定義〜実装(一部コードのみ)まで全て記録に残していこうと思います。
私も学びながら進めているため、間違いなどがあればコメントにて指摘・アドバイスなどくれると嬉しいです！

# 要件定義
要件定義はシステム開発の最初に行われる工程です。
設計をするためにはまず<font color="red">**どんなものを作るのか**</font>を考える必要があります。
そのために必要なのが要件定義です。
要件定義で内容を詰めずにいると、実装の途中で大幅な修正が入ることになります。
最終的に納期に間に合わないということになりかねません。

<br>

**〜とある日のちびまろ〜**

<font color="green">ちびまろ</font>「わぉ！この機能お客さんが求めていた機能と違うらしいよ！」
<font color="blue">ちびまろの同僚</font>「ほんとに？！じゃあ設計からやり直しになるよね？！」
<font color="blue">ちびまろの同僚</font>「やめてくれー！！(￣^￣゜)ｸﾞｽﾝ」

最悪の場合、システムの土台ごと設計し直すようなことになります。

## 要件定義の目的
**クリアな目標の設定**
- 何を作るのか、どのような問題を解決するのかを明確にする

**ステークホルダーの期待の一致**
- 開発者、ユーザー、関連部門など、関わるすべての人々の期待を一致させる

**開発工程の基盤作り**
- 後の設計や実装フェーズでの方針や基準を確立する

## 要件定義の種類
要点定義は大きく分けて２種類あります。

### １.機能要件
システムが持つべき機能や振る舞いを定義します。
サービスやタスクなど、システムが「何をするか」に関する要件です。
**例**
- ユーザーはログインとログアウトができる
- 管理者はユーザーアカウントを作成・削除できる
- システムは商品の在庫情報を表示する
- ユーザーはカートに商品を追加・削除できる

### ２.非機能要件
システムがどのような品質属性を持つべきか。
つまり「どのように機能するか」に関する要件を指します。
これはシステムのパフォーマンス、信頼性、セキュリティなどの特性に関連します。
**例**
- システムの応答時間は2秒以内であること
- 99.9%の稼働率を確保する
- ユーザーデータは暗号化して保存する
- システムは1万人の同時アクセスに耐えられる

## 機能の洗い出し
早速Todoアプリを作る上で必要な機能を洗い出します。

### ログイン機能
1. ユーザーID、パスワードの登録を可能とする
    - メールアドレスの登録は不要
2. タスクを作成すると、ユーザに紐づいたデータが作成される
3. パスワードの条件は以下の通り
    - 8文字以上。大文字・小文字・数字それぞれ最低1文字含むこと。

### タスク一覧表示機能
1. ログインユーザに紐づくタスクを表示する
    - ステータスが未完了かつ、登録日が古いもの順に表示させる

### タスク登録機能
1. 保持するデータ
    - タスクのタイトル
    - タスクの詳細
    - タスクのステータス
        1. 未着手
        2. 着手中
        3. 保留
        4. 完了
    - 期限
        - 期日が1日以内の物は赤字表示もあり？
### タスク詳細表示機能
1. タイトルに関する詳細なタスク内容を表示する
    - タイトルのリンクを押下すると詳細画面に飛ぶ
### タスク編集機能
1. タイトル・詳細・期日の編集を行うことができる
    ※ステータスは編集ボタンを押下せずとも常時編集可能とする
### タスク削除機能
- 間違えて登録したタスクや、不要となったタスクを削除する
- ページネーション機能
    - 10件単位とする


# 画面構成
機能の洗い出しをして必要な機能は以下の７つになりました。

1. ユーザーログイン機能
2. ユーザー登録機能
3. Todo一覧表示機能
4. Todo登録機能
5. Todo詳細表示機能
6. Todo編集機能
7. Todo削除機能

# DB設計
今回必要なDBは２つ
1. 登録されたユーザー情報を保管するテーブル
    - Usersテーブル
2. ユーザーが作成したタスク情報を保管するテーブル
    - Todosテーブル

## 必要なデータ・データ型・文字数・制約
それぞれのテーブル構成は以下のようにしました。
ユーザーに対して複数のタスクを紐付ける(一対多の関係)ため、todosテーブルに外部キーを担う`user_id`を追加しています。
usersテーブルの`id`とtodosテーブルの`user_id`を紐づけることで、誰が追加したタスクかを判断するようにしています。
気になった方は「[DB リレーションシップ](https://www.google.com/search?q=DB+%E3%83%AA%E3%83%AC%E3%83%BC%E3%82%B7%E3%83%A7%E3%83%B3%E3%82%B7%E3%83%83%E3%83%97)」でググってみてください。

### usersテーブル
![image002_todoForOneHundredKnocks.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/431046/fe62ee12-b264-99f0-9d3e-7d918cda909c.png)

### todosテーブル
![image003_todoForOneHundredKnocks.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/431046/576e8055-4496-ec8f-2b35-b1ada5dea234.png)


# フローチャートの作成
機能別のプロセスを整理するためにフローチャートの作成はとても良い手段だと考えています。
頭の中で考えるより図解して整理することで、足りない機能があることに気付くこともあります。
簡易的ですが<a href="https://app.diagrams.net/">draw.io</a>を使ってそれぞれの画面でのフローチャートを作りました。

![image004_todoForOneHundredKnocks.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/431046/a7989c74-be8d-ca35-3ead-0d8f5314281f.jpeg)


# 画面設計

デザインはどうにも苦手で😅
ここはハードルを下げるために一旦諦めて潔く[テンプレートサイト](https://flowbite.com/)にお世話になりました！

# 実装

テンプレートを使い、自分の要望とは合致しないボタンやレイアウトは変更する形で対応しました！

## フォーム系の画面
フォームが実装されている画面は全て同じ[こちら](https://flowbite.com/blocks/marketing/register/#:~:text=Default%20register%20page)のテンプレートを使用しました。

### ユーザー登録画面

テンプレートを元に一部自分好みにカスタマイズしました。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/431046/ad232423-b4f5-3e29-05eb-cc5091c73634.png" width="400px">

 - 「I accept the Terms and Conditions」の削除


### ログイン画面
まだ実装はしきれてなく、余裕がある時に実装しようかと考えている機能が2つあります。
 - Remember me
 - Forgot your password?

それぞれ自動ログイン機能と、パスワードリセット機能です。
応用に近い機能だと感じたため、画面には残しましたがロジックの実装は後々という感じで考えています。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/431046/42691957-4d92-e308-646b-cb1998e96d34.png" width="400px">


### Todo登録機能

以下4つの内容を登録できるような画面を作成しました。
1. タスクのタイトル
2. タスクの詳細情報
3. 期限日
4. 状況

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/431046/a0b99169-8b1f-e844-a0bc-ccb3563fbbad.png" width="400px">

### Todo編集機能

登録されたデータのidをリンクの`/edit`前に渡すことによって、紐づくデータを取得して初期表示の際にフォームに自動的に入るようにしています。
```link
http://127.0.0.1:8000/todos/1/edit
```

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/431046/18f615a3-b642-0e0d-45f7-72c5d4c348e9.png" width="400px">

この編集機能を実装するときは本当に色々つまづきました。
詳細は[後述](#苦労したところ)します。

### Todo詳細表示機能
本来であれば実装の必要はなかったのですが、どうしても`show`メソッドを使ってみたかったので実装することにしました。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/431046/f9d9acd1-97f0-5352-3353-9f8d53b1df0e.png" width="400px">

## Todo一覧表示機能

[こちら](https://flowbite.com/blocks/application/advanced-tables/#:~:text=Requires%20Flowbite%20JS-,Default%20table,-%23)のテンプレートを元に一部カスタマイズしました。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/431046/5f061ffa-4e43-ebc1-57c0-03413e5a3156.png" width="800px">

#### カスタマイズ項目
 - 検索窓の削除
 - Actionsボタンの削除
 - Filterの削除

ちなみに右側の「・・・」を押すと以下の画面（赤枠）が展開されます。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/431046/1e390863-9400-2100-9051-578dfb835053.png" width="800px">


# 苦労したところ
今回Todoアプリを作る上でつまづいたところがいくつかあったので紹介します！


## 詳細画面でのステータス表示

登録されたステータスを取得し、デフォルトで表示されるよう`selected`をつける処理をどうしようかと迷いました。
何とかスマートな実装方法にしようと考えたところ以下のように落ち着きました。
「if($todos->status == '?')だったら selectedをつける」というロジックを各ステータスに書いています。

![スクリーンショット 2023-12-02 2.04.37.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/431046/e69896b3-45cd-61e8-5dc2-c53886a7c91a.png)


## [Todo編集機能](#todo編集機能)
<font color="green">ちびまろ</font>「だめだ〜、フォームの内容を変更して更新ボタン押しても全然反映されない...」

<font color="green">ちびまろ</font>「なんでだろ〜」

**〜色々試行錯誤〜**

<font color="green">ちびまろ</font>「見た感じルーティングの設定もあってるはず...」

<font color="green">ちびまろ</font>「見た感じformのactionリンクもあってるはず...」

<br>

<font color="green">ちびまろ</font>「あれ？ルーティングの`Route::??`の`??`の部分を間違えてる？！」
```PHP
Route::post('/todos/{id}', [TodoController::class, 'update'])->name('todos.update');
```
↓
```PHP
Route::put('/todos/{id}', [TodoController::class, 'update'])->name('todos.update');
```

<font color="green">ちびまろ</font>「よし！これでいけるはずだ！」

<br>

**〜結果は変わらず〜**

<br>

などと2時間ほど格闘した結果、ルーティングのパラメータ名が原因でした。

<font color="red">**ルーティングのパラメータ名**</font>と<font color="red">**`update`メソッドの第二引数の変数名（$todos）**</font>を一致させる必要があります。

今回の場合、第二引数の`$todos`と合わせる必要があります。

#### コントローラー
```PHP
public function update(Request $request, Todo $todos): RedirectResponse
```

#### ルーティング

```PHP
Route::put('/todos/{id}', [TodoController::class, 'update'])->name('todos.update');
```
↓putメソッドの第１引数のパラメーターを`todos`に変更後↓
```PHP
Route::put('/todos/{todos}', [TodoController::class, 'update'])->name('todos.update');
```

こうすることで、更新処理が上手く走るようになりました！

<font color="green">ちびまろ</font>「きたーーーーー！！！！」
<font color="green">ちびまろ</font>「この壁を突破した感覚があるからプログラミングは辞められない！」


### P.S.
[X](https://twitter.com/chibimaro_nikki)で教えていただきましたが、[Route Model Binding](https://laravel.com/docs/10.x/routing#route-model-binding)という機能があるそうです！
まだざっくりとしか理解できてないので割愛させていただきますが、気になった方は是非調べてみてください。


# 最後に
最後まで読んでいただきありがとうございました。
他のTodoアプリを参考にしたものの、0から何かを作る経験を積むことができて少し自信に繋がりました。

設計時点では色々アイデアは思いつきましたが、期日を１ヶ月と決めていたため、最低限の機能のみ実装しました。
1回作成しただけでは慣れないので、CRUD機能を用いた何かしらのシステムをまた作成しようと考えています。
<br>
<font color="green">ちびまろ</font>「はてさて、次は何作ろうか？」