AIに指示を出せば、動くコードはすぐに出てきます。問題は「動く」ことではなく、自分が今何をAIにやらせていて、何が起きているかを言葉にできるか の方です。ここが薄いまま進めると、動いてはいるが正しくないコードに気づけないまま本番に出てしまいます。
バイブコーディングをする前に最低限持っておきたい知識を、自分でまとめた教科書から要点だけ抜き出して並べます。全部を暗記する必要はなく、「こういう概念があるらしい」と知っているだけで、詰まった時に自分で調べ直せます。
全体の流れ
知識を知って終わりにせず、実際にAIに実装させて、疑って、壊して、なぜ壊れたかを理解するところまでが1セットです。
AIに任せていい仕事とダメな仕事がある
判断基準はシンプルで、「間違っていた場合に自分で気づけるか」 です。気づけない仕事をAIに丸投げするのが一番危険です。
| 任せていい | 任せると危険 |
|---|---|
| 定型的なコードの雛形生成 | セキュリティに関わる判断(認証方式の選定など) |
| リファクタ・命名の統一 | 「なぜこの設計にしたか」の意思決定そのもの |
| エラーメッセージの解読補助 | 検証していない外部データの扱いの最終判断 |
| テストケースの列挙 | 本番データを操作する破壊的な処理の実行 |
「動く」と「正しい」は違う
「動く」は「今、目の前のケースでエラーが出ていない」という意味でしかありません。「正しい」は「想定される全てのケースで仕様を満たしている」ことです。AIは指示された内容を最も自然に満たす 典型的な実装 を出すよう学習されているので、「空文字列が来たら」のような非典型なケースは、明示的に頼まない限り出てきません。ここを埋めるのが後述の「壊す」です。
AIが出したコードの違和感に気づくための語彙
書けなくてもいいですが、違和感に気づける ことは必須スキルです。特に事故りやすいのがこのあたりです。
-
エラー処理:
except: passのように例外を握りつぶすと、失敗したことそのものが誰にも見えなくなります。一番タチの悪いバグの隠し方です - 型: 「この変数は文字列のはずが数値だった」というズレは頻発します
- ファイル・DB・ネットワーク: すべて「プログラムの外側」なので、相手が応答しない・途中で失敗する前提を持っておく必要があります
- Git: commitの粒度が細かいほど、「AIに直させて、ダメなら戻す」が安全にできます
例えば次のようなコードは、一見動きますが2箇所引っかかります。
def get_user_age(user_id):
try:
user = fetch_user_from_db(user_id)
return user["age"]
except:
pass
except: pass でエラーを握りつぶしている上、失敗理由が一切分からないまま戻り値が None になり、呼び出し側が気づけません。
設計は「要件」と「仕様」を分けることから始まる
要件 は「何を実現したいか」、仕様 は「それをどう振る舞いとして定義するか」です。「ログイン機能が欲しい」は要件、「メールとパスワードで認証し、5回失敗したらロックする」は仕様です。AIに実装を頼む前に、この2つを分けて言葉にできているかを確認するだけで、後工程の手戻りがかなり減ります。
もう1つ効くのが 責務分離 です。目安は「その部品の説明に『それと』が出てきたら分割サイン」。「ユーザーを検証して、DBに保存して、メールを送る関数」のように「て」が繰り返し出てくる説明は分割候補です。
曖昧な指示は曖昧な実装しか生まない
AIへの指示は精度がそのまま実装の質になります。
| 曖昧な言い方 | 精度の高い言い方 |
|---|---|
| 「なんかバグってる」 | 「〇〇を押すと△△というエラーが出る。再現手順は1,2,3」 |
| 「もっといい感じにして」 | 「この関数を、単一責任になるよう2つに分割して」 |
| 「セキュリティ大丈夫?」 | 「このフォームの入力値はエスケープせずHTMLに埋め込んでいないか確認して」 |
大きすぎるタスクをそのまま渡すと内部で矛盾した実装が混ざるので、「まずデータ構造を決める→次にインターフェースを決める→最後に実装する」のように区切って渡すのも重要です。
「壊してみる」ことでしか見えないバグがある
正直、最初はこの工程を軽視していました。ただ実際に手で壊してみると、レビューだけでは絶対に気づけなかったバグが毎回1つ以上見つかります。壊す観点は教科書側の詳細にまとめていますが、だいたい次の10種類に収まります。
境界値・異常系・空データ・巨大データ・同時実行・ネットワーク切断・権限不足・データ破損・再起動・二重実行。
見つけたバグはその場で忘れず、テストコードに変換 しておくと、後で仕様を変えた時に壊れたことへ確実に気づけます。テストの本当の目的は「バグを見つけること」より、「後で仕様を変えた時、壊れたことに気づけること」にあります。
本番で壊れた時に気づけるかは別問題
意図的に壊す工程とは対になる話です。一番怖いのは、エラーになっていることにすら誰も気づかず、ユーザーだけが被害を受け続ける状態です。ログを残していても、誰も見ていなければ気づけないまま放置されます。
- 失敗しうる処理(外部API・DB操作・決済など)で、失敗時に「何が」「いつ」「どんな入力で」を記録しているか
- ログが記録されるだけで終わっておらず、開発者に通知(Slack・メール・監視ダッシュボードなど)が届く経路があるか
- 通知を受けた後、原因調査に必要な情報(入力値・ユーザーID)がログに紐づいているか
「ログ→検知→通知→調査」のどこかが途切れていると、結局は気づけません。
セキュリティの根っこはたった1つの原則
個別に見ると膨大ですが、根っこは1つです。
外部から来たデータは、形式・内容ともに一切信用しない。
# 危険: 文字列結合でSQLを組み立てる
query = f"SELECT * FROM users WHERE name = '{user_input}'"
# 安全: プレースホルダを使う
cursor.execute("SELECT * FROM users WHERE name = ?", (user_input,))
この原則1つを意識するだけで、SQL Injection・XSS・秘密情報の直書きの多くは防げます。認証(あなたは誰か)と認可(あなたに何が許されているか)は別物で、「ログインさえできれば全機能が使える」設計は認可の実装漏れであることが多いです。
テストは自動で実行され続けて初めて価値を持つ
壊して見つけたテストも、人間が思い出した時にだけ実行しているうちは、いずれ実行し忘れます。pushするたびに自動でテスト・Lint・型チェックが走る仕組み(CI)を最低限用意するだけで、「自分のPCでは動いた」と「誰の環境でも動く」の差を機械的に検出できるようになります。
AIツールは「どれが正解」ではなく使い分ける
チャット型・IDE統合型・CLI/エージェント型・自律実行型のどれか1つが常に正解ではありません。相談しながら設計を固めたいならチャット型、複数ファイルにまたがる実装を一括で任せたいならCLI/エージェント型、というように タスクの粒度とAIに求める自律性 で選びます。どのツールを使っていても、監督する姿勢と壊す検証は省略できません。
知識を1回、自分の手で回してみる
読んで終わりにせず、小さなアプリを1つ題材にして、知識→AIに実装させる→疑う→壊す→なぜ壊れたか理解する、のループを実際に1周させると、以降のバイブコーディングの質が変わります。この1周を通しでやるだけの実践編も教科書側に用意しています。
これだけでは足りなくなったら
ここに挙げたのは教科書10章のうち、特に事故りやすいポイントだけです。全文には各章末の演習、用語集、FAQ、そして実際にコードに対して実行できるClaude Code向けのチェックスキルまで用意してあります。
まとめ
バイブコーディングが危険なのは、AIに頼ること自体ではなく、AIが出したものを評価する言葉を自分が持たないまま採用してしまうこと です。ここに挙げた知識は全部、その言葉の精度を上げるための最短ルートのつもりで選びました。
AIの利用について
この記事の一次稿はClaudeと一緒に作成しました。教科書の構成・章立て・演習内容・ライセンス選定・記事のタイトルとタグの最終判断は自分で行い、本文のドラフト作成はClaudeに任せています。