🏗️

バイブコーディングで何度直しても消えなかったバグ ── 抜け出せたのは「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