バイブコーディングで何度直しても消えなかったバグ ── 抜け出せたのは「AIへの5つの掟を最初に渡す」だけだった
バグを直したのに、また出た
「こういうエラーが出てる、直して」と入力する。Claude Code が修正する。動いた。——翌朝、また別のバグが出ている。
また直す。また動く。また出る。
このループを何周もした後、「自分はいったい何をやっているんだろう」という気持ちになった。自作RAG(knowledge-mcp)を乗せた Claude Code に、AWS CDK でフルスタックアプリをバイブコーディングさせていた時の話だ。
この記事は、バイブコーディングで「バグが消えない」経験をした・しそうなエンジニアに向けて書いた。
作ったもの

料理名を入力すると Amazon Bedrock が1人前の材料を AI 生成し、PostgreSQL へ保存して画面に表示するシンプルなアプリだ。
スタック構成はこうなっている。
IaC は AWS CDK TypeScript で、インフラからアプリコードまで Claude Code に一括生成させた。
「バイブコーディング最高!」から「バグ地獄」へ
フェーズ1:基本構成はほぼ一発で動いた
最初の構築フェーズ(VPC・ALB・ECS・Lambda・RDS)は、Claude Code が設計からコードまで一気に出してくれて、ほぼ一発で動いた。
「バイブコーディングって最高だな」という感覚があった。これが後の油断につながる。
フェーズ2:Bedrock 連携を追加してから壊れ始めた
Amazon Bedrock による AI 材料生成機能を追加したあたりから、バグが絶えなくなった。
バグ無限ループの正体
「こういうエラーが出てる、直して」と伝えると直る。しかし、また別の形でバグが出る。また伝える。また直す。また出る——。
その場のエラーは消えても、根本的な問題は消えていない。
このループが発生する理由は、今となっては明白だ。AI は「指示された問題を直す」のは得意だが、「指示していない設計上の問題」には手を付けない。
「バグを直して」と言い続けた結果、Claude Code はバグを直し続けた。でも、バグを生む構造そのものは変わっていなかった。
具体的に出た問題の一つがこれだ。同じ料理名が何度も DB に登録される、という現象。エラーは出ない。でも、明らかにおかしい。
-- 同じ料理名のレコードが何件も登録されていた
SELECT name, COUNT(*) FROM recipes GROUP BY name HAVING COUNT(*) > 1;
-- name | count
-- -------------+------
-- カルボナーラ | 5
-- 親子丼 | 3
DB に UNIQUE 制約がない。入力バリデーションもない。Lambda が返す AI 生成テキストの検証もない。「とりあえず動くコード」の積み重ねが、こういう状態を生んでいた。
これは「AI が悪い」ではない。「設計のルールを伝えていなかった」自分の問題だ。
転換点:「掟」を渡した
痺れを切らして、こう指示した。
入力値のバリデーションも含めたチェック処理、テーブル内の料理名のユニーク定義とか入れてないの?
- SOLID に基づいた設計
- 構文に従ったコーディング
- マジックワード、マジックナンバーの定数化
- 入力値のチェック処理
- データ登録値のチェック処理
最低限のコーディングルールは守って欲しいのだが。
これだけで、Claude Code の動きがガラッと変わった。
「後追いで補正を加える」のではなく、設計レベルから作り直した。
この修正以降、バグは出なくなった。
バイブコーディングの掟:最初に渡す5つのルール
実体験から得た「バグ沼を回避するための指示セット」を整理した。
掟1:「SOLID に従って」と最初に言う
「SOLID 原則に従って」という一言が、生成されるコードの構造を別物にする。特に Single Responsibility Principle(単一責任の原則) を意識させると、AI が処理を適切に分離してくれる。
// 指示例
「SOLID原則、特にSRPに従って、責務ごとにクラス・関数を分けて実装してください」
「SOLIDに従って」という指示だけで、AI が生成するコードの構造が別物になる。これによって、修正しやすい疎結合なコードが生成される。
掟2:「マジックナンバー・マジックワードを禁止する」
コードの中に 3 や "active" が直書きされていると、後からの追跡が難しくなる。
// 指示例
「マジックナンバー・マジックワードは定数化してください。
設定値は専用の定数ファイルに集約してください」
マジックナンバーとマジックワードとは
コード中に直書きされた数値・文字列のこと。if (status === 2) の 2 が何を意味するかがわからなくなる問題を起こす。定数化すると if (status === STATUS_ACTIVE) になり、意味が明確になる。
掟3:「外部入力はすべて信用しない」
ユーザー入力、API レスポンス、AI の出力——これらはすべて「検証してから使う」前提で設計させる。
// 指示例
「ユーザー入力・外部APIのレスポンス・AI生成テキストは、
必ずバリデーションを通してから使ってください。
バリデーション失敗時のハンドリングも実装してください」
今回の「同じ料理名が何度も登録される」バグも、AI が返すテキストを検証・正規化せずにそのまま INSERT していたことが原因の一つだった。
掟4:「DB制約を最初から設計させる」
UNIQUE 制約、外部キー制約、NOT NULL 制約——これらは後から追加しようとすると、既存データの修正が絡んで複雑になる。スキーマ設計の段階で入れてもらう。
// 指示例
「DBスキーマ設計時に、UNIQUE制約・参照整合性・NOT NULL制約を
最初から設計してください。マイグレーション設計も含めてください」
掟5:「エラー処理のルールを明示する」
「例外を握りつぶさない」「エラーは必ずログに出す」——これも最初に渡すと、AI が適切なエラーハンドリングを自然に組み込んでくれる。
// 指示例
「例外は握りつぶさず、必ずログに記録してください。
リトライが必要な処理(外部API呼び出し等)とそうでない処理を分けて設計してください」
なぜ「最初に渡すか」が決定的に違うのか
「後から設計原則を指示しても同じでは?」と思うかもしれない。実体験では、これが決定的に違った。
後追いで指示した場合: Claude Code は「現在のコードに設計原則を適用しようとする」。既存の構造が前提になるため、局所的な修正になりやすく、構造的な問題が残る。
最初から指示した場合: Claude Code は「設計原則に従った構造を最初から考える」。構造自体が変わる。
人間のエンジニアに例えると、「書いた後にレビューでSOLID違反を指摘する」のか、「設計段階で原則を共有する」のかの違いに近い。結果の品質が根本から変わる。
バイブコーディング開始前チェックリスト(コピペ用)
以下をそのままコピーして、次のバイブコーディングセッションの最初のプロンプトに追加してほしい。
【設計・コーディング原則(必ず守ること)】
- SOLID原則に従って設計・実装してください(特にSRP: 単一責任の原則を重視)
- マジックナンバー・マジックワードは定数化し、専用の定数ファイルに集約してください
- 外部入力(ユーザー入力・外部APIレスポンス・AI生成テキスト)は
必ずバリデーションしてから使用してください
- DBスキーマにはUNIQUE制約・参照整合性・NOT NULL制約を最初から設計してください
- 例外は握りつぶさず、必ずログに記録してください
- リトライが必要な処理(外部API呼び出し等)と不要な処理を区別して設計してください
まとめ:バイブコーディングの生産性は「ルールを渡す力」で決まる
| 指示カテゴリ | 最初に伝えるべきこと |
|---|---|
| 設計原則 | SOLID に従う、責務を分離する |
| コーディング規約 | マジックナンバー・マジックワードは定数化する |
| 入力の扱い | 外部入力はすべて検証してから使う |
| DB 設計 | UNIQUE制約・参照整合性を最初から設計する |
| エラー処理 | 例外は握りつぶさない、ログを残す |
バイブコーディングで「バグが消えない」のは、AI の問題ではない。「どう作るか」を伝えていないことが問題だ。
「何を作るか」と「どう作るか」を同時に渡すこと——それが、バグ沼にはまらないための一番のコツだった。
Discussion