OmniAICreator/Qiita-1.07M huggingface dataset:
個人的備忘録：コンテナ2つで構成するDjango＋NginxアプリのECSタスク定義とは

## はじめに
AWS ECS（Elastic Container Service）は、Dockerコンテナをスケーラブルにデプロイ・管理できるサービスです。

:::note info
**個人の備忘録程度の走り書きとなっておりますが、温かい目で見守っていただければ幸いです。**
:::

本記事では、実際のタスク定義（Task Definition）をもとに、DjangoアプリケーションとNginxのリバースプロキシ構成がどのように構成されているのかを紐解きます。

---

## タスク定義の全体構成

```json
"taskDefinitionArn": "arn:aws:ecs:ap-northeast-1:xxx:task-definition/reverse-proxy-task:11",
"family": "reverse-proxy-task",
"revision": 11,
"status": "ACTIVE",
"requiresCompatibilities": ["FARGATE"],
"networkMode": "awsvpc",
"cpu": "1024",
"memory": "2048",
```

- **taskDefinitionArn**: タスク定義の一意な識別子。
- **family**: タスク定義グループ名。
- **revision**: リビジョン番号。バージョン管理に相当。
- **requiresCompatibilities**: 実行環境（ここでは `FARGATE`）。
- **networkMode**: `awsvpc` で独立したENIが割り当てられる。
- **cpu/memory**: タスク全体に割り当てるリソース量。

---

## コンテナ定義①：Django アプリ

```json
"name": "django",
"image": "xxx.dkr.ecr.ap-northeast-1.amazonaws.com/reverse-proxy-django-app",
"cpu": 512,
"memory": 1024,
"portMappings": [{"containerPort": 8000, "hostPort": 8000}],
"environment": [
  {"name": "DJANGO_SETTINGS_MODULE", "value": "mysite.settings"},
  {"name": "STATIC_ROOT", "value": "/app/staticfiles"},
  {"name": "DJANGO_SECRET_KEY", "value": "your-secret-key"}
],
"logConfiguration": {
  "logDriver": "awslogs",
  "options": {
    "awslogs-group": "/aws/ecs/reverse-proxy-cluster",
    "awslogs-region": "ap-northeast-1",
    "awslogs-stream-prefix": "ecs"
  }
}
```

- **image**: ECR上のDjangoアプリケーションイメージ。
- **portMappings**: コンテナ内ポート8000をホストの8000にバインド。
- **environment**: Djangoの設定に必要な環境変数。
- **logConfiguration**: CloudWatch Logs へのログ送信設定。

---

## コンテナ定義②：Nginx

```json
"name": "nginx",
"image": "xxx.dkr.ecr.ap-northeast-1.amazonaws.com/reverse-proxy-django-nginx",
"cpu": 512,
"memory": 1024,
"portMappings": [{"containerPort": 80, "hostPort": 80}],
"logConfiguration": {
  "logDriver": "awslogs",
  "options": {
    "awslogs-group": "/aws/ecs/reverse-proxy-cluster",
    "awslogs-region": "ap-northeast-1",
    "awslogs-stream-prefix": "ecs"
  }
}
```

- **image**: ECR上のNginxイメージ。Djangoへのリバースプロキシ。
- **portMappings**: HTTPリクエスト用に80番ポートをバインド。
- **logConfiguration**: Djangoと同様、CloudWatchにログ出力。

---

## タスク実行に必要なIAMロール

```json
"executionRoleArn": "arn:aws:iam::xxx:role/ecsTaskExecutionRole"
```

このIAMロールには以下のポリシーが含まれている必要があります：

- AmazonECSTaskExecutionRolePolicy
- ECRからのイメージ取得、CloudWatchへのログ出力

---

## その他の設定

```json
"requiresAttributes": [
  "com.amazonaws.ecs.capability.logging-driver.awslogs",
  "ecs.capability.execution-role-awslogs",
  "com.amazonaws.ecs.capability.ecr-auth",
  "ecs.capability.task-eni"
]
```

- ECSがタスクを正常に実行するために必要な機能。

---

## まとめ
このタスク定義は、AWS ECS Fargate上にDjangoアプリとNginxのリバースプロキシ構成をデプロイするための標準的な例です。Fargateを使うことでインフラの管理が不要となり、ログ収集やネットワークも簡単に構成可能です。

このような構成は、マイクロサービス化やDevOpsを進める上で非常に有効です。
Wrangler pages devでホットリロードしたい

# はじめに

Cloudeflare WorkerをNext.jsで開発している中で調べても見つからなかったのでまとめます

# 問題

cloudflare workerをローカルで開発するときに

```
$ npm run preview
```

```package.json
    "pages:build": "npx @cloudflare/next-on-pages",
    "preview": "npm run pages:build && wrangler pages dev --d1=DB"
```

をするとホッとリロードが効かないです。
`--hot-reload`などを試しましたが何故か上手く生きませんでした。

# 解決方法

nodemonを使って`app`を監視して変更があったら`npm run pages:build`をすることで解決しました

```
$ npm i nodemon
$ npm i concurrently
```

```package.json
    "watch-build": "nodemon --watch app --ext js,jsx,ts,tsx,css,json --exec \"npm run pages:build\" --ignore .vercel/",
    "dev:watch": "concurrently \"npm run watch-build\" \"wrangler pages dev --d1=DB --live-reload\"",
```

こうすることでホッとリロードは実現できます。

**しかし、変更がある度にすべてのビルドをするので超遅いです**

# おわりに

このような方法をしている人が多かったので、そもそも開発の仕方として違うのかもしれません
ただDBを使うにはWrngler devで起動しないといけないのでわかる方はこめんとくだｓ
イミュータブル設計：なぜ“変更しない”が強いのか


## 概要

「イミュータブル（immutable）」── 不変性を意味するこの設計概念は、関数型プログラミングにおいて中心的な思想だ。  
だが、なぜ「値を変えない」ことがそれほどまでに重要視されるのか？

本稿では JavaScript をベースに、イミュータブル設計の意味、メリット、誤解、実装技術を  
**「なぜ」「いつ」「どのように」使うべきかという設計的視点**から明快に解き明かしていく。

---

## 1. 可変 vs 不変：その違いを明示する

### ❌ ミュータブル（可変）

```js
const user = { name: 'Alice' }
user.name = 'Bob' // 値が書き換えられる
```

- 値が直接変更される  
- 参照元のオブジェクトも変わってしまう

---

### ✅ イミュータブル（不変）

```js
const user = { name: 'Alice' }
const updatedUser = { ...user, name: 'Bob' } // 新しい値を作る
```

- 元のオブジェクトは変更されない  
- 状態が明示的に管理される

---

## 2. なぜ不変性が強いのか？

| 利点              | 説明                                                                 |
|-------------------|----------------------------------------------------------------------|
| **予測可能性**     | 値が変化しないので、**どこでどう変わったか**を追う必要がない       |
| **デバッグ容易性** | 前の状態がそのまま残るため、**履歴が追える**                        |
| **並行処理との親和性** | 複数スレッド・非同期処理でも**状態の衝突が起こらない**             |
| **Undo/Redoが容易** | 状態が履歴として残るため、**時間軸的制御が可能**                    |

---

## 3. JavaScriptでのイミュータブル実装技術

### ✅ 配列の例

```js
const arr = [1, 2, 3]
const updated = [...arr, 4] // 新しい配列を返す
```

### ✅ オブジェクトの例

```js
const settings = { darkMode: false }
const nextSettings = { ...settings, darkMode: true }
```

### ✅ ネストされた構造：ライブラリ使用推奨（例：Immer）

```js
import produce from 'immer'

const nextState = produce(state, draft => {
  draft.user.name = 'Charlie'
})
```

---

## 4. 状態を持たない「思考」へのシフト

### Before: 命令型的な設計

```js
let total = 0
for (let n of [1, 2, 3]) {
  total += n
}
```

### After: イミュータブル + 宣言的設計

```js
const total = [1, 2, 3].reduce((acc, n) => acc + n, 0)
```

- 状態の更新がなく、**ロジックが明示的に読める**

---

## 5. 設計判断フロー

```text
① この値は複数箇所から変更されうるか？ → YES → 不変性で守るべき

② 前の状態を保持したいか？ → YES → イミュータブルが適している

③ 関数が副作用を含むか？ → NO → イミュータブル設計が生きる

④ 複雑な変更を追うのが辛い？ → YES → 値を破壊せずに更新する方針に切り替える
```

---

## よくある誤解と対策

### ❌ イミュータブルだとコードが冗長になる

→ ✅ 初期はそう見えるが、**長期的に破壊的変更のバグが消える**

---

### ❌ オブジェクトがどんどんコピーされてパフォーマンス悪化

→ ✅ 実際にはシャローコピー＋参照共有で問題にならない。必要なら**永続データ構造**の導入を

---

### ❌ 「全部イミュータブルにすればいい」

→ ✅ **副作用を隔離したい“境界”に対して適用**。すべてを不変にするのではない

---

## 結語

イミュータブル設計とは、**「値が変わらない」ことに価値があるのではない。**  
それは「**変わるという概念を管理可能にする構造**」であり、設計の本質的な安定性を担保する技術である。

- 値を破壊しない  
- 状態を管理ではなく**構築**する  
- 時間・履歴・副作用を構造に内包できる

**イミュータブル設計とは、  
“変化に強いソフトウェアを、不変という前提から築く構造的な戦略である。”**
純粋関数とは何か：状態と副作用を捨てると何が得られるか


## 概要

関数型プログラミング（FP）における核、それが**純粋関数（pure function）**である。  
しかし「副作用がない関数」と言われても、それが設計にどう効くのかは直感的に理解しづらい。

本稿では、Rustを例にしながら「純粋関数とは何か？」「副作用を除外することの意味は何か？」を、  
**実用・設計・安全性・テスト性**の観点から徹底的に分解・言語化する。

---

## 1. 純粋関数とは？

### ✅ 定義：

> **同じ入力に対して、常に同じ出力を返し、副作用を持たない関数。**

```rust
fn add(a: i32, b: i32) -> i32 {
    a + b
}
```

- ✅ `add(2, 3)` は常に `5` を返す  
- ✅ グローバル変数、IO、状態への書き込みを行わない

---

## 2. 純粋関数 vs 非純粋関数

### ❌ 非純粋関数（副作用を含む）

```rust
use std::fs;

fn save_log(message: &str) {
    fs::write("log.txt", message).unwrap();
}
```

- IOを行っている  
- 実行するたびに世界（ファイルシステム）を変化させる  
- テスト・並列実行が**壊れやすい**

---

### ✅ 純粋関数

```rust
fn format_log(level: &str, msg: &str) -> String {
    format!("[{}] {}", level, msg)
}
```

- 入力 → 出力  
- 状態を変えない  
- 結果に一切のブレがない

---

## 3. 純粋関数の利点

| 観点       | 説明 |
|------------|------|
| **テスト** | 状態依存がないため、**モック不要・DI不要・安定** |
| **再利用** | 関数の「使い回し」が容易。文脈に依存しない |
| **並列性** | 状態を持たないため、**スレッドセーフが自動的に担保** |
| **デバッグ** | ロジックが独立しており、**問題の局所化が容易** |

---

## 4. Rustと純粋関数の相性

- Rustは**副作用を強制しないが、明示的な所有権とライフタイムで副作用の管理を強化**している
- 可変性（mut）もデフォルトで禁止されており、**イミュータブルベースの思考に向いている**

```rust
fn square(x: i32) -> i32 {
    x * x
}
```

- **値の所有 / 移動 / 借用**により、副作用の意図的な切り出しが可能

---

## 5. 純粋関数を書くための判断フロー

```text
① グローバル変数・IO・ネットワークアクセスを含んでいないか？ → YES → 純粋でない

② 入力だけで出力が決まるか？ → NO → 振る舞いが曖昧、純粋性に欠ける

③ 状態を書き換えていないか？ → YES → 設計の再考

④ 同じ引数で常に同じ値を返すか？ → YES → 純粋
```

---

## 6. よくある誤解と対策

### ❌ 「純粋関数しか使えないと不便なのでは？」

→ ✅ FPは副作用を否定しない。**“制御下に置く”ために純粋関数を中心に据える**

---

### ❌ 「副作用を取り除くと実用的じゃない」

→ ✅ 副作用を**末端に限定し、ロジック本体から隔離する設計**が理想

---

### ❌ 「副作用が悪い」＝ NG

→ ✅ **予測できない副作用が問題**。予測可能にすればOK

---

## 7. 構造のデザイン指針

```rust
// 副作用を含む関数（ログ出力）を
fn log_to_console(msg: &str) {
    println!("{}", msg);
}

// 純粋関数に変換可能
fn build_log_message(level: &str, content: &str) -> String {
    format!("[{}] {}", level, content)
}
```

- ロジックを分離 → 副作用部分をコントローラ層で限定的に呼ぶ  
- テストしやすさ / ロジックの流用性が一気に向上する

---

## 結語

純粋関数とは、単に「きれいなコード」の話ではない。  
それは**「状態」「副作用」「複雑性」といったプログラミングの根本的困難を制御する戦略的な構造」**である。

- 小さく、明確で、テスト可能な関数
- 設計を閉じることで、拡張・変更に強くなる
- 副作用を“排除”ではなく、“支配”するための技術

**関数型設計とは、  
“混沌と予測不能を、関数と構造で静かに制御する抽象的技術体系である。”**
関数型プログラミング入門：FPが求められる理由とその哲学



## 概要

関数型プログラミング（Functional Programming / FP）は、  
副作用や状態を抑制し、**より安全で予測可能なソフトウェア設計**を志向する哲学だ。

この思想は単なるスタイルの違いではない。  
それは「ソフトウェアの成長・保守・拡張に耐える設計」を根本から捉え直すための構造的転換である。

本稿では、FPの本質・背景・設計思想を整理しながら、Elixirでの事例を交えて解説する。

---

## 1. 命令型（Imperative）と関数型（Functional）の違い

### ✅ 命令型：**「何をどうやるか」を記述**

```ruby
# Rubyでの命令型スタイル
total = 0
[1, 2, 3].each do |n|
  total += n
end
puts total
```

- 状態（`total`）が変化しながらロジックが進行  
- 実行順序に強く依存する

---

### ✅ 関数型：**「何をしたいか」を記述**

```elixir
# Elixirでの関数型スタイル
IO.puts Enum.sum([1, 2, 3])
```

- 状態を持たず、式の合成で振る舞いを定義  
- 実行順序に依存せず、副作用もない

---

## 2. なぜ今FPなのか？

### ✅ マルチスレッド時代の「安全性」を担保する

- 可変状態を持つ命令型コードは**スレッドセーフでない**
- FPは**イミュータブル（不変）な値**を基本とし、状態の競合を回避する

---

### ✅ テストしやすい構造を自然に得られる

- 関数が純粋（同じ入力 → 同じ出力）であれば  
  **モック不要、DI不要、環境依存ゼロのテスト**が可能になる

---

### ✅ 副作用の制御が明示的になる

- IO / DB / ネットワークといった**不可測な操作を明示的に分離できる**
- 振る舞いの中心は「純粋なロジック」に留められる

---

## 3. 関数型の本質：構造としての「制約と自由」

| 特性             | 説明                                                  |
|------------------|-------------------------------------------------------|
| **純粋関数**     | 副作用を持たず、同じ入力には常に同じ出力を返す        |
| **イミュータブル** | 値の再代入ができず、全ての状態は新しい値として返る   |
| **関数合成**     | 小さな関数を繋げて大きな振る舞いを作る                |
| **宣言的構文**   | 処理の意図をコードで表現し、実行順序を持たない構造    |

---

## 4. Elixirにおける関数型思考の実践

### 純粋関数 + パターンマッチによる明快な設計

```elixir
defmodule Tax do
  def calc(:normal, price), do: price * 1.1
  def calc(:reduced, price), do: price * 1.08
end
```

- 副作用なし
- 条件分岐も命令型の `if` ではなく、**マッチングで表現**
- データと振る舞いが分離されている

---

## 5. FPは「抽象化」のための構文ではなく、「思考の再設計」

### ❌ よくある誤解

- FPは難解な構文の話？  
  → **No**、それは結果であり本質ではない

- 関数をいっぱい書くだけ？  
  → **No**、副作用を排除し**“制御可能な世界”を作る思想**である

### ✅ 真のFPは「ロジックを透明にする設計哲学」

---

## 設計判断フロー

```text
① この関数は副作用を含むか？ → YES → 分離して外側に置く

② このデータは変化する必要があるか？ → NO → イミュータブルで扱う

③ この構造は再利用しやすいか？ → YES → 純粋関数 + 高階関数に昇華できる

④ 処理の意図を「何をしたいか」として記述できるか？ → YES → 宣言的に書く
```

---

## よくある疑問と答え

### Q. FPは結局、実用に向いてるの？

✅ 向いてる。特に以下の分野で有効性が高い：

- 並行処理（Elixir / Erlang）
- ドメインロジックの抽象化（Haskell / Scala）
- ビジネスルールの表現力（F# / ReasonML）
- テストしやすさを設計で担保したい場面（TypeScript / Kotlin）

---

### Q. JavaScriptやPythonでもFPできる？

✅ できる。  
`map`, `filter`, `reduce` などは**関数型の片鱗**。  
状態・副作用を切り離すだけで、思想的にはほぼFPである。

---

## 結語

関数型プログラミングは、**構文の美しさ**を追い求めるものではない。  
それは、**複雑さ・バグ・副作用・設計崩壊からソフトウェアを守る哲学**である。

- 副作用を分離し、  
- ロジックを構造化し、  
- 実行ではなく**意図**を記述する

**FPとは、  
“予測不能な世界を、制御可能なロジックとして再構築するための抽象的な思考技術である。”**
TDDによるプロジェクト駆動設計：個人開発やチーム開発における実践戦略


## 概要

TDD（Test-Driven Development）はコードレベルの技術に留まらない。  
それは、**設計・意思決定・ドキュメント・開発文化そのものを駆動する戦略**でもある。

本稿では、TDDをプロジェクトの核に据えることで、  
個人開発やチーム開発において**どのような実利があるか、どう展開するか**を具体的に提示する。

---

## 1. 「テストが先」は「仕様が先」という思想

- TDDは「テストを書く手法」ではない  
- それは **「設計の意思を先に表明するプロセス」** である

```text
要件 → 仕様（Red）→ 最小の実装（Green）→ 構造の洗練（Refactor）
```

- TDDの目的は「正しく動くコード」ではなく、  
  **「意味を持つ構造」「壊れにくい設計」を生み出すこと**

---

## 2. 個人開発でTDDを導入する意義

### ✅ 要件が曖昧な中での羅針盤となる

- 自分で決めた仕様でも、**テストに書くことで外部化できる**
- 「思いつき」を「設計」に昇華する道筋になる

### ✅ 無限リファクタの暴走を防ぐ

- テストが仕様を固定することで、**進行方向がロックされる**
- 曖昧な設計ではなく、**動く・壊れない設計**が構築される

---

## 3. チーム開発におけるTDDの文化的価値

### ✅ コードレビューが「仕様レベル」で行える

- テストが仕様なので、**レビュー対象が「正しいか」から「望ましいか」に進化する**
- 実装の詳細ではなく、**意思と契約にフォーカスしたレビュー**が可能に

### ✅ テストが「仕様書」兼「ドキュメント」になる

- テスト = 何が期待されているか  
- 実装が読めなくても、**テストを見ればその関数の存在理由が分かる**

### ✅ リグレッションに対する自信が持てる

- 大規模変更やリファクタも、**テストが仕様を保証することで加速する**

---

## 4. プロジェクト設計にTDDを活かすパターン

| 活用領域               | 方法                                     | 効果                                 |
|------------------------|------------------------------------------|--------------------------------------|
| API開発                | インターフェース仕様をテストとして先に書く | 設計のブレを防ぎ、実装がスムーズに  |
| ドメインロジック設計  | 境界条件・例外パターンをTDDで仕様化       | 拡張しやすく、バグに強い構造へ      |
| モジュール分離         | 振る舞いテストを先に書くことで責務が明確に | 自然に責任単位でモジュール分離される|
| CI/CD設計              | テスト失敗 = リリース不可にする           | 品質ゲートの文化的インストール       |

---

## 設計判断フロー（プロジェクト全体でTDDを生かす）

```text
① 要件はそのままテストに落とせるか？ → YES → 実装よりもテストを書く

② 担当者が変わっても、仕様が理解できるか？ → YES → テストを仕様書に

③ 設計議論が「構造」ではなく「振る舞い」で行えるか？ → YES → 設計が進化可能に

④ バグが出たとき、テストで再現可能か？ → YES → 再発防止策が明示化される
```

---

## よくある壁と対策

### ❌ TDDが形式だけになり、実装が主導している

→ ✅ **Red → Green → Refactor** の思考順序を維持する  
→ ✅ 「どう書くか」より「どう使われるか」に集中する

---

### ❌ テストがメンテ不能になり、リファクタの阻害要因に

→ ✅ **内部実装ではなく、外部仕様（インターフェース）に対するテスト**を書く

---

### ❌ テストがあるのに品質が担保されない

→ ✅ テストが仕様を表していない可能性。**「何を保証しているか」**を見直す

---

## 結語

TDDとは、**テストでドライブされる開発手法ではない。**  
それは**「設計そのものを先に定義し、実装を後から従わせる設計駆動戦略」**である。

- 要件の不確実性に対応し  
- 設計の方向性を確定し  
- チームの共通言語として機能し  
- プロジェクトを守る防壁になる

**TDDとは、  
“仕様をコードとして先に描き、プロジェクトそのものを制御する戦略的デザインアプローチである。”**
MCPツール の使い方

Ubuntu上でMCPツール（mcptools）の使い方をまとめてみました。

> GitHub: [https://github.com/f/mcptools](https://github.com/f/mcptools)

---

## 📌 この手順でできること

- ✅ MCP CLI（`mcp`）をUbuntuにインストール
- ✅ ファイル操作MCPツール（@modelcontextprotocol/server-filesystem）を使ってみる
- ✅ ファイルの読み書き・検索などをコマンド1つで実行できるようになる

---

## 🧰 1. 必要なシステム環境とパッケージのインストール（※Ubuntu専用）

> 💡 **この手順は Ubuntu（Debian系）Linux 環境を前提としています。**

```bash
sudo apt update
sudo apt install -y git curl build-essential golang make nodejs npm
```

---

## ✅ 2. Go（Golang）のセットアップ（バージョン 1.21 以上）

```bash
go version
```

古い場合は以下で更新：

```bash
cd /tmp
curl -LO https://go.dev/dl/go1.22.2.linux-amd64.tar.gz
sudo rm -rf /usr/local/go
sudo tar -C /usr/local -xzf go1.22.2.linux-amd64.tar.gz
echo 'export PATH=$PATH:/usr/local/go/bin:$HOME/go/bin' >> ~/.bashrc
source ~/.bashrc
```

再確認：

```bash
go version
```

---

## ✅ 3. MCP CLI（mcptools）のインストールとセットアップ

```bash
go install github.com/f/mcptools/cmd/mcptools@latest
ln -s ~/go/bin/mcptools ~/go/bin/mcp
echo 'export PATH="$HOME/go/bin:$PATH"' >> ~/.bashrc
source ~/.bashrc
```

確認：

```bash
mcp --help
```

---

## ✅ 4. MCP テンプレートのインストール（初回のみ）

```bash
mkdir -p ~/.mcpt/templates
git clone https://github.com/f/mcptools.git
cp -r mcptools/templates/* ~/.mcpt/templates/
```

---

## 🧪 5. MCPツールの即時実行テスト（ファイル操作ツール）

```bash
cd ~
mcp tools npx -y @modelcontextprotocol/server-filesystem ~
```

---

# 🔧 使用例まとめ（ファイル操作系 MCP ツール）

### 📖 ファイルを読む

```bash
echo "Hello MCP" > test.txt
mcp call read_file --params '{"path": "test.txt"}' npx -y @modelcontextprotocol/server-filesystem ~
```

### 📝 ファイルを書き込む

```bash
mcp call write_file --params '{"path": "hello.txt", "content": "Hello from MCP!"}' npx -y @modelcontextprotocol/server-filesystem ~
```

### 📁 ディレクトリ構成を確認

```bash
mcp call list_directory --params '{"path": "."}' npx -y @modelcontextprotocol/server-filesystem ~
```

### 🌳 ツリー構造で取得

```bash
mcp call directory_tree --params '{"path": "."}' npx -y @modelcontextprotocol/server-filesystem ~
```

### 🔍 ファイル検索

```bash
mcp call search_files --params '{"path": ".", "pattern": "txt"}' npx -y @modelcontextprotocol/server-filesystem ~
```

---

## ✅ .mcptプロジェクトとObsidianの連携

1. Obsidianを開き、「Vaultを開く」で `~/.mcpt` を選択
2. `.mcpt` フォルダ内のツール定義やノートが閲覧・編集可能になります

---

## 🧩 よくあるエラーと対処法

### `ENOENT: no such file or directory`

```bash
cd ~
mcp call read_file --params '{"path": "test.txt"}' npx -y @modelcontextprotocol/server-filesystem ~
```

---

## 🎁 補足：MCP Tools の機能一覧（概要）

| コマンド | 説明 |
|----------|------|
| `tools` | 利用可能なMCPツール一覧を表示 |
| `call` | MCPツール・プロンプト・リソースの呼び出し |
| `mock` | テスト用モックMCPサーバ起動 |
| `proxy` | シェルスクリプトをツールとして登録 |
| `shell` | 対話CLIモード |
| `new` | プロジェクトやツールの雛形を作成 |
| `alias` | MCPサーバーショートカット登録 |

---
TDDにおける失敗のパターン：テスト先行で開発できないときに起こっていること

## 概要

TDD（Test-Driven Development）は、構造化された開発戦略だ。  
しかし現場でTDDを採用しようとしても、**うまく機能しないケースが存在する。**

本稿では、Java + JUnit5 をベースに、  
**TDDが破綻する典型パターンとその背後にある設計上の問題点**を分解・解説する。

TDDが機能するには、**「正しい構造」＋「適切なテスト粒度」＋「思考の順序」**が必要だ。

---

## 1. パターン①：テストが書けないほど複雑なロジック

### 症状：

```java
public void process() {
    // if A then B, unless C, but if D then E...
    // deeply nested logic
}
```

- 単一メソッドが多すぎる責務を抱えている  
- テストを書こうとすると「どこをどう切り出せばいいか分からない」

### 処方：

- テストが書けない = 設計が間違っているサイン  
- 責務を分離し、**小さなユニットへと分割することでTDD可能に**

---

## 2. パターン②：UIやDBなど副作用に密結合している

### 症状：

```java
public void saveUser(User user) {
    Connection con = DriverManager.getConnection(...);
    ...
}
```

- 外部I/Oに依存しており、テストのたびに副作用が発生  
- モック化も困難

### 処方：

- **依存をインターフェースに抽象化し、注入（DI）する構造へ**  
- DBアクセスやAPI通信は、**テスト対象外に分離**

---

## 3. パターン③：テストが実装に引きずられ過ぎている

### 症状：

```java
// 内部のフィールド値や呼び出し回数に依存したテスト
assertEquals(service.getInternalMap().size(), 3);
```

- 実装の詳細に依存し、変更に対して壊れやすい  
- リファクタできなくなる

### 処方：

- **振る舞い（アウトプット）ベースでテストを書く**  
- 中身ではなく「外から見える結果」を保証する

---

## 4. パターン④：「とりあえず動かす」 → テスト後回し

### 症状：

- 先にコードを書き、「あとからテストを書く」方がラク  
- 結果、テストは補足的になり、設計は無秩序に肥大化

### 処方：

- それは「TDD」ではなく「Test-After」  
- **TDDの本質は「先に仕様を書く」ことによる設計誘導**

---

## 5. パターン⑤：テストの粒度が合っていない

### 症状：

- 巨大な統合テスト1本で、すべてをチェックしようとする  
- 失敗時に「どこが悪いか分からない」

### 処方：

- **ユニットレベルでの小さなテスト**を積み上げる  
- 外部依存はモック・スタブで隔離

---

## 設計判断フロー

```text
① テストが書きにくい？ → 責務が多すぎるか、密結合している

② テストが壊れやすい？ → 実装の詳細に依存している可能性

③ テストを書いても価値が薄い？ → 粒度 or 仕様の曖昧さを見直す

④ 実装を先に書いていないか？ → それはTDDではない
```

---

## よくあるミスと対策

### ❌ 「TDDは面倒くさいから最後にやる」

→ ✅ **TDDは後から足すものではなく、設計を導く入口である**

---

### ❌ テストを書いているのに設計が良くならない

→ ✅ **テストが仕様になっていない（単なる確認になっている）**

---

### ❌ テストがどんどん壊れて疲弊する

→ ✅ **テスト構造に依存しすぎている。リファクタに耐えうる設計を**

---

## 結語

TDDが機能しないとき、問題は**TDDの手法そのものではなく、設計と向き合う姿勢**にある。

- テストが書けない構造こそ、改善すべき構造  
- TDDは「テストを書く技術」ではなく、「仕様から設計を導く戦略」  
- 書けない理由を**設計の失敗として見つめ直す**ことが、TDD最大の価値である

**TDDとは、  
“書けないテストが教えてくれる、設計の限界と進化の方向である。”**
境界条件を仕様として先に書く：TDDでバグの温床を消す技法



## 概要

バグの多くは**境界条件（境界値）**で発生する。  
1未満、100超、0の扱い、空配列、最大件数…。

TDDではこのような「壊れやすい瞬間」を**“仕様として先にテストに刻む”**ことで、  
未然に不具合を防ぎ、堅牢で進化可能な設計を実現できる。

本稿では、Python + pytest による実装を通じて、  
**TDDにおける境界条件設計の技術と思想**を実践的に解説する。

---

## 1. 境界条件とは「コードの不確実性が最も高まる瞬間」

- 「>= 100」と「> 100」の違い  
- 配列長が `0`、`1`、`最大` のときの処理  
- 入力が空文字列、null、0 のとき…

> ✔️ テストがなければ、**実装者の感覚頼りになる**  
> ✔️ テストがあるなら、**それが境界の仕様書になる**

---

## 2. 実例：`is_valid_age(age: int) -> bool` のTDD

### 🔴 Red – 仕様を先に定義する

```python
# test_validator.py

from validator import is_valid_age

def test_age_under_minimum():
    assert is_valid_age(-1) is False

def test_age_minimum():
    assert is_valid_age(0) is True

def test_age_maximum():
    assert is_valid_age(120) is True

def test_age_over_maximum():
    assert is_valid_age(121) is False
```

- ここで **「何を許し、何を拒否するか」** が明確に仕様化される  
- **バグの種を先に潰す** ための Red である

---

## 3. 🟢 Green – テストを通す実装を書く

```python
# validator.py

def is_valid_age(age: int) -> bool:
    return 0 <= age <= 120
```

- ✅ 単純な比較だが、**仕様が先に定義されているから迷いがない**
- ✅ 誰が見ても「何が有効な年齢か」が明らか

---

## 4. TDDにおける境界設計のパターン

| テスト観点           | 例                               | 理由                               |
|----------------------|----------------------------------|------------------------------------|
| 最小値/最大値       | `0`, `120`                       | 許容される境界を明示              |
| 境界直下/直上       | `-1`, `121`                      | 排除される境界を明示              |
| 空/null/None        | `""`, `None`                     | 実行時エラーや意図しない通過を防止 |
| 最短/最長の配列     | `[]`, `["a"] * 100`              | 反復処理の開始点・終了点           |

---

## 5. テストに刻むべき“設計の綻び”

TDDで境界を仕様化するとは、「開発者の迷い」を先に潰すことである。

- 曖昧な値 → 明示的な仕様で定義  
- 複雑な条件 → テストケースで分解  
- 例外的な振る舞い → テストで「期待」として固定化

> ✔️ TDDで書いた境界テストは、**「将来の改修に対するバグガード」**になる

---

## 設計判断フロー

```text
① この関数に「境界的な値」があるか？ → YES → その境界をRedで書く

② 最小/最大/その前後はどうなるべきか？ → YES → 明示的に仕様化

③ 許容する値と、拒否する値は？ → 曖昧なら仕様として定義してしまう

④ 後続処理で依存していないか？ → 境界を守ることで他ロジックを単純化できる
```

---

## よくあるミスと対策

### ❌ 境界条件をあとでテストに追加しようとする

→ ✅ TDDでは**最初に“失敗する境界”をRedとして書く**

---

### ❌ 「たぶん動く」コードでテストを書かない

→ ✅ **曖昧な仕様こそ、最も先に書くべきテスト**

---

### ❌ 境界テストが通るだけのコードで満足する

→ ✅ **リファクタ後も壊れない保証として、Red → Green → Refactor を一貫させる**

---

## 結語

境界条件とは、**仕様の曖昧さが最も現れる地点であり、最も壊れやすい地点**でもある。  
TDDではその危うさを、**Redとして先に可視化し、Greenとして仕様に昇華する**。

- 開発者の不安をコード化する  
- 境界をテストに刻むことで安心して構造を進化できる  
- 境界値が明文化されていれば、バグは未然に潰される

**TDDとは、  
“不安をRedにし、安心をGreenで設計に変える。進化のための予防的戦略である。”**
リファクタとテストのバランス：安全な変更と進化可能な構造


## 概要

TDDの三原則は「Red → Green → Refactor」と表現されるが、  
最も誤解されがちなのが **「Refactor」の扱い** である。

本稿では、TypeScript + Vitest を使った実例を通して、  
**TDDにおけるリファクタリングの意義、タイミング、テストとの相互関係**を設計視点から深掘りする。

---

## 1. リファクタは「書き直し」ではない

### ❌ 書き直し ≠ リファクタ  
- 書き直し：挙動が変わる  
- リファクタ：**挙動を変えずに構造を改善する**

> ✔️ リファクタとは「振る舞いを保ったまま、設計だけを進化させる行為」

---

## 2. 実例：TDDでFizzBuzzをリファクタする

### ✅ 初期状態（Green済み）

```ts
export function fizzbuzz(n: number): string {
  if (n % 15 === 0) return 'FizzBuzz'
  if (n % 3 === 0) return 'Fizz'
  if (n % 5 === 0) return 'Buzz'
  return String(n)
}
```

### ✅ テストが保証している状態

```ts
import { describe, it, expect } from 'vitest'
import { fizzbuzz } from './fizzbuzz'

describe('fizzbuzz', () => {
  it('returns "FizzBuzz" for 15', () => {
    expect(fizzbuzz(15)).toBe('FizzBuzz')
  })
  it('returns "Fizz" for 3', () => {
    expect(fizzbuzz(3)).toBe('Fizz')
  })
  it('returns "Buzz" for 5', () => {
    expect(fizzbuzz(5)).toBe('Buzz')
  })
  it('returns number string otherwise', () => {
    expect(fizzbuzz(2)).toBe('2')
  })
})
```

---

## 3. Refactor：構造改善をテストに守られながら行う

```ts
const rules: [number, string][] = [
  [15, 'FizzBuzz'],
  [3, 'Fizz'],
  [5, 'Buzz'],
]

export function fizzbuzz(n: number): string {
  for (const [divisor, word] of rules) {
    if (n % divisor === 0) return word
  }
  return String(n)
}
```

### ✅ テストが全て通っている → 振る舞いは保たれている

- 可読性・保守性が向上  
- テストが「不変性の保証」として機能

---

## 4. TDDにおける「安全な進化」の戦略

| 項目           | 説明                                                       |
|----------------|------------------------------------------------------------|
| リファクタの開始条件 | Green状態。全テストが通っていること                     |
| リファクタの目的     | 重複の除去、関心の分離、責務の明確化                   |
| リファクタの限界     | 振る舞いを変えない範囲でのみ行う（変えるならRedから） |

---

## 5. テストによって保証される「設計の自由」

TDDのテストは、仕様を保証するためだけではない。  
それは**「安全な変更を可能にする境界線」**でもある。

### ✅ テストが存在すると…

- 構造を壊す不安がない  
- 改善の自由度が高まる  
- **進化できる設計**が実現する

---

## 設計判断フロー

```text
① この変更は振る舞いに影響を与えるか？ → YES → Redから設計変更

② テストはすべて通っているか？ → YES → Refactorに入れる

③ 重複・密結合・肥大化があるか？ → YES → 分離・抽象化・責務の再配置

④ 実装の都合でテストが壊れやすくなっていないか？ → YES → テスト構造も整理
```

---

## よくあるミスと対策

### ❌ テストを書かずに構造を変えてしまう

→ ✅ **Green状態 + テスト網** がないリファクタは「賭け」

---

### ❌ 「振る舞いは同じ」の確認ができない

→ ✅ テストが網羅していなければ、**それはRefactorではない**

---

### ❌ テストが脆く、構造変更で頻繁に壊れる

→ ✅ テストも「設計の一部」。**リファクタしやすい構造に保つこと**

---

## 結語

TDDの最終工程である「Refactor」は、**設計を進化させるための権利**である。  
そして、その権利はテストによって保証されている。

- RedとGreenで振る舞いを定義し  
- Refactorで構造を洗練する  
- テストによって**リスクなき進化が可能になる**

**TDDとは、  
“コードの正しさを守りながら、設計を攻められる構造を作るための進化戦略である。”**
モックの使いどころとやりすぎを見極める：TDDにおける隔離戦略


## 概要

TDDにおいて「モック」は、  
**外部依存や副作用を分離し、純粋な設計を支える道具**として強力に機能する。

しかし一方で、**過剰なモックはテストを壊れやすく、設計を不自然にする。**

本稿では、C# + xUnit + Moq による実装例を通じて、  
**「モックを使うべきとき」「使ってはいけないとき」**の判断基準と、設計への影響を明確にしていく。

---

## 1. モックの目的は「外部依存の隔離」

テスト対象を純粋なロジックに保つには、**外部との通信（DB/API/メール/時間など）を排除する**必要がある。

```csharp
public interface IClock {
    DateTime Now { get; }
}
```

```csharp
public class GreetingService {
    private readonly IClock _clock;

    public GreetingService(IClock clock) {
        _clock = clock;
    }

    public string Greet() {
        return _clock.Now.Hour < 12 ? "Good morning" : "Good evening";
    }
}
```

> ✅ 時間に依存せず、**コアロジックのテストが可能な設計**

---

## 2. Moqでのモック作成とTDDでの利用

```csharp
public class GreetingServiceTest {
    [Fact]
    public void Greet_BeforeNoon_ReturnsGoodMorning() {
        var clock = new Mock<IClock>();
        clock.Setup(c => c.Now).Returns(new DateTime(2024, 4, 2, 9, 0, 0));

        var service = new GreetingService(clock.Object);
        var result = service.Greet();

        Assert.Equal("Good morning", result);
    }
}
```

- ✅ モックは「対象が依存している振る舞い」の**予測可能な置換**である
- ✅ 「結果が時間に依存しない」という**仕様の検証**が可能になる

---

## 3. モックを使うべきタイミング

| タイミング                           | 理由                                      |
|--------------------------------------|-------------------------------------------|
| 外部I/Oが関わる                      | 実行速度・安定性・副作用防止              |
| 状態や出力が予測しにくい            | 時間・乱数・非同期など                    |
| フローを確認したい（コールされたか）| verify系を使って**振る舞いを検証**したい時 |
| 契約に従っているか検証したい        | interfaceの**利用側の正しさ**を担保       |

---

## 4. モックを使ってはいけない場面

| 状況                             | なぜNGか                                      |
|----------------------------------|-----------------------------------------------|
| 単純なデータ構造だけの依存       | モックよりフェイクや直接生成の方が自然        |
| テスト対象の内部実装に依存する   | 実装の詳細に依存しすぎて**テストが脆くなる**  |
| コール順、回数などを過剰に縛る   | 振る舞いを固定化し、**リファクタに弱くなる**  |
| 「なんでもモック」でテストを書く | テストが**信頼できるドキュメントでなくなる** |

---

## 5. モックとスタブ・フェイクの選定戦略

| 手法   | 用途                             | 特徴                             |
|--------|----------------------------------|----------------------------------|
| モック | コールされたことを検証           | `Verify()`で振る舞いを確認       |
| スタブ | 特定の戻り値を返す               | 振る舞いのシミュレーション       |
| フェイク | 簡易実装で依存を代替             | 実装あり。シンプルなテストDBなど |

> 選定基準は「**どの設計レイヤを検証したいか**」

---

## 設計判断フロー

```text
① テスト対象が外部に依存しているか？ → YES → モック/スタブを検討

② 検証したいのは戻り値か？呼び出しか？ → 値 = スタブ、呼び出し = モック

③ 依存のインターフェースがあるか？ → NO → 設計見直し（DIへ）

④ モックを導入することでテストが壊れやすくならないか？ → YES → 他の手段を検討
```

---

## よくあるミスと対策

### ❌ あらゆる依存に対して機械的にモックを適用

→ ✅ **テストの目的が曖昧になる。**構造と責務を見直すべきシグナル

---

### ❌ モックの戻り値や呼び出し順にテストが過剰に依存

→ ✅ **振る舞いを過度に縛ると設計が変えられなくなる**

---

### ❌ モックが肥大化してメンテ不能に

→ ✅ フェイクや実装差し替え可能な構造を優先する

---

## 結語

モックはTDDの中で最も誤用されやすい道具だ。  
しかし本質的には、**“テストの正確性を保ちつつ、構造の透明性を確保するための隔離戦略”**である。

- 依存を分離することで、テストは高速・安定・意図的になる  
- 過剰なモックは、テストを壊れやすくし、設計を硬直させる  
- モックは「使うこと」が目的ではない。「構造を制御する」ためにある

**TDDとは、  
“正しい隔離によって、誤差を制御し、構造を純化するための戦略的な設計運用である。”**
ユーザー操作をTDDで記述する：UI操作・イベント駆動テストの書き方


## 概要

TDD（Test-Driven Development）は、**ロジックだけでなくUIにも適用できる。**  
むしろ、ユーザー操作という「最も振る舞いに近い層」にこそ、TDDは真価を発揮する。

本稿では、Vue 3 + Testing Library + Vitest を使って  
**UIイベント駆動テストをTDDで設計・実装する方法**を、段階的に解説する。

---

## 1. UIにおけるTDDとは

UIのTDDでは「コンポーネントの内部構造」をテストするのではなく、  
**ユーザー視点での操作とその結果**を仕様として書いていく。

> テストの対象は「状態」ではなく「振る舞い」

---

## 2. 実装例：ToDo追加フォームのTDD

### 🔴 Red：まずは失敗する仕様を書く

```ts
// AddTodo.spec.ts
import { render, screen } from '@testing-library/vue'
import userEvent from '@testing-library/user-event'
import AddTodo from './AddTodo.vue'

test('入力後、ボタンをクリックするとToDoが登録される', async () => {
  const user = userEvent.setup()
  render(AddTodo)

  await user.type(screen.getByPlaceholderText('やること'), '牛乳を買う')
  await user.click(screen.getByRole('button', { name: '追加' }))

  expect(screen.getByText('牛乳を買う')).toBeInTheDocument()
})
```

---

## 3. 🟢 Green：最小構成の実装でテストを通す

```vue
<!-- AddTodo.vue -->
<template>
  <div>
    <input v-model="text" placeholder="やること" />
    <button @click="add">追加</button>
    <ul>
      <li v-for="(todo, i) in todos" :key="i">{{ todo }}</li>
    </ul>
  </div>
</template>

<script setup>
import { ref } from 'vue'

const text = ref('')
const todos = ref([])

function add() {
  if (text.value) {
    todos.value.push(text.value)
    text.value = ''
  }
}
</script>
```

---

## 4. Red-Green-Refactor：UI層でもこの循環は生きる

| フェーズ   | アクション                          | 設計上の意義                        |
|------------|-------------------------------------|-------------------------------------|
| 🔴 Red     | 仕様（ユーザー操作）を書く           | 要求が明確になる                    |
| 🟢 Green   | 最小構成で振る舞いを満たす実装を書く | 過剰な機能や構造を避けられる        |
| 🔁 Refactor| DOM構造やメソッドの整理              | 可読性・再利用性が高まる            |

---

## 5. ユーザー視点のTDD設計指針

### ✅ テストは「ユーザー操作と言葉」で書く

- `"牛乳を買う"` という入力
- `"追加"` というボタン
- 結果として「表示される」ToDo

### ✅ DOMの詳細に依存しない

- `getByText`, `getByPlaceholderText`, `getByRole` を活用  
- `querySelector` ではなく、**ユーザーが見える情報**で取得

### ✅ 内部ロジックの存在を意識しない

- テストは **入力 → 結果** のみを書く  
- ローカルステートや関数名に依存しない

---

## 設計判断フロー

```text
① どんな操作をするか？ → userEventで表現

② 何が画面に表示されるか？ → screen.getByTextで表現

③ DOM構造や実装を意識していないか？ → NO → ユーザー視点に戻す

④ ボタンが押されたあと、何が見えるか？ → YES → 期待結果として明記
```

---

## よくあるミスと対策

### ❌ DOM要素のクラス名やIDに依存したテスト

→ ✅ UIは「見える振る舞い」ベースで書く（＝ユーザー視点）

---

### ❌ 「フォームの値」や「内部のstate」を直接検証

→ ✅ 入力 → 出力の結果でテストすること。**中身ではなく結果**

---

### ❌ プレーンな`click()`や`input.value = ...`で操作する

→ ✅ `userEvent` を使って実際のユーザー操作を模倣する

---

## 結語

UIにおけるTDDとは、**コンポーネントの中身を検査するものではない。**  
それは**「ユーザーの操作に対して、何が画面に現れるか」を仕様として定義し、実装をそれに従わせるプロセス**である。

- 内部状態ではなく、**ユーザー体験（UX）**をテストに落とし込む  
- DOMの構造ではなく、**振る舞いと言葉**で書く  
- UIにもTDDを適用することで、**壊れにくく進化しやすい画面設計が可能**になる

**TDDとは、  
“ユーザーの行動をコードとして記述し、インターフェースの期待値を明文化するUI設計戦略である。”**
TDDで進めるAPI設計：戻り値と例外をテストから設計する

## 概要

API設計において、レスポンスの構造やエラーの表現は**後回しにされやすい設計領域**だ。  
しかし、TDDを実践することで、**戻り値・エラー・境界条件を「仕様」として最初に定義できる**ようになる。

本稿では、Node.js + Jest を使った TDD の流れを通して、  
**「振る舞いの設計」と「エラーの設計」をテスト駆動でどう構築するか**を具体的に解説する。

---

## 1. API設計における「戻り値と例外」の責任

- APIは「成功」と「失敗」の2軸しかない  
- それらを**構造的にどう返すかが設計品質に直結する**

TDDでは、「何を返すべきか」を**テストという仕様定義の中で明文化できる**。

---

## 2. 実装例：ユーザー登録API（成功 / バリデーションエラー / DB失敗）

### 🔴 Red：仕様を書く（Jest）

```js
// userService.test.js

const { registerUser } = require('./userService');

describe('registerUser', () => {
  it('should return userId on successful registration', async () => {
    const user = { name: 'Alice', email: 'alice@example.com' };
    const result = await registerUser(user);
    expect(result).toEqual({ ok: true, userId: expect.any(String) });
  });

  it('should return validation error if email is missing', async () => {
    const user = { name: 'Bob' };
    const result = await registerUser(user);
    expect(result).toEqual({
      ok: false,
      error: {
        code: 'VALIDATION_ERROR',
        message: 'Email is required.',
        field: 'email',
      },
    });
  });

  it('should return system error if DB fails', async () => {
    const user = { name: 'Charlie', email: 'fail@db.com' };
    const result = await registerUser(user);
    expect(result.ok).toBe(false);
    expect(result.error.code).toBe('DB_ERROR');
  });
});
```

---

## 3. 🟢 Green：仕様を通す実装を最小構成で書く

```js
// userService.js
const crypto = require('crypto');

async function registerUser(user) {
  if (!user.email) {
    return {
      ok: false,
      error: {
        code: 'VALIDATION_ERROR',
        message: 'Email is required.',
        field: 'email',
      },
    };
  }

  if (user.email === 'fail@db.com') {
    return {
      ok: false,
      error: {
        code: 'DB_ERROR',
        message: 'Failed to connect to database',
      },
    };
  }

  return {
    ok: true,
    userId: crypto.randomUUID(),
  };
}

module.exports = { registerUser };
```

---

## 4. 構造の意義：振る舞いを「定義」するという設計

- 成功：`{ ok: true, data }`  
- 失敗：`{ ok: false, error: { code, message, field? } }`  

このような構造を**テストから先に書くことで**、  
- 振る舞いが明文化され、  
- 実装はその仕様に忠実に従うよう設計される。

---

## 5. TDDによるAPI設計の価値

| 項目         | TDDでの設計効果                              |
|--------------|-----------------------------------------------|
| 戻り値構造   | 明示的かつ一貫性のある返却型が定義される     |
| エラー制御   | 曖昧な例外処理ではなく、構造化された失敗     |
| 拡張性       | `error.code` ベースでロジックを追加できる     |
| UI実装側     | 型が保証され、**安心してマッピング可能**     |

---

## 設計判断フロー

```text
① 成功の戻り値は何か？ → テストで先に書いて定義する

② 失敗時に何を返したいか？ → 構造・コード・メッセージを明示する

③ 想定する失敗の種類は？ → バリデーション / システム / 認証 など

④ その情報でフロントは制御できるか？ → UI要件も含めて考える
```

---

## よくあるミスと対策

### ❌ 成功時だけを前提とした実装で例外を投げるだけ

→ ✅ **失敗も1つの仕様として明示的に定義する**

---

### ❌ テストがレスポンス構造をチェックしていない

→ ✅ **「何を返すか」が設計の本質。型・構造を仕様として記述**

---

### ❌ テストでtry/catchを使っている（=テストが仕様を覆っている）

→ ✅ **catchではなく、構造的な `result.ok === false` に寄せる**

---

## 結語

TDDは、単に「コードを確認するもの」ではない。  
それは**“振る舞いを先に定義し、実装をそれに従わせるための設計手法”**である。

- テストは「何を返すべきか」を先に定義する仕様書  
- 失敗もレスポンスとして設計することで、APIが堅牢になる  
- フロントエンドやクライアント実装との整合性が高まる

**TDDとは、  
“振る舞いの期待値をテストに刻み込み、構造的なAPI設計を導く戦略である。”**
DI（依存性注入）とTDD：テスタブルな構造はどう生まれるか

## 概要

TDD（Test-Driven Development）を実践していく中で、  
必ず直面するのが「テストしづらいコード」である。  
その多くは「依存が暗黙的に組み込まれていること」が原因だ。

本稿では、**依存性注入（Dependency Injection）を通じて、TDDに適した構造をどう設計するか**を、  
Kotlin + JUnit5 + Mockito をベースに徹底解説する。

---

## 1. テスタブルなコードには「依存の明示」が必要

### ❌ テストが難しいコードの典型例

```kotlin
class UserService {
    fun registerUser(email: String) {
        val mailer = Mailer()
        mailer.send(email)
    }
}
```

- `Mailer` が**内部で直接 new されている**ため、テスト時に差し替え不能  
- モックもDIも適用できないため、**構造自体が閉じている**

---

### ✅ TDDでは依存を外部から注入することで設計を開く

```kotlin
class UserService(private val mailer: Mailer) {
    fun registerUser(email: String) {
        mailer.send(email)
    }
}
```

- 依存（Mailer）は**コンストラクタで注入**  
- テスト時に**モックを差し込むだけで振る舞いを検証可能**

---

## 2. 実装とテストの分離：TDD視点での構造構築

### インターフェースを使った依存の抽象化

```kotlin
interface Mailer {
    fun send(to: String)
}
```

```kotlin
class SmtpMailer : Mailer {
    override fun send(to: String) {
        println("Sending mail to $to")
    }
}
```

### 本体クラス（テスト対象）

```kotlin
class UserService(private val mailer: Mailer) {
    fun registerUser(email: String): Boolean {
        mailer.send(email)
        return true
    }
}
```

---

### テストコード（Mockitoでモック化）

```kotlin
class UserServiceTest {

    private val mailer = mock(Mailer::class.java)
    private val service = UserService(mailer)

    @Test
    fun `should send mail on register`() {
        val email = "test@example.com"

        val result = service.registerUser(email)

        assertTrue(result)
        verify(mailer).send(email)
    }
}
```

- ✅ 依存の抽象化により、**テストが局所的に・高速に・確実に行える**
- ✅ 実装を変えずに、**テストの検証範囲を意図的に限定可能**

---

## 3. TDDがDIを要求する理由

| TDDの要件                   | DIによる設計改善                       |
|-----------------------------|----------------------------------------|
| 単体で検証可能な構造       | 依存を注入して**制御可能な構造**にする |
| 副作用の隔離               | 実装依存を**抽象（インターフェース）**に置換 |
| 曖昧な責務の可視化         | コンストラクタで**依存を明示**          |
| モックの適用性             | DIにより**差し替えが容易**になる        |

---

## 4. 設計パターンとしてのDI

### コンストラクタインジェクション（最推奨）

```kotlin
class MyService(private val repository: UserRepository)
```

- ✅ 不変性の担保、明示性、テスト容易性すべてを備える

---

### フィールドインジェクション（柔軟だが非推奨）

```kotlin
lateinit var repository: UserRepository
```

- ❌ 明示的でなく、テスト時の**副作用の混入リスクが高い**

---

### メソッドインジェクション（限定された場面で有効）

```kotlin
fun process(repo: UserRepository) {
    repo.doSomething()
}
```

- ✅ 短命な依存や一時的な差し替えに使える

---

## 設計判断フロー

```text
① 依存する外部オブジェクトがあるか？ → YES → インターフェース抽出

② テストで差し替えたいか？ → YES → コンストラクタ or メソッドで注入

③ 実装に依存せず、契約だけで使いたいか？ → YES → 抽象型を渡す

④ DIフレームワークを使うか？ → 小規模では不要、明示的な設計で代替可
```

---

## よくあるミスと対策

### ❌ newやstaticメソッドがテスト対象に直書きされている

→ ✅ 外部依存を**注入可能な構造に変更する**

---

### ❌ モックがうまく機能せず、テストが壊れる

→ ✅ **インターフェース設計が甘い or 責務が混在しているサイン**

---

### ❌ DIを使うが、何に注入すべきか分からない

→ ✅ **変化する or 副作用を持つ依存**が対象。純粋な関数は不要

---

## 結語

TDDにおけるDIとは「テストのための小技」ではない。  
それは**“構造を開き、依存を制御し、責務を明示するための設計戦略”**である。

- 依存は「隠す」のではなく「渡す」ことで設計は透明になる  
- テストしやすさは、設計が分離できているかのリトマス試験紙  
- DIは**柔軟性ではなく、明示性と制御性をもたらす設計構造**

**TDDとは、  
“依存を明示し、責務を最小化し、テスト可能な構造に導くための思考設計プロセスである。”**
TDDで書く「失敗するテスト」の美学：想定される未来の不具合と設計ガード


## 概要

TDD（Test-Driven Development）では、  
**まず「失敗するテスト」を書くことからすべてが始まる。**

それは単なるルールではなく、**設計を「防御的かつ先回り的」に進める知的戦略**である。

本稿では、Go言語を使った実装例を通して、  
**「TDDにおける失敗するテスト」の意義、構造、設計的価値**を深掘りする。

---

## 1. なぜ「失敗するテスト」を先に書くのか？

### ✅ 仕様が不明確なまま書かれたコードは、防御不能になる

- **期待を明文化せずにコードを書くと、バグではなく“未定義”が量産される**
- TDDは「何が期待されるか」をコードよりも先に言語化するため、**設計が意識的になる**

> ✔️ **Red（失敗）とは、仕様未満であることを意味する警報**である。

---

## 2. 実践例：Goで負の数を扱えない平方根関数をTDDで拡張

### 初期仕様（正の数のみ）

```go
// sqrt.go
package sqrt

import "math"

func Sqrt(n float64) float64 {
	return math.Sqrt(n)
}
```

```go
// sqrt_test.go
package sqrt

import "testing"

func TestSqrt_PositiveNumber(t *testing.T) {
	got := Sqrt(9)
	want := 3.0
	if got != want {
		t.Errorf("got %v, want %v", got, want)
	}
}
```

---

### 失敗するテストを書く（Red）

```go
func TestSqrt_NegativeNumber(t *testing.T) {
	defer func() {
		if r := recover(); r == nil {
			t.Errorf("expected panic on negative input")
		}
	}()
	Sqrt(-1)
}
```

実行結果：

```
--- FAIL: TestSqrt_NegativeNumber
    sqrt_test.go:...: expected panic on negative input
```

---

## 3. テストから見えてくる「設計の空白」

- 現時点の仕様では、負の数に対する振る舞いが未定義（math.SqrtはNaNを返す）
- **TDDは「仕様の抜け漏れ」をRedであぶり出す**
- ここで**「何を期待するか」＝「何をガードすべきか」**を定義する

---

## 4. Green – ガードを導入して通る実装に

```go
func Sqrt(n float64) float64 {
	if n < 0 {
		panic("negative input not allowed")
	}
	return math.Sqrt(n)
}
```

テスト結果：

```
✓ TestSqrt_PositiveNumber
✓ TestSqrt_NegativeNumber
```

---

## 5. Redは「バグ検知」ではなく「仕様強化」

### Redを書かなければ見逃されていたかもしれないもの

| 不具合の種 | 設計的ガード                     |
|------------|----------------------------------|
| nullや0除算 | 明示的に制御すべき入力           |
| 境界値     | テストを書くことで意識が向く     |
| 不正状態   | Redを先に書くことで構造が強化される |

---

## 設計判断フロー

```text
① この仕様に対して、失敗してほしいパターンはあるか？ → YES → Redを書く

② 書いたRedが、仕様として意味を持つか？ → YES → 実装に意味を与える

③ Redが通った後、実装に過剰なものが残っていないか？ → NO → Greenを最小化

④ 想定外の入力は、定義しておくべきか、黙殺するか？ → YES → テストで明示
```

---

## よくあるミスと対策

### ❌ 正常系しかテストを書かない

→ ✅ 仕様が単線化し、想定外の挙動を許容する  
→ 🔁 **Redで失敗系・境界系・例外系を先に書くことで、設計に幅が生まれる**

---

### ❌ Redを「ただ通すためだけ」の作業になる

→ ✅ **Redは「何を恐れているか」を意図として書く。思想を持った失敗を。**

---

## 結語

TDDにおける「Red」は、単なる失敗ではない。  
それは**“まだ満たされていない仕様がある”というシグナルであり、設計を先鋭化させる対話の起点”**である。

- 仕様の「抜け」は、Redによって炙り出される  
- 実装の「過剰」は、Greenによって抑制される  
- 構造の「曖昧さ」は、Refactorによって洗練される

**TDDとは、  
“仕様の不完全さをRedで照らし、進化するシステムの防壁を構築する戦略である。”**
TDD三原則と実践フロー：最小限のコードで、最大限の保証を得る戦略


## 概要

TDD（Test-Driven Development）には、**明文化された三原則**が存在する。  
これらは単なる「テストの手順」ではなく、  
**“設計の複雑性を制御し、進化に耐えるコードを書くための制約”**である。

本稿では、Ruby + RSpec による実践を通して、  
TDD三原則の意味と威力を構造的に掘り下げる。

---

## 1. TDD三原則とは何か

Kent Beck によって定義された以下の三原則がTDDのコアにある：

### 原則①：失敗するテストを書くまで、プロダクションコードを書いてはならない  
> → テストファースト。**何を満たすべきかを先に書く**

### 原則②：テストが失敗したら、それを通すためだけのコードを書く  
> → **最小限の実装**。余計な処理を先回りしない

### 原則③：重複を除去しながらリファクタする  
> → **動作を保ちつつ、設計を洗練させる**

---

## 2. 実践：TDDで文字列の回文判定関数を書く

### ステップ1：Red – 仕様を書く

```ruby
# palindrome_spec.rb
require './palindrome'

RSpec.describe '#palindrome?' do
  it 'returns true for "madam"' do
    expect(palindrome?('madam')).to eq true
  end
end
```

### ステップ2：Green – テストを通すためだけの実装

```ruby
# palindrome.rb
def palindrome?(str)
  true
end
```

- ✅ 原則②に則り、**最低限のコードでテストを通す**

---

### ステップ3：Red – もう1つの仕様を追加

```ruby
it 'returns false for "hello"' do
  expect(palindrome?('hello')).to eq false
end
```

### Green – 振る舞いを満たす実装

```ruby
def palindrome?(str)
  str == str.reverse
end
```

---

### ステップ4：Refactor – 冗長性を排除し構造を磨く

この例ではコードは既に簡潔だが、他のケースでは：
- 条件の共通化
- 変数抽出
- メソッドの分割
などを実施する。

---

## 3. 原則の力：なぜ「少しずつ」進めるのか

- 実装前に**期待（仕様）を明確化**することで、責務がシンプルになる
- 過剰設計を防ぎ、**“使われるコード”のみを書く**習慣がつく
- 小さなテストサイクルが、**信頼性と可読性を継続的に確保**

> 👉 三原則とは、「余計なことをしない」ための思考のフレームワーク

---

## 4. 三原則 × 設計改善のフロー

| ステップ      | 内容                               | 設計効果                     |
|---------------|------------------------------------|------------------------------|
| 🔴 Red        | 仕様を書く                         | 要求の明示                   |
| 🟢 Green      | 必要最低限でテストを通す           | 実装の最小化                 |
| 🔁 Refactor   | 動作を保ったまま改善する           | 構造の洗練・再利用性の向上   |

---

## 設計判断フロー

```text
① この処理に対してテストが書けるか？ → NO → 設計が不明確かもしれない

② テストのために多くの依存を作っていないか？ → YES → 責務が大きすぎる

③ 「仕様 → 実装 →改善」の順序が保たれているか？ → YES → 三原則通り

④ テストが書きやすい設計になっているか？ → YES → 結合が適切に制御されている
```

---

## よくあるミスと対策

### ❌ 先に実装を書き、後からテストを合わせる

→ ✅ テストは **設計そのものを定義する仕様書**。後付けでは本末転倒

---

### ❌ テストを通すために「一発で完璧な実装」をしようとする

→ ✅ Greenは「動けばよい」。**Refactorで設計する習慣**をつける

---

### ❌ テストケースが冗長で読みづらい

→ ✅ 共通化や条件の分離を**Refactorステップで整理**

---

## 結語

TDD三原則は、コードを書くためのルールではない。  
それは**“コードの意味と目的を明確にするための、思考と設計のリズム”**である。

- 最初に仕様を書く  
- それを通す最小限の実装を書く  
- 継続的に構造を洗練する

**TDDとは、  
“機能するコードではなく、意味を持つ構造をつくるための設計原則である。”**
なぜTDDは設計を改善するのか：関心の分離・依存の明示・責務の単純化


## 概要

TDD（Test-Driven Development）は、  
しばしば「品質向上のための手法」と誤解されるが、  
その本質は**“設計改善のプロセス”**にある。

本稿では、TDDが設計に与える影響を以下の3つの軸で構造的に分析する：

- **関心の分離（Separation of Concerns）**
- **依存の明示（Dependency Visibility）**
- **責務の単純化（Responsibility Isolation）**

Python + pytest を用いた実装例を交え、**「TDDを設計手法として捉える視点」**を提示する。

---

## 1. TDDがもたらす「関心の分離」

### ✅ テストファーストで始めると「副作用」と「ロジック」が分離される

```python
# app.py
def calculate_tax(price: float, rate: float) -> float:
    return price * rate
```

```python
# test_app.py
def test_calculate_tax():
    assert calculate_tax(100, 0.1) == 10.0
```

副作用（ログ、DBアクセス）を含まない**純粋ロジックだけ**を最初に作ることが可能になる。

> 👉 結果：UIやインフラ層と**ロジックの関心が分離される**

---

## 2. 「依存の明示」が設計を透明にする

テストを書く前提で設計すると、**隠れた依存（現在時刻、グローバル変数、DBなど）**が即座に浮かび上がる。

```python
# ❌ テスト不能：datetime.now() に依存
def should_send_email():
    return datetime.now().weekday() == 0
```

```python
# ✅ TDD設計：依存を注入
def should_send_email(today):
    return today.weekday() == 0
```

- TDDは依存の明示を強制し、**副作用の分離・DI設計**を促進する
- 結果として **Mockやスタブで差し替え可能な構造**が生まれる

---

## 3. 責務の単純化：関数が「一つのこと」だけをするようになる

TDDでは、**最小の期待（仕様）をテストで先に書く**ため、  
実装は必然的に「1つの責務」を持った関数・メソッドになる。

```python
def parse_email(text: str) -> str:
    # メールアドレスだけを抽出する（責務は1つ）
```

```python
def send_email(to: str, body: str):
    # 送信だけを行う（パースしない）
```

> ✅ 関数やクラスの「責任」が小さく明確になることで、再利用・保守性が高まる

---

## 4. 設計改善の実例：料金計算のTDDプロセス

### 要求

- 基本料金：500円
- 土日は20%割引

### テスト（Red）

```python
def test_weekday_charge():
    assert calc_charge('2024-04-01') == 500

def test_weekend_discount():
    assert calc_charge('2024-04-06') == 400
```

### 実装（Green）

```python
from datetime import datetime

def is_weekend(date_str: str) -> bool:
    day = datetime.strptime(date_str, '%Y-%m-%d').weekday()
    return day >= 5

def calc_charge(date_str: str) -> int:
    return 400 if is_weekend(date_str) else 500
```

### 設計効果（Refactor）

- `is_weekend` が分離され**関心の明確化**
- 料金計算ロジックは**1関数1責務**
- 日付依存は `str` で受け取り**テストしやすい構造**

---

## 設計判断フロー

```text
① ロジックと副作用が混在していないか？ → 分離すべき

② 外部依存（時間・ランダム・I/O）が埋め込まれていないか？ → 注入方式に

③ テストしづらい箇所があるか？ → それは設計の匂い（Smell）

④ 1つの関数に複数の責任がないか？ → TDDに従い分解する
```

---

## よくあるミスと対策

### ❌ TDDをやってもテストしづらいコードになる

→ ✅ **TDDは「テストを先に書く」だけではなく、設計改善が主目的であることを再認識**

---

### ❌ テストのために実装を「無理やり弄る」

→ ✅ **依存を明示・注入すれば、設計は自然にテスタブルになる**

---

### ❌ 結果的に1つの関数が肥大化

→ ✅ **テストケースが大きくなったら、それは分割のサイン**

---

## 結語

TDDがもたらす最大の恩恵は「テストがあること」ではない。  
それは**“設計がシンプルになり、進化に耐える構造になること”**である。

- 思考が仕様ベースになる  
- 関心が自然に分離される  
- 依存と副作用が明示され、構造が透明になる

**TDDとは、  
“テストを通して設計と責任の境界線を描き出す建築的プロセスである。”**
TDDとは何か：実装よりも先に「仕様」を書くという開発スタイル

## 概要

TDD（Test-Driven Development）とは、  
**「コードを書き始める前に、そのコードが満たすべき仕様（テスト）を書く」**という開発手法である。

この手法の本質は「テストを書く」ことではなく、  
**“思考を仕様ベースで始める”**ことにある。

本稿では、TDDの思想・流れ・メリットと、Vitest＋TypeScriptを用いた最小構成での実践例を交えながら、  
**「なぜTDDが設計を変えるのか」**を構造的に解き明かす。

---

## 1. TDDとは何か：定義と誤解

TDDは「テストを書いてから実装する」という説明では足りない。  
本質は以下の3つの原則にある：

- 🔴 **Red**：失敗するテストを書く（仕様を書く）
- 🟢 **Green**：テストが通る最小限のコードを書く
- 🛠️ **Refactor**：構造を改善し、意味を保つ

> 実装駆動ではなく、**仕様駆動**であることがTDDの根幹にある。

---

## 2. なぜTDDは「先にテストを書く」のか

- 実装より先に「何を期待するか」が明確になる  
- コードが過剰に書かれず、最小限で済む  
- 依存や外部要因を先に意識できるため、疎結合な設計になる

> テストは「品質保証」ではなく、**「設計プロンプト」**である

---

## 3. 実践：TDDでFizzBuzzを設計する（TypeScript + Vitest）

```bash
npm create vite@latest tdd-fizzbuzz --template vanilla-ts
cd tdd-fizzbuzz
npm i
npm i -D vitest
```

### `src/fizzbuzz.ts`（まだ空）

```ts
// 空の実装（Green前）
```

### `src/fizzbuzz.test.ts`

```ts
import { describe, expect, it } from 'vitest';
import { fizzbuzz } from './fizzbuzz';

describe('fizzbuzz', () => {
  it('returns number for non-multiples of 3 or 5', () => {
    expect(fizzbuzz(1)).toBe('1');
  });
});
```

### Red：テストが失敗する

```
ReferenceError: fizzbuzz is not defined
```

---

### Green：最小限の実装を書く

```ts
export function fizzbuzz(n: number): string {
  return String(n);
}
```

再度テスト：

```
✓ returns number for non-multiples of 3 or 5
```

---

### Red → Green → 次の仕様を追加

```ts
it('returns Fizz for multiples of 3', () => {
  expect(fizzbuzz(3)).toBe('Fizz');
});

it('returns Buzz for multiples of 5', () => {
  expect(fizzbuzz(5)).toBe('Buzz');
});

it('returns FizzBuzz for multiples of 15', () => {
  expect(fizzbuzz(15)).toBe('FizzBuzz');
});
```

---

### Green：拡張された実装でテストを通す

```ts
export function fizzbuzz(n: number): string {
  if (n % 15 === 0) return 'FizzBuzz';
  if (n % 3 === 0) return 'Fizz';
  if (n % 5 === 0) return 'Buzz';
  return String(n);
}
```

---

### Refactor：構造を洗練させる

- 条件分岐の順序を整理
- 再利用可能な条件チェッカーを抽出可能

---

## 4. 設計観点から見るTDDの本質

- 🔍 **仕様が明確になることで、設計がシンプルになる**  
- 🧩 **依存を隔離しやすく、モジュール単位の責務が明確になる**  
- 🚦 **Red→Greenの明快なフィードバックが、設計の正しさを保証する**

> 実装は「仕様を通すための必要最小限の部品」になる。

---

## 5. TDDが破壊する3つの常識

| 従来の思考                 | TDD的思考                             |
|----------------------------|----------------------------------------|
| コード → テスト            | テスト → コード                       |
| 実装のために考える         | 期待される振る舞いから設計する       |
| UIやAPIをまず作る          | 使用者視点の仕様から導入する         |

---

## 結語

TDDは「実装をテストする」手法ではない。  
それは**“実装されるべき仕様を明示し、それにコードを従わせる構造的思考法”**である。

- 仕様を書くことで、設計が始まる  
- 実装は仕様を満たす最小限にする  
- テストは「確認」ではなく、「設計のトリガー」として機能する

**TDDとは、  
“コードを書き始める前に「何を保証したいか」を思考し、実装を仕様に従属させるための知的戦略である。”**
JavaScriptにおける非同期制御の設計戦略：Promise, async/await, AbortControllerの実用指針


## 概要

JavaScriptは**非同期を本質に持つ言語**である。  
イベントループ、非同期I/O、UI描画の最適化など、  
その基盤は「同期的に見える非同期制御」に支えられている。

本稿では、**非同期処理の設計におけるPromise / async/await / AbortControllerの役割と、それらを組み合わせた制御戦略**を提示する。  
単なる文法ではなく、**「どう制御するか」「どう失敗させるか」「どう管理するか」**の視点で解説していく。

---

## 1. Promise設計の基本と型構造

```ts
function fetchData() {
  return new Promise((resolve, reject) => {
    setTimeout(() => resolve('data'), 1000);
  });
}
```

- ✅ Promiseは「状態管理オブジェクト」：**pending → fulfilled / rejected**
- ✅ 複数ステップをthenチェーンで接続可能
- ❌ 可読性が低下しやすく、エラーハンドリングが錯綜しやすい

---

## 2. async/awaitによる同期的表現

```ts
async function loadData() {
  try {
    const data = await fetchData();
    console.log(data);
  } catch (e) {
    console.error('Failed:', e);
  }
}
```

- ✅ **Promiseの状態を同期的に待つ**構文 → コードの線形性が向上
- ✅ `try/catch` によるエラー制御が可能
- ✅ Promiseとの互換性を維持しつつ、**コードの明瞭さが増す**

---

## 3. AbortControllerによるキャンセル可能な非同期制御

```ts
const controller = new AbortController();
fetch('/api/data', { signal: controller.signal });

// キャンセル
controller.abort();
```

- ✅ `fetch` を中断可能にする標準機能
- ✅ UIイベントやルーティング変更時の **非同期キャンセル** に有効
- ✅ `AbortError` による専用のハンドリングが必要

```ts
try {
  const res = await fetch(url, { signal });
} catch (e) {
  if (e.name === 'AbortError') {
    // 明示的なキャンセル
  } else {
    throw e;
  }
}
```

---

## 4. 非同期エラー設計と再試行戦略

```ts
async function withRetry(fn, retries = 3) {
  for (let i = 0; i < retries; i++) {
    try {
      return await fn();
    } catch (e) {
      if (i === retries - 1) throw e;
    }
  }
}
```

- ✅ **一時的な障害（ネットワーク、API制限）**に耐性を持たせる
- ✅ 非同期処理には**失敗を前提とした制御構造**が必要

---

## 5. 非同期の構造化と可視性の確保

### モジュールで切り出す

```ts
// userService.ts
export async function getUser(id: string, signal?: AbortSignal) {
  const res = await fetch(`/api/users/${id}`, { signal });
  if (!res.ok) throw new Error('Fetch failed');
  return await res.json();
}
```

### UI側で制御

```ts
const controller = new AbortController();
getUser('123', controller.signal)
  .then(renderUser)
  .catch(handleError);
```

- ✅ 非同期関数は**明確な責務でモジュール化**
- ✅ UI側で**キャンセル、タイムアウト、再試行**を統括

---

## 設計判断フロー

```text
① 非同期処理はPromiseであるべきか？ → YES → then / async/await に展開

② 処理の順序性が重要か？ → async/await で明示

③ ユーザー操作で中断する必要があるか？ → AbortControllerを導入

④ エラーは想定されるか？ → try/catch + 専用ハンドラ設計

⑤ 再試行・リカバリが必要か？ → withRetry等の高階関数で制御
```

---

## よくあるミスと対策

### ❌ 非同期処理をtry/catchで囲っていない

→ ✅ **async関数内では常にcatchを意識した構造にする**

---

### ❌ キャンセルできないfetchを多数同時発火

→ ✅ **AbortControllerで外部制御可能に設計**

---

### ❌ UIコンポーネントがアンマウント後にawaitが残ってエラー

→ ✅ `useEffect` + `isMounted` or `AbortController` で**終了制御**

---

## 結語

非同期制御は「待つ」だけではない。  
それは**“実行の責任とタイミングを設計し、失敗を制御可能にする戦略”**である。

- async/await で直感的に順序を表現  
- AbortController でキャンセル性を持たせる  
- 高階関数で再試行やタイムアウト制御を汎用化  
- 非同期処理は責務を分離し、構造的に管理する

**JavaScriptにおける非同期制御とは、  
“動的で不確実なプロセスを予測可能に設計し、ユーザー体験と安定性を支えるアーキテクチャ戦略である。”**