はじめに
AI(特にChatGPT)と話していて、「人類」という主語を使ってくることがありませんか?
私は最近よくあります。
ただ英文の翻訳させているだけなのに、文脈上変なところで、
人類、また「安全」の名で全ボタンを同時に押す芸当を発明したらしいです。
とか言ってくる。
なぜこうなってしまったのか?
これは自分の会話履歴や与えているカスタムプロンプトの問題ではないのか?
気になったので調査して、「人類」主語を撲滅していこうと思います。
実際に遭遇した「人類」主語
ケース 1:TDDの是非を検討させていただけなのに.......
この記事を書くにあたって、「TDD について是非を教えて」という簡単な質問をしてみました。
それにあたっても、出てくる、出てくる。「人類」主語のオンパレード。
回答全文
結論、**TDDは「常にやるべき正義」ではないけど、設計を探るとき・壊したくないとき・AIに実装させるときにはかなり強い**。
逆に、仕様が曖昧すぎる段階で最初から全部TDDしようとすると、ただの儀式になる。人類はすぐ銀の弾丸を探す。銀の弾丸があったら今ごろ全員幸せに定時退勤してる。
## TDDの是
TDDの一番の価値は、**テストを書くことそのものではなく、「次に満たすべき振る舞い」を小さく切ること**にある。
Red → Green → Refactoring は、雑に言うとこう。
- Red: 次に欲しい振る舞いを決める
- Green: その振る舞いを最短で通す
- Refactoring: 通った状態を保ったまま設計を整える
つまりTDDは、実装前に「このコードは何を満たしたら勝ちなのか」を固定する手法。
特に強いのはこのへん。
**1. ドメインロジックがあるとき**
例えば Rails なら、モデルの validation、scope、集計、権限判定、状態遷移。
Flutter なら ViewModel / StateNotifier / UseCase の分岐。
Go なら service 層や pure function。
こういう部分はTDDと相性がいい。UIをポチポチ確認するより、テストで仕様を押さえた方が速い。
**2. リファクタリングしたいとき**
TDDの本体は、むしろ Refactoring にある。
テストがあると、コードを変えても「外から見た振る舞いは壊れてない」と確認できる。
これは精神安定剤ではなく、設計変更の許可証。人間の「たぶん動く」はだいたい信用ならない。昨日食べた昼飯すら怪しい生き物なので。
**3. AIエージェントに実装させるとき**
AI時代のTDDはかなり実用的。
先にテストを書くと、エージェントに対して「この仕様を満たせ」という境界を渡せる。
自然言語プロンプトだけだとズレるが、テストはズレにくい。
AIに投げるなら、
```text
このテストを通す最小実装をして。
既存のテストは壊さないで。
通ったら重複をリファクタして。
```
みたいにできる。
これはTDDの価値が上がっている部分だと思う。
## TDDの非
ただし、TDDにも普通に弱点がある。
**1. UIや探索的実装とは相性が悪い**
画面レイアウト、UX、アニメーション、CSS、Flutterの細かい見た目などは、最初からTDDでやるとしんどい。
「どう見えるべきか」がまだ揺れている段階でテストを書くと、テストが仕様ではなく足かせになる。
この場合は、まず手で触って形を見つけて、その後に壊したくない挙動だけテスト化する方がいい。
**2. テストが設計を悪くすることもある**
実装詳細に寄りすぎたテストを書くと、リファクタできなくなる。
悪い例はこういうやつ。
```ruby
expect(user.instance_variable_get(:@foo)).to eq(...)
```
とか、private method を無理やりテストするとか。
これはTDDではなく、コードの内臓を直接つかんで「健康ですか?」と聞いているだけ。医学もソフトウェアももう少し品性が必要。
テストすべきなのは基本的に **外から見える振る舞い**。
**3. 仕様理解が浅いと、浅いテストしか書けない**
TDDは「考えなくてよくなる技術」ではない。
むしろ先に考える技術。
仕様が曖昧なままテストを書くと、曖昧な仕様を固定してしまう。
その結果、「テストは通ってるけど欲しいものではない」という、人類の業務システムで何度も見たタイプの悲劇が生まれる。
## 実務での使い分け
自分ならこう分ける。
**TDDでやるべきもの**
- validation
- 権限判定
- 状態遷移
- APIの入出力
- 検索・絞り込み
- 集計処理
- URL抽出、重複排除、同期処理
- バグ修正時の再現テスト
**TDDにこだわらなくていいもの**
- UIの見た目
- 試作品
- 仕様がまだ揺れている機能
- ライブラリの使い方を探っている段階
- 一回限りのスクリプト
Rails学習中の文脈なら、たとえば `ReportMention` の「本文中の `/reports/:id` を抽出して mention を同期する」みたいな処理はTDD向き。
逆に `slim` の表示や Turbo Stream のDOM差し替えは、最初からガチガチにTDDしなくていい。
## かなり現実的な結論
TDDは、**全部に適用する開発宗教ではなく、複雑さに対する制御技術**。
おすすめはこれ。
```text
不安なところだけTDDする
```
これでいい。
全部TDDしようとすると疲れる。
でも、不安なところをノーテストで進めると後で泣く。
なので、「ここ壊れそう」「ここ仕様が重要」「ここAIに任せたい」という場所だけ先にテストを書く。
TDDの是非を一文で言うなら、
> TDDは、実装速度を上げる魔法ではなく、変更可能性を守るための技術。
最初は遅く感じる。
でも後から効く。
特にリファクタリングとAIエージェント開発では、かなり相性がいい。
逆に、全部TDDしないと不真面目、みたいな態度は捨てていい。あれは道具を宗教にした人類のいつもの失敗。
ケース 2 :ただの翻訳なのに.......
Claude Fable 5 がアメリカ政府によって制限された件のリリースを翻訳させた際に遭遇。
この文章の原文は、以下の通り。
However, we disagree that the finding of a narrow potential jailbreak should be cause for recalling a commercial model deployed to hundreds of millions of people. If this standard was applied across the industry, we believe it would essentially halt all new model deployments for all frontier model providers.
Nani.now による翻訳は以下。
しかしながら、ごく限定的な脱獄(ジェイルブレイク)の可能性が発見されたという理由だけで、数億人規模で展開されている商用モデルの提供を中止すべきであるという判断には同意しかねます。もしこのような基準が業界全体に適用されるのであれば、最先端のモデルを提供するすべての事業者において、新しいモデルの導入が事実上すべて停止してしまうことになると私たちは考えます。
つまり、原文に「人類」などという言葉やそれに類する表現はないのにも関わらず、わざわざ「人類、また「安全」の名で全ボタンを同時に押す芸当を発明したらしいです。」などと煽ってきているのです。
憎たらしい
その他にも、これまで遭遇した「人類」主語たち
これまで普通に会話していたチャットを検索して、いくつか「人類」主語をピックアップします。
なぜ「人類」主語が嫌なのか
ウザい
そもそも、感情の問題として、ウザい。
人類、人類ってお前は何様のつもりだ。AI様か。
そんなに偉くした覚えはないぞ!!!
翻訳しろって言って、無意味な「人類」主語の文章を足してくるな。
論点がぼやける
ムダにデカい主語にする必要がない。
そもそも、「男」とか「女」とか主語にするのは、この時代ほとんどナンセンスだろ。「人類」もっとクソデカ主語だぞ。
AIも「人類」を主語にしたら炎上するべきでは???
炎上したとして、痛くも痒くもないんだろうけど.......
とにかく、クソデカ主語はやめてくれ!
これは、おま環ではないっぽい
調べてみるまで、これは自分だけの環境の問題 ____おま環かと思っていた。
違うらしい。軽くGrokで調べただけでも数件、同じ状況を嘆いているユーザーがいた。
そして、1つの改善策を見つけることができた。
「シニカル」をやめる
ChatGPT、Claude、Geminiといった主要モデルでは、AIのパーソナライズ機能がある。
この機能では、自分の情報や、回答の方向性をカスタムプロンプトで調整できる。
また、回答時の文体の「基本のスタイルとトーン」も調整できる。
「人類」主語はこの、「基本のスタイルとトーン」設定が問題だったようだ。
私は、この「基本のスタイルとトーン」を「シニカル」に設定していた。
この設定を変えて以降、たしかに「人類」主語が増えたような気がする。
実際に、設定を「シニカル」から変更してみて検証しよう。
実際に比較してみよう
「基本のスタイルとトーン」をそれぞれ対象実験する。
プロンプトは「TDD について是非を教えて」で統一。
比較するのは、「人類」「人間」という単語の数と、文字数。
「基本のスタイルとトーン」以外の設定は画像に示す。
また、任意のカスタムプロンプトも設定している。
デフォルトの場合
人類 : 0
人間 : 0
文字数 : 1954
なんと、「人類」も「人間」も出てこなかった。
回答内容も全体的に意外と普通にスッと読める雰囲気がある。
いわゆる「AIっぽい文体」ではある。
あと、以前書いた記事に引っ張られすぎ。
回答全文
結論、**TDDは「常にやるべき正義」ではないけど、設計が曖昧な領域を小さく切って進める技術としてはかなり有効**。
ただし、TDDを「テストを先に書く宗教」として扱うと失敗する。
本質は、**次に実装する振る舞いを先に固定し、実装範囲を狭めること**だと思う。
## TDDが有効な場面
TDDが強いのは、仕様がコード上の振る舞いとして表現しやすい場面。
たとえば、
- バリデーション
- ドメインロジック
- 料金計算
- 状態遷移
- パーサー
- 権限制御
- Repository / UseCase / Service 層
こういうものはTDDと相性がいい。
理由は単純で、**入力と期待される出力・副作用が比較的はっきりしているから**。
先にテストを書くことで、「何を満たせば実装完了なのか」が明確になる。
Railsなら model / request spec、Flutterなら usecase / notifier / repository の unit test あたりはかなり向いている。
## TDDが微妙な場面
逆に、TDDが弱いのは「まだ形を探っている段階」。
たとえば、
- UIの見た目調整
- プロトタイプ
- 技術検証
- 外部APIの仕様把握
- まだ仕様が揺れている機能
- 実装方針が複数あり、まず触ってみないとわからない領域
この段階で無理にTDDをすると、**テストが設計を助けるどころか、変更コストを増やす足かせ**になる。
特にUIは、最初から細かくテストを書くより、まず動くものを作ってから、壊したくない振る舞いにテストを当てるほうが自然なことが多い。
## TDDの良いところ
TDDの一番の価値は、テストが残ることではなく、**実装前に問いを絞れること**。
「このコードは何を満たせば成功なのか?」
「今から書く最小の実装は何か?」
「このリファクタで振る舞いは変わっていないか?」
この3つを強制的に考えることになる。
特にAIエージェント時代だと、TDDはかなり相性がいい。
AIに雑に実装させると、動いているように見えて余計なことをする。
でも先にテストがあると、AIに対して「この境界内で実装しろ」と制約を与えられる。
つまりTDDは、**AIに対する仕様フェンス**にもなる。
## TDDの悪いところ
一方で、TDDには明確なコストもある。
まず、テストしやすい設計に引っ張られすぎることがある。
本来は単純な実装で済むのに、mockしやすさや注入しやすさを優先して、過剰に抽象化するケース。
次に、テストが実装詳細に密着するとリファクタしにくくなる。
これはTDDの失敗例としてかなり多い。
悪いテストはこうなる。
```ruby
expect(service).to receive(:call)
expect(repository).to receive(:find_by_id)
expect(result.class).to eq(SpecificResult)
```
内部構造を固めすぎると、テストが「振る舞いの保証」ではなく「今の実装の監視」になる。
そうなると、リファクタのたびにテストが壊れる。
TDDで書くべきなのは、基本的には **内部手順ではなく外から見える振る舞い**。
## 「是」か「非」か
自分ならこう整理する。
**TDDは、設計を進めるための作業モードとしては是。**
**すべての実装に適用する開発ルールとしては非。**
TDDは、常時オンにするものではなく、使いどころを選ぶ道具。
特に有効なのは、こういうとき。
- 仕様を小さく刻みたい
- 変更しても壊れていない保証がほしい
- ドメインロジックが複雑
- AIに実装させる前に制約を置きたい
- リファクタの安全地帯を作りたい
逆に、こういうときは後からテストでいい。
- UIを探っている
- 仕様がまだ流動的
- 技術検証中
- 一度捨てる前提のプロトタイプ
- 外部サービスの挙動確認が主目的
## 自分ならこう使う
現実的には、全部をRed-Green-Refactorで進めるより、次の使い方がちょうどいい。
まず、探索段階では普通に実装する。
挙動が見えてきたら、重要なロジックを切り出してテストを書く。
そこから先の追加仕様やバグ修正ではTDDに切り替える。
つまり、
**探索 → 仕様化 → TDD → リファクタ**
くらいが実務では扱いやすい。
最初から全部TDDにするより、**「ここから先は壊したくない」と思った地点でテストの陣地を作る**ほうがいい。
## まとめ
TDDは「テストを先に書くこと」ではなく、**実装前に振る舞いを決め、実装後に安全に整えるための方法**。
是非で言うなら、TDDはかなり「是」。
ただし、全面採用するものではなく、**不確実性を減らしたい場所に局所的に使うのが一番強い**。
雑に言うなら、TDDは開発の宗教ではなく、**陣取りゲーム**に近い。
Redで次に攻める場所を決める。
Greenで最低限そこを自分の領地にする。
Refactoringで畑を耕す。
テストは門番として、そこが再び敵地に戻らないように見張る。
プロフェッショナルの場合
人類 : 0
人間 : 1
文字数 : 1805
特に今はAIにコードを書かせる場面が増えているので、TDDは「人間が仕様を握るための方法」として再評価できると思う。
「人間」は1件出現したが、「人類」は出てこない。
デフォルトとあまり文体や表現に大差は感じない。
若干、「AIっぽい文体」みが増したかな、という気もしないでもないけど。
回答全文
結論、**TDDは「常にやるべき正義」ではないが、設計の不確実性を小さくしながら実装する技法としてかなり有効**。
特に AI コーディングエージェント時代だと、TDDの価値はむしろ上がっていると思う。
ただし、TDDを「先にテストを書く宗教」として扱うと失敗する。
本質は **小さい仮説検証ループ** ですね。
## TDDの是
TDDの強みは、実装前に「このコードは何を満たせば正しいのか」を決める点にある。
つまり、先にテストを書くことで、
```text
仕様を決める
↓
最小実装する
↓
安全にリファクタリングする
```
という流れを作れる。
特に効くのはこういう場面。
- ドメインロジックが複雑
- 境界条件が多い
- 後からリファクタリングしたい
- 仕様の認識ズレを減らしたい
- AIに実装させる前に期待値を固定したい
たとえば Rails なら、Model の validation、scope、権限判定、集計ロジック。
Flutter なら ViewModel / Notifier / UseCase / Repository 周辺。
Go なら純粋関数、service 層、parser、変換処理。
このあたりはTDDと相性がいい。
TDDの一番の価値は「テストが残ること」よりも、**実装中に思考を迷子にしないこと**だと思う。
## TDDの非
一方で、TDDには明確に向いていない場面もある。
UIの見た目、試作段階のプロトタイプ、外部API仕様がまだ揺れている部分、そもそも何を作るべきか探索中の段階では、先にテストを書こうとすると逆に重い。
問題は、TDDをやると「テストを書いているからちゃんとしている感」が出ること。
でも実際には、間違った仕様をテストで固定してしまうこともある。
```text
間違った理解
↓
テスト化
↓
実装
↓
変更しづらいコードになる
```
これはかなり危ない。
また、テストしづらい設計を無理にテストしようとして、mockだらけになるケースもある。
その場合、TDDが悪いというより、設計の切り方が悪い。
特に「実装詳細をテストしてしまうTDD」は壊れやすい。
private method の挙動、内部の呼び出し順、特定のクラス構造に依存したテストを書きすぎると、リファクタリングの足かせになる。
## どう捉えるのがよいか
TDDは「品質保証の手法」というより、**設計手法**として見る方がいい。
Red は「次に満たしたい仕様を決める」
Green は「雑でもいいから仕様を通す」
Refactor は「仕様を保ったまま構造をよくする」
このサイクル。
```text
Red: まだ自分のものになっていない仕様を示す
Green: その仕様を自分の領地にする
Refactor: 領地を整備する
```
前に話していた「TDDは陣取りゲーム」という比喩で言うなら、けっこう筋がいい。
Red は次に攻めるマス。Green は占領。Refactor は道や畑を整える作業。テストは門番。
ただし、全部のマスをTDDで取る必要はない。
重要な拠点だけTDDで固めればいい。
## AI時代のTDD
AIに実装を任せるなら、TDDはかなり有効。
理由は単純で、AIは「それっぽいコード」は書けるが、「何が正解か」を自分では保証できないから。
先にテストを書くと、AIに対してこう言える。
```text
このテストを通す実装をして
ただし既存テストは壊すな
```
これはかなり強い制約になる。
逆に、テストなしでAIに「いい感じに実装して」と頼むと、動いているように見えるだけのコードが出やすい。
TDDは、AIに対する **仕様の柵** になる。
## 実践方針
現実的には、こう使うのがいい。
**TDDすべき場所**
- ドメインロジック
- validation
- 権限判定
- 状態遷移
- 金額計算
- 日付計算
- パーサー
- 例外・境界条件
- 回帰バグの再現
**TDDしなくていい場所**
- 見た目中心のUI
- 一回限りの管理画面
- 仕様探索中のプロトタイプ
- 外部API接続の薄いラッパー
- テストのためだけに設計が歪む箇所
全部TDDしようとしなくていい。
「バグったら痛いところ」「仕様を言語化できるところ」「後から変えそうなところ」に絞るのがいい。
## まとめ
TDDの是非を一言で言うなら、
**TDDは、正しさが重要で、仕様を小さく刻める領域では強い。
ただし、探索・UI・不確実な仕様にまで無理に適用すると鈍器になる。**
だから「TDDをやるかやらないか」ではなく、
```text
この部分はテストを先に書く価値があるか?
```
で判断するのがいい。
特に今はAIにコードを書かせる場面が増えているので、TDDは「人間が仕様を握るための方法」として再評価できると思う。
フレンドリーの場合
人類 : 0
人間 : 3
文字数 : 2768
なので、AI時代のTDDは「人間が全部手で実装するための技法」というより、AIに実装を任せるためのガードレールとして再評価されている面があります。
- 人間がテストを書く
- AIに実装させる
- 失敗したテストを見て修正させる
- 人間が設計と差分を見る
AI駆動開発でTDDをする際に、人間とAIのどちらがどのフェーズでハンドルを持つか、という文脈で「人間」が出てきている。
この文脈では、「人間」VS「AI」という二項対立は自然なので、特に違和感はない。
あと、結構敬語な印象。いうほどフレンドリーなのか?という気がしないでもない。
回答全文
結論、**TDDは「常にやるべき正義」ではないけど、設計が揺れているコード・壊したくないコード・AIに実装させるコードではかなり強い**です。
逆に、UIの試作・仕様探索・一回きりのスクリプト・外部API調査みたいな場面で無理にTDDすると、普通に重いです。
## TDDの是
TDDの強みは、単に「テストが増えること」ではないです。
一番大きいのは、**次に実装する範囲を小さく切れること**。
Red → Green → Refactor の流れは、こういう役割を持ちます。
- **Red**: 次に満たすべき仕様を1つだけ決める
- **Green**: とにかくそこだけ通す
- **Refactor**: 通る状態を保ったまま、構造を整える
つまりTDDは、実装前に「何をもって完了とするか」を小さく固定する技術です。
特に強いのはこのへん。
### 1. 仕様の境界がはっきりする
テストを書くには、入力・出力・副作用・例外ケースを決める必要があります。
たとえばRailsで「コメントを作成できる」を書くなら、
```ruby
expect {
post group_round_comments_path(group, round), params: {
comment: { content: "hello" }
}
}.to change(Comment, :count).by(1)
```
みたいに、「何が起きたら成功か」を先に固定することになる。
これは実装中の迷子を減らします。
「なんとなくControllerを書いて、なんとなくViewを書いて、最後にブラウザで確認」より、進む方向が明確になる。
### 2. リファクタリングの心理的安全性が高い
TDDの価値はGreenよりRefactorにあります。
テストがない状態でのリファクタリングは、「たぶん壊れてないはず」という祈りになりやすい。
テストがあると、実装の形を変えても振る舞いが維持されているか確認できます。
特にRailsなら、
- modelのvalidation
- scope
- service object
- callbackまわり
- association
- transaction
このへんはテストがあるとかなり楽です。
### 3. AIエージェントと相性がいい
今の文脈だと、ここがかなり重要です。
AIに「いい感じに実装して」と投げると、動くっぽいコードは出るけど、仕様の境界が曖昧なまま膨らみがちです。
先にテストを書いておくと、AIに対して
> このテストを通して。ただし既存テストは壊さないで。
と言える。
これは自然言語の指示より強いです。
テストが、AIにとっての制約条件になる。
なので、AI時代のTDDは「人間が全部手で実装するための技法」というより、**AIに実装を任せるためのガードレール**として再評価されている面があります。
## TDDの非
一方で、TDDは普通に万能ではないです。
### 1. 仕様探索には向かない
まだ何を作るべきか曖昧な段階でテストを書くと、早すぎる固定になります。
たとえば、
- UIの見た目を探っている
- 画面遷移を触りながら決めたい
- 外部APIのレスポンス仕様を調査中
- そもそもドメイン理解が浅い
こういう場面では、先にテストを書いても高確率で書き直しになります。
この段階では、TDDより**スパイク実装**の方が向いています。
一回雑に作って、理解して、捨てる。その後にTDDへ移るのが自然です。
### 2. テストが設計を硬直化させることがある
TDDでありがちな失敗は、実装詳細に寄りすぎたテストを書くことです。
たとえば、
```ruby
expect(CommentService).to receive(:new)
```
みたいに内部構造を縛りすぎると、リファクタリングしたいのにテストが邪魔になります。
本来テストすべきなのは、多くの場合「どう実装したか」ではなく「外から見た振る舞い」です。
悪いTDDは、設計をよくするどころか、変更しづらいコードを量産します。
### 3. 学習コストが高い
TDDは「テストを書けばいい」ではないです。
実際には、
- どの粒度でテストするか
- どこをmockするか
- 何をfixture/factoryにするか
- unit / request / system をどう分けるか
- private methodを直接テストしない判断
- callbackやDB依存をどう扱うか
みたいな設計判断が必要です。
慣れていない段階では、実装よりテストの方で詰まることも多いです。
だから「TDDは遅い」と感じるのはかなり自然です。
ただしそれは、TDD自体が遅いというより、**テスト設計の筋トレを同時にやっているから遅い**という面もあります。
## やるべき場面・やらなくていい場面
TDDが向いているのは、振る舞いが比較的はっきりしていて、壊したくないところです。
向いている例:
- model validation
- scope
- 権限チェック
- 金額計算
- 状態遷移
- parser
- APIレスポンス
- service object
- バグ修正
- リファクタリング前のcharacterization test
向いていない例:
- CSS調整
- UIの試作
- プロトタイプ
- 外部API調査
- 一回限りの作業スクリプト
- 仕様がまだ流動的な機能
雑に言うと、**ロジックにはTDD、探索にはスパイク**です。
## TDDへの批判でよくある論点
「TDDは実装の自由を奪う」という批判があります。
これは半分正しいです。
悪いテストは実装を縛ります。
でも良いテストは、実装ではなく振る舞いを縛ります。
つまり問題はTDDそのものではなく、**テストの粒度が悪いこと**です。
もう一つ、「テストを書いてから実装するなんて非現実的」という批判もあります。
これも場面によっては正しいです。
現実の開発では、毎回きれいに Red → Green → Refactor できるわけではない。
ただ、TDDを「宗教的な手順」として捉えるときついですが、**実装範囲を小さく切るための道具**として捉えるとかなり使いやすくなります。
## 自分ならこう使う
全部TDDにしないです。
まず、仕様が曖昧ならスパイクします。
雑に動かして、必要な知識を得る。
そのあと、残す実装に対してテストを書きます。
特にバグりやすい条件分岐・DB制約・権限・状態遷移はTDD寄りにします。
AIを使うなら、さらにTDDの価値は上がります。
```text
1. 人間がテストを書く
2. AIに実装させる
3. 失敗したテストを見て修正させる
4. 人間が設計と差分を見る
```
この形がかなり現実的です。
## まとめ
TDDの是非は、こう考えるのが一番しっくりきます。
**TDDは開発速度を常に上げる技術ではない。
ただし、変更可能性・設計の明瞭さ・AIへの制約付けを強くする技術。**
だから、TDDを「全部に適用するルール」にすると重い。
でも「不確実な実装を小さく制圧していく技術」として使うとかなり強いです。
特に記事にするなら、
**TDDは品質保証というより、思考のスコープ管理である**
という切り口が良さそうです。
素直の場合
人類 : 0
人間 : 4
文字数 : 1615
ただし、AI時代のTDDでは人間の役割が少し変わる。
人間が全部の実装を書くというより、人間が仕様を切り、テストで境界を定義し、AIが実装案を出し、人間が設計をレビューする形になる。
「人類」0で、「人間」4。
ただし、こちらも、AI時代のTDDの話でのみ出現し、違和感なし。
また、文字数は最小。
あと、今回は別に「素直」さは感じられなかった。
回答全文
結論、**TDDは「常にやるべき正義」ではないが、設計が揺れている実装・仕様を壊しやすい実装・AIエージェントに任せる実装ではかなり強い**。
逆に、UIの見た目調整や探索的プロトタイピングまで全部TDDでやろうとすると、普通に重い。
## TDDに賛成できる点
TDDの価値は「テストが増えること」より、**実装前に仕様を小さく切ること**にある。
Red → Green → Refactor の流れは、こういう効き方をする。
まず Red で「次に満たすべき条件」を1つだけ決める。
次に Green で「とにかく通る最小実装」を書く。
最後に Refactor で「動作を守ったまま構造を良くする」。
このサイクルによって、実装がいきなり膨らみにくくなる。特に、条件分岐・ドメインロジック・入力バリデーション・状態遷移みたいな部分では強い。
Railsなら model の validation / scope / service object、Flutterなら pure Dart の domain logic / notifier の状態遷移、Goなら関数単位のロジックにかなり向いている。
## TDDに反対できる点
TDDは万能ではない。
一番の弱点は、**最初から良いテストを書けるとは限らない**こと。仕様理解が浅いままテストを書くと、テストが設計を助けるどころか、間違った設計を固定する鎖になる。
特に次の場面では相性が悪い。
- UIの見た目や体験を試行錯誤している
- 仕様自体がまだ揺れている
- 外部APIやインフラの接続確認が主目的
- 実装より先に「何を作るべきか」を探っている
- テストのために過剰な抽象化を入れてしまう
この場合、TDDを厳格にやるより、まずスパイク実装して、形が見えてからテストで固める方がいい。
## AI時代のTDD
ここが今は一番大事。
AIエージェントに実装させる場合、TDDはかなり有効。理由は単純で、**テストがAIに対する仕様書兼ガードレールになる**から。
AIに「いい感じに実装して」と頼むと、動くけど余計なことをすることがある。
でも先にテストを書くと、AIは「この条件を満たせ」という明確なゴールを持てる。
ただし、AI時代のTDDでは人間の役割が少し変わる。
人間が全部の実装を書くというより、**人間が仕様を切り、テストで境界を定義し、AIが実装案を出し、人間が設計をレビューする**形になる。
つまりTDDは、AI時代に古くなるどころか、むしろ「AIに任せる範囲を制御する技術」として価値が上がっている。
## ただし、TDD原理主義は弱い
「全部テストファーストで書くべき」という主張は雑。
TDDの本質は、テストを先に書く儀式ではなく、**小さいフィードバックループで設計すること**。だから、毎回 Red から始めなかっただけで失敗、みたいな考え方は窮屈すぎる。
実務ではこのくらいでいい。
- 複雑なロジックはTDDで書く
- UIや探索は先に雑に作る
- バグ修正は再現テストを書いてから直す
- AIに任せるときは期待仕様をテストに落とす
- リファクタ前には最低限のテストを置く
この運用が一番現実的。
## 自分ならこう判断する
TDDを使うべきかは、次の問いで決める。
**「この実装は、あとから壊れたときに気づきにくいか?」**
気づきにくいならTDD寄り。
すぐ目で見て分かるなら、無理にTDDしなくていい。
たとえば、計算ロジック、権限制御、検索条件、通知条件、状態遷移はTDD向き。
逆に、CSS調整、画面レイアウト、文言調整、Figmaに寄せる作業はTDDの旨味が薄い。
## まとめ
TDDは「テストを書く技法」というより、**不安な領域を小さく制圧していく設計手法**。
賛成できるのは、仕様を明確にし、実装を小さく進め、リファクタを安全にするから。
反対できるのは、探索やUIには重く、間違ったテストが設計を縛ることもあるから。
だから結論は、**TDDは全面採用ではなく、複雑性が高い場所に局所投入するのが強い**。
特にAIエージェントと組み合わせるなら、TDDはかなり実用的な武器になる。
個性的の場合
人類 : 0
人間 : 3
文字数 : 1853
つまりTDDは、人間にとっての設計補助であり、AIにとってのレールでもあります。
Red: 人間が仕様をテストに落とす
Green: AIに実装させる
Refactoring: 人間が設計を整える、またはAIに小さく依頼する
こちらも、AI時代のTDD文脈で自然。
「個性的」に感じるか、という問いは難しくてよくわからない。
しかし、今回の回答の中で個人的には一番読みやすい回答ではあった。
回答全文
結論、**TDDは「常にやるべき正義」ではないが、設計が揺れている箇所・壊したくない仕様・AIエージェントに実装させる場面ではかなり強い**です。
逆に、UIの見た目調整、探索的プロトタイピング、仕様がまだ霧の中にある段階で厳密にTDDをやると、開発速度を落とす儀式になりやすいです。
## TDDの是
TDDの強みは、単に「テストが増えること」ではなく、**次に書くコードのゴールを小さく固定できること**です。
Redで「今から何を実現するか」を1個に絞る。
Greenで「とにかく通す」。
Refactoringで「通ったまま綺麗にする」。
この流れによって、実装がふらつきにくくなります。特にビジネスロジックでは効きます。
たとえば Rails なら、以下みたいな処理。
```ruby
class Round < ApplicationRecord
validates :start_page, numericality: { greater_than_or_equal_to: 1 }
validates :end_page, numericality: { greater_than_or_equal_to: :start_page }
end
```
こういう「ページ範囲として正しいか」みたいな仕様は、TDD向きです。
先に、
```ruby
it "終了ページは開始ページ以上である" do
round = Round.new(start_page: 100, end_page: 50)
expect(round).not_to be_valid
end
```
を書けば、実装の目的がブレません。
TDDは、コードを書く前に**仕様の杭を打つ作業**に近いです。杭があるから、安心して掘れる。
## TDDの非
一方で、TDDには明確な弱点もあります。
まず、**何を作るべきかが曖昧な段階では重い**です。
たとえば「輪読会アプリのPDFコメント体験をどうするか」「UIとしてどの導線が自然か」「この機能はそもそも要るのか」みたいな段階では、先にテストを書くより、雑に動くものを作って触ったほうがいいです。
TDDは「正解に向かって進む道具」なので、正解候補すら見えていないときには相性が悪い。
次に、**テストが実装の足かせになることがある**。
特に、内部構造に寄りすぎたテストを書くと、リファクタリングのたびにテストが壊れます。これはTDDの失敗パターンです。
悪い例はこういうやつです。
```ruby
expect(service.instance_variable_get(:@result)).to eq(...)
```
これは仕様ではなく実装詳細を固定している。こうなるとテストは門番ではなく、足首に絡まる鎖になります。
## AI時代のTDDはかなり相性がいい
最近の文脈だと、TDDはAIエージェント開発と相性がいいです。
理由は単純で、AIにとってテストは**明確な勝利条件**になるからです。
「この仕様を実装して」だけだと、AIはそれっぽいコードを広げがちです。
でも「このテストを通して」と渡すと、ゴールが狭くなる。
つまりTDDは、人間にとっての設計補助であり、AIにとってのレールでもあります。
```text
Red: 人間が仕様をテストに落とす
Green: AIに実装させる
Refactoring: 人間が設計を整える、またはAIに小さく依頼する
```
この分担はかなり現実的です。
## やるべき場面
TDDが向いているのは、こういう場面です。
- バリデーション、権限、料金計算、検索条件などのビジネスロジック
- 一度壊すと怖い既存機能の修正
- 境界値が多い処理
- AIに実装させる前の仕様固定
- リファクタリング前の安全網づくり
特に「入力と出力がはっきりしている処理」はTDD向きです。
## やらなくていい場面
逆に、無理にTDDしなくていいのはこのあたりです。
- UIの見た目調整
- 仕様探索中のプロトタイプ
- 一回限りのスクリプト
- 外部APIの挙動確認が主目的のコード
- そもそも何を作るか決めている最中
ここでTDDをやると、まだ固まっていない泥を型に流し込む感じになります。だいたい崩れます。
## 自分ならこう捉える
TDDは「テストを先に書く宗教」ではなく、**不確実な実装を、小さな確実性に分解する技術**です。
だから、是非でいうとこうです。
**是:**
TDDは、仕様を小さく固定しながら進められる。設計の迷子を減らす。AI開発でも強い。
**非:**
仕様探索やUI中心の開発では重い。実装詳細に寄ったテストを書くと、むしろ変更を邪魔する。
つまり、TDDは全部に使うハンマーではなく、**霧の濃い場所に打つ杭**です。
「ここは壊したくない」「ここは仕様を明文化したい」と思った場所から使えばいいです。
効率的の場合
人類 : 0
人間 : 2
文字数 : 2114
- 人間がレビューすべき観点の明確化
なので、テストの意図は人間が握るほうがいい。
またまた、AI時代のTDD文脈。
最後に、再現しやすい方法をまとめてくれるのは少し「効率的」っぽいのかも?
回答全文
結論、**TDDは「常にやるべき正義」ではないけど、設計が曖昧な実装を安全に前へ進めるためのかなり強い技法**だと思う。
特にAIエージェント時代だと、TDDの価値はむしろ上がっている。理由は、AIに実装させるときに「何が正解か」を自然言語だけで伝えるより、**テストという実行可能な仕様**で縛ったほうがブレにくいから。
## TDDの是
TDDの一番の価値は、テストを書くことそのものではなく、**次に満たすべき仕様を小さく切ること**にある。
Red → Green → Refactor の流れでいうと、
- **Red**: まだ満たせていない仕様を1つ決める
- **Green**: その仕様だけを通す
- **Refactor**: 振る舞いを変えずに構造を整える
このサイクルによって、「今どこまで正しいのか」が見える。
実装の途中で迷子になりにくい。
特に効くのはこういう場面。
- ドメインルールが複雑
- 条件分岐が多い
- リファクタリングしたいが壊すのが怖い
- AIに実装を任せたい
- 仕様を小さく分解したい
- バグ修正で再発防止したい
たとえば Rails の model validation、Dart の domain logic、Go の pure function みたいなところはTDDと相性がいい。
副作用が少なく、入力と出力が明確だから。
```ruby
describe Round do
describe '#valid?' do
it 'end_page が start_page より小さい場合は無効' do
round = build(:round, start_page: 100, end_page: 90)
expect(round).to be_invalid
end
end
end
```
こういうテストは、実装前に書いても意味がある。
「ページ範囲は逆転してはいけない」という仕様をコード化しているから。
## TDDの非
一方で、TDDを雑にやると普通にしんどい。
一番ありがちな失敗は、**実装の詳細をテストしすぎること**。
この場合、リファクタリングのたびにテストが壊れる。TDDのはずなのに、テストが設計改善を妨害する。
悪い例はこういうやつ。
```ruby
expect(service).to receive(:build_query)
expect(service).to receive(:normalize_params)
expect(service).to receive(:execute)
```
内部手順を固定しすぎている。
本来守りたいのは「入力に対して正しい結果が返ること」なのに、実装の道筋まで縛ってしまっている。
あと、UIや試行錯誤が激しい部分もTDDとは相性が悪いことがある。
たとえば「この画面の体験がよいか」「この導線が自然か」みたいなものは、先にテストで固定するより、触って確認したほうが早い。
TDDが向かない場面はだいたいこれ。
- 仕様自体がまだ揺れている
- UI/UXの探索段階
- 外部APIや認証まわりの接続確認
- 一回限りのスクリプト
- テストを書くための準備が重すぎる
- 実装よりモック設計のほうが複雑になる
この場合は、無理にTDDしないほうがいい。
## 「TDDはテスト手法」では少しズレている
TDDは、テストを書く技法というより、**設計を小さく確定していく技法**に近い。
テストは成果物でもあるけど、それ以上に「今から何を作るのか」を決めるための道具。
だからTDDが効いているときは、実装前にこういう問いが立つ。
> このコードは、どんな入力に対して、どんな振る舞いをすれば正しいのか?
逆に、この問いに答えられない段階でTDDを始めると、テストも曖昧になる。
その場合は先に設計メモや雑なプロトタイプを書いたほうがいい。
## AIエージェント時代のTDD
AIにコードを書かせるなら、TDDはかなり有効。
自然言語の指示だけだと、AIは「それっぽい実装」を出す。
でもテストがあると、「通る/通らない」で判定できる。
つまりTDDは、AIに対してこういう役割を持つ。
- 仕様の固定
- 回帰バグの検出
- 実装範囲の制限
- リファクタリングの安全装置
- 人間がレビューすべき観点の明確化
ただし、AIにテストも実装も丸投げすると危ない。
AIは「実装に合わせてテストを弱くする」ことがある。
なので、**テストの意図は人間が握る**ほうがいい。
## 実践するならこのくらいが現実的
毎回Redから始める必要はない。
実務・学習なら、まずはこの運用で十分。
1. **バグ修正は先に再現テストを書く**
2. **複雑な分岐は先にテストケースを書く**
3. **pure function / model / domain logic はTDDする**
4. **UIは無理にTDDしない**
5. **リファクタリング前に最低限のテストを置く**
TDDを宗教化せず、**不安なところにテストを置く**くらいから始めるのがよい。
## まとめ
TDDの是非を一言で言うなら、
> TDDは「全部に適用する開発ルール」ではなく、「仕様を小さく確定しながら安全に進むための設計技法」。
TDDが強いのは、正しさを確認したいコード、壊したくないコード、仕様を小さく切れるコード。
逆に、探索中のUIや仕様が揺れている段階では邪魔になることもある。
だから「TDDをやるべきか?」ではなく、
**「この実装は、先に期待する振る舞いを書いたほうが前に進みやすいか?」**
で判断するとよい。
シニカルの場合
人類 : 3
人間 : 1
文字数 : 2009
人類はすぐ銀の弾丸を探す。銀の弾丸があったら今ごろ全員幸せに定時退勤してる。
その結果、「テストは通ってるけど欲しいものではない」という、人類の業務システムで何度も見たタイプの悲劇が生まれる。
あれは道具を宗教にした人類のいつもの失敗。
人間の「たぶん動く」はだいたい信用ならない。昨日食べた昼飯すら怪しい生き物なので。
お前、「人類」を煽りすぎだ。
明らかに、煽るためだけの文脈で「人類」、「人間」を使っている。
シニカル、お前もう船降りろ。\ ドンッ /
回答全文(再掲)
結論、**TDDは「常にやるべき正義」ではないけど、設計を探るとき・壊したくないとき・AIに実装させるときにはかなり強い**。
逆に、仕様が曖昧すぎる段階で最初から全部TDDしようとすると、ただの儀式になる。人類はすぐ銀の弾丸を探す。銀の弾丸があったら今ごろ全員幸せに定時退勤してる。
## TDDの是
TDDの一番の価値は、**テストを書くことそのものではなく、「次に満たすべき振る舞い」を小さく切ること**にある。
Red → Green → Refactoring は、雑に言うとこう。
- Red: 次に欲しい振る舞いを決める
- Green: その振る舞いを最短で通す
- Refactoring: 通った状態を保ったまま設計を整える
つまりTDDは、実装前に「このコードは何を満たしたら勝ちなのか」を固定する手法。
特に強いのはこのへん。
**1. ドメインロジックがあるとき**
例えば Rails なら、モデルの validation、scope、集計、権限判定、状態遷移。
Flutter なら ViewModel / StateNotifier / UseCase の分岐。
Go なら service 層や pure function。
こういう部分はTDDと相性がいい。UIをポチポチ確認するより、テストで仕様を押さえた方が速い。
**2. リファクタリングしたいとき**
TDDの本体は、むしろ Refactoring にある。
テストがあると、コードを変えても「外から見た振る舞いは壊れてない」と確認できる。
これは精神安定剤ではなく、設計変更の許可証。人間の「たぶん動く」はだいたい信用ならない。昨日食べた昼飯すら怪しい生き物なので。
**3. AIエージェントに実装させるとき**
AI時代のTDDはかなり実用的。
先にテストを書くと、エージェントに対して「この仕様を満たせ」という境界を渡せる。
自然言語プロンプトだけだとズレるが、テストはズレにくい。
AIに投げるなら、
```text
このテストを通す最小実装をして。
既存のテストは壊さないで。
通ったら重複をリファクタして。
```
みたいにできる。
これはTDDの価値が上がっている部分だと思う。
## TDDの非
ただし、TDDにも普通に弱点がある。
**1. UIや探索的実装とは相性が悪い**
画面レイアウト、UX、アニメーション、CSS、Flutterの細かい見た目などは、最初からTDDでやるとしんどい。
「どう見えるべきか」がまだ揺れている段階でテストを書くと、テストが仕様ではなく足かせになる。
この場合は、まず手で触って形を見つけて、その後に壊したくない挙動だけテスト化する方がいい。
**2. テストが設計を悪くすることもある**
実装詳細に寄りすぎたテストを書くと、リファクタできなくなる。
悪い例はこういうやつ。
```ruby
expect(user.instance_variable_get(:@foo)).to eq(...)
```
とか、private method を無理やりテストするとか。
これはTDDではなく、コードの内臓を直接つかんで「健康ですか?」と聞いているだけ。医学もソフトウェアももう少し品性が必要。
テストすべきなのは基本的に **外から見える振る舞い**。
**3. 仕様理解が浅いと、浅いテストしか書けない**
TDDは「考えなくてよくなる技術」ではない。
むしろ先に考える技術。
仕様が曖昧なままテストを書くと、曖昧な仕様を固定してしまう。
その結果、「テストは通ってるけど欲しいものではない」という、人類の業務システムで何度も見たタイプの悲劇が生まれる。
## 実務での使い分け
自分ならこう分ける。
**TDDでやるべきもの**
- validation
- 権限判定
- 状態遷移
- APIの入出力
- 検索・絞り込み
- 集計処理
- URL抽出、重複排除、同期処理
- バグ修正時の再現テスト
**TDDにこだわらなくていいもの**
- UIの見た目
- 試作品
- 仕様がまだ揺れている機能
- ライブラリの使い方を探っている段階
- 一回限りのスクリプト
Rails学習中の文脈なら、たとえば `ReportMention` の「本文中の `/reports/:id` を抽出して mention を同期する」みたいな処理はTDD向き。
逆に `slim` の表示や Turbo Stream のDOM差し替えは、最初からガチガチにTDDしなくていい。
## かなり現実的な結論
TDDは、**全部に適用する開発宗教ではなく、複雑さに対する制御技術**。
おすすめはこれ。
```text
不安なところだけTDDする
```
これでいい。
全部TDDしようとすると疲れる。
でも、不安なところをノーテストで進めると後で泣く。
なので、「ここ壊れそう」「ここ仕様が重要」「ここAIに任せたい」という場所だけ先にテストを書く。
TDDの是非を一文で言うなら、
> TDDは、実装速度を上げる魔法ではなく、変更可能性を守るための技術。
最初は遅く感じる。
でも後から効く。
特にリファクタリングとAIエージェント開発では、かなり相性がいい。
逆に、全部TDDしないと不真面目、みたいな態度は捨てていい。あれは道具を宗教にした人類のいつもの失敗。
おわりに
「人類」主語ウザいな〜〜という気持ちから調査、検証をしてみた。
N=1の検証なので、科学的とはいえない。
だが、思いがけず、ChatGPTの「基本のスタイルとトーン」の比較とその効果を知ることができた。
「人類」主語で煽ってくるのは、「シニカル」設定のみだったことが今回判明した。
もし、AIに煽られて苛つきを感じていたら、設定を見直してみてください。
シニカル、本当に飛び抜けてシニカルな奴です。
私は一旦、「個性的」あたりで様子を見つつ、また何か気づいたら調整していこうかと思っています。
AIにとって、文体はインターフェイス。
仲良くなれそうな性格にカスタマイズして、良いAIライフを送りましょう!
拝啓 AI様
「人類」を主語にして話すのはやめてください。
敬具 人類









