
AIが書いたコードの品質を疑う方法:個人開発者のための8つの検証原則
AIコーディングツールでAttractiveWebAIやShopifyアプリなどを開発するなかで経験した10の失敗と、動いているように見える「UIの錯覚」を乗り越えてコード品質を守るための8つの現実的な原則を共有する。
もっともらしい画面が生んだ錯覚
ShopifyShopifyデジタル店舗と実店舗をホスティングし、多言語翻訳、グローバル決済、カスタムアプリのエコシステムを提供する世界的なコマースプラットフォームです。Read More →のメンバーシップアプリで最初のデモビルドが成功したとき、私は興奮を隠せなかった。画面にはすっきりしたダッシュボードが表示され、設定メニューのトグルボタンはなめらかに動き、ポイント付与のルールを入力するフォームも完璧に見えた。マウスをクリックするたびに、画面はきびきびと反応した。AIコーディングツールに何度か指示を打ち込んでから、わずか2日で手に入れた成果だった。このペースなら、来週にでもアプリストアに公開できそうな気がした。
でも、喜びは長くは続かなかった。テストアカウントでストアから実際に決済を進め、顧客ランクを上げようとしたところ、アプリはまったく反応しなかった。コードを掘り下げて調べてみて、ようやく厳しい現実を突きつけられた。画面に表示されていたもっともらしい数字は、すべてAIが勝手に埋め込んだMock Data(ダミーデータ)で、肝心のお金を扱う決済APIも、ポイント付与のWebhookも、自動割引のトリガーも、一行たりとも書かれていなかったのだ。外側の殻だけがあって、中身はからっぽだった。
私はプロのソフトウェアエンジニアではない。ITプロジェクトマネージャー(PM)として働きながら、必要なプロダクトをAIの力を借りて自分でつくり、デプロイしている個人のつくり手に近い。Webサイト分析SaaSのAttractiveWebAI、ShopifyShopifyデジタル店舗と実店舗をホスティングし、多言語翻訳、グローバル決済、カスタムアプリのエコシステムを提供する世界的なコマースプラットフォームです。Read More →のメンバーシップアプリ、そしてmacOSのウィンドウプレビュー用ユーティリティまで、いくつものプロダクトを開発するなかで、Gemini、Claude、Codexといったツールをあらゆる場面で使い倒してきた。
最初のうちは、ほしい機能をざっくり説明するだけで、ちゃんと動くコードがあっという間に出てくるスピードに酔っていた。ところがプロジェクトの規模が大きくなり、機能同士が絡み合いはじめると、画面の裏に隠れていた欠陥がいっせいに頭をもたげてきた。
AIが隠していた10の負債
デプロイの段階を経るなかで、痛い思いをしながら書き留めてきた失敗のリストは、思っていたより長く、具体的だった。
- DBへの保存漏れ:フロントエンドのフォームで「保存」ボタンを押すと、画面には成功メッセージが出る。なのに肝心のSupabaseのデータベースには何も書き込まれず、データはメモリの中をさまよったあげく消えていた。
- 消えたAPI接続:フロントエンドUIのかっこいいボタンや入力欄は完成していたのに、バックエンドのAPIエンドポイントと通信するコードが抜けていて、実際のサービスは動かなかった。
- ダミーデータの放置:開発の都合で一時的に入れたMock Dataやテスト用のハードコード値が、本番の運用モードでもそのまま使われていた。
- 同じコードの重複生成:AIが既存プロジェクトの全体構造を覚えていられず、すでにあるユーティリティ関数やコンポーネントを、名前だけ少し変えて、3つも4つも重複してつくっていた。
- 回帰(リグレッション)エラー:ある箇所のバグを直そうとコードを修正すると、それまで問題なく動いていたまったく別のページの機能が壊れる。そんなことがくり返された。
- ビルド成功の罠:
npm run buildもTypeScriptの型チェックも完璧に通ったのに、ランタイムで特定の条件になると、ブラウザが真っ白な画面しか出さなくなる致命的なエラーが起きた。 console.logだけが残った報告:AIは機能の実装を終えたと堂々と答えたが、コードを開いてみると、中身のかわりにconsole.log("TODO: 実装予定")というコメントだけがぽつんと残されていた。- データベーススキーマの欠落:ローカル開発環境のSupabaseテストアカウントでは問題なく動いていた機能を、本番用のSupabaseアカウントに移したときのこと。コードと環境変数は切り替えたのに、SQLのテーブルとトリガーのスキーマを移行していなかったせいで、サービス全体が止まった。
- コアロジックの省略:ShopifyShopifyデジタル店舗と実店舗をホスティングし、多言語翻訳、グローバル決済、カスタムアプリのエコシステムを提供する世界的なコマースプラットフォームです。Read More →アプリをデプロイする過程で、画面デザインは仕上がっていた。しかし肝心のBilling APIとの連携と、自動割引ポリシーを呼び出すロジックがつながっておらず、実際の収益モデルを検証できなかった。
- システム権限の認識エラー:macOSのウィンドウプレビュー用ユーティリティを開発していたとき、OSの設定画面ではアクセシビリティと画面収録の権限がオンになっているように見えても、実際のランタイムのコードではその権限の状態を検知できず、アプリが固まってしまう。そんなデバイスレベルの例外が頻発した。
こうした失敗の後始末に追われて夜を明かすうちに、あることにハッと気づかされた。AIコーディングの本当のボトルネックは、コードを書くという行為そのものではなかった。AIが吐き出したコードを検証し、それが「完全に完了した」ことを人間の目で証明するプロセスこそが核心だったのだ。ここを放置すれば、プロダクトは動いているふりをする技術的負債の巨大な沼に変わってしまう。
この試行錯誤をくぐり抜けるなかで私が確立した、8つのコード品質検証の原則を共有する。
原則1. 頼む前に、まず完了条件(Definition of Done)を書く
AIに「ログイン機能をつくって」とあいまいに頼むと、AIは勝手に楽な方法を選んで、とりあえず動くだけのコードを書く。私は機能を頼む前に、必ず検証すべきチェックリストをあらかじめ書いて、依頼文に含めている。
[完了条件]
1. ユーザーがGoogle OAuthアカウントでログインできるか?
2. ログインセッションは、リロードやブラウザの再起動後も維持されるか?
3. ログアウトボタンを押すとセッションが削除され、トップページにリダイレクトされるか?
4. ログインしていないユーザーがAPIを直接呼び出したとき、401 Unauthorizedエラーを返すか?
5. ログインしたユーザーは、自分のデータだけを閲覧・修正できるか?
6. パスワードや機密性の高いトークンが、ローカルストレージに平文で残っていないか?
こうして明確な制約とテストシナリオを渡すと、AIは例外処理のコードやセキュリティのロジックを省かず、最初からきっちり骨組みを埋めてくれる。
原則2. AIの完了報告を、決してそのまま信じない
AIが「ご依頼の機能を完璧に実装しました」と言うときこそ、いちばん危ない。私はAIの報告を受けたらすぐに、その成果物を確かめるため、いつも次の質問を投げて答えを求めている。
- 変更されたファイル、新しく作成されたファイルの全リスト
- 各ファイルで実際に修正された主要なコード箇所と、その理由
- 一時的なテストのために残したMock Dataやハードコードされた値があるかどうか
- コード内に含まれる
TODOコメントやconsole.logの位置 - まだ実装できていない部分や、環境の制約で残した技術的な限界
この質問を投げるだけで、AIは「実はこれこれの部分は仮のデータで処理しています」と抜けていた部分を遅ればせながら白状したり、自分から未完成のコードを補強したりする。
原則3. ビルドの成功と機能の成功を厳密に区別する
コンパイラがエラーを出さないからといって、ビジネスロジックがうまくいっているわけではない。ターミナルに緑色の成功メッセージが出たあとも、必ず手作業で次の項目をひとつずつ検証する。
- 状態の保持:フォームに入力して保存したあと、ブラウザを強制的にリロードしても、データがデータベースから正しく読み込み直されるかを確認する。
- 限界値の入力:空の値のまま送信する、おかしな文字を入力する、ボタンを連打する、といった操作を立て続けに行い、システムが落ちないかを見る。
- 権限の分離:ログインしていない状態や、ほかのユーザーのアカウントトークンを真似た状態で、非公開ページやAPIエンドポイントへのアクセスを試してみる。
- ログの確認:正常に動いている画面の裏で、ブラウザのコンソールやサーバーログに404エラーや
unhandled rejectionの警告が隠れていないかを観察する。
原則4. 作業の単位をできるだけ小さく分ける
一度に「ダッシュボードページと分析データの連携をまとめてやって」と大きなかたまりで頼むと、AIは高い確率で内部構造をめちゃくちゃに混ぜたり、ロジックの一部を抜かしたりする。面倒でも、ステップは徹底的に分ける。
- データスキーマの設計:データベースのテーブル構造とリレーション設定のSQLを書いて反映する。
- APIハンドラーの作成:データを取得・保存するバックエンドのAPIエンドポイントを先につくり、Postmanなどで単体テストする。
- UIのバインディング:画面のコンポーネントをつくり、先ほどつくったAPIにつなぐ。
- 例外処理の追加:ネットワークの切断、入力エラー、エラーレスポンスといった状況での案内メッセージを入れる。
- プロダクション検証:ローカル環境を離れ、stagingまたはデプロイ先のURLで、実際に動くかどうかを最終確認する。
原則5. コードを書くAIとレビューするAIを分ける
ひとつのチャットセッションで同じAIモデルにコードを書かせ続け、そのままレビューまでさせると、自分が書いたコードの論理的な誤りが見えなくなる認知バイアスに陥る。
私は機能を実装し終えたら、そのコードをまったく新しい会話セッションか、別のモデル(例:Claudeで書いたならGeminiでレビュー)に渡して、次のようなプロンプトを与える。
「このコードは、ある機能のために書かれたものです。あなたは非常に厳しいシニアバックエンドエンジニアであり、QAのスペシャリストです。このコードのセキュリティ脆弱性、エッジケースでエラーが起きる可能性、パフォーマンスの非効率、構造的な改善点を、遠慮なく厳しくレビューしてください。」
このやり方なら、ひとりで働いていても、とても優秀なコードレビューのパートナーをそばに置いているのと同じ効果が得られる。
原則6. 機能ごとの実装状況をマトリクスで管理する
「ダッシュボードページ、完成しました」というひと言には、誤解の余地がありすぎる。企画者、デザイナー、開発者としての自分をひとりで全部抱える個人開発者には、もっと明確な基準が必要だ。私はメモ帳やNotionに、機能ごとに次の状態を細かく分けてチェックしている。
- 未実装(Unimplemented):企画だけが存在する
- UIレイアウト完了(UI Only):画面の見た目だけができている
- 仮データ接続(Mock Data):ローカルのダミーデータで、動いているふりをしているだけ
- バックエンドAPI接続完了(API Connected):API通信はできる
- DB永続化の確認(DB Persisted):実際のDBへの書き込みと読み込みが保証されている
- 例外・エッジケースのテスト完了(QA Verified):失敗時のテストを通過
- 本番環境での検証完了(Prod Verified):本番サーバーへのデプロイ後の検証まで終了
この段階を踏まずに、目に見える画面だけで機能を完了扱いにしてしまうと、あとでどこが偽物でどこが本物なのか、自分でも見分けがつかない混乱に陥ることになる。
原則7. コードを修正する前に、まず既存の文脈を理解させる
既存プロジェクトのソースコードをいきなり渡して「ここにこれを追加して」と言うと、AIは既存のコーディングパターンや設計原則を無視して、ad-hoc(その場しのぎ)な汚いコードを継ぎ足しがちだ。修正を頼む前に、まず既存の構造の文脈を把握させなければならない。
「このファイルのコードを修正する予定です。変更をお願いする前に、まずこのファイルの現在の構造とデータの流れ、そして実装方法の意図を説明してください。どの関数が影響を受ける可能性があるかも整理してください。」
AIが既存のコードを正確に読み解き、分析結果を出してきたのを確認してから、はじめて「では、その意図とパターンに沿って、最小限の変更で機能を実装して」と頼む。このステップひとつだけで、コードの一貫性は見違えるほど良くなる。
原則8. 負債を抱えるのはいい。ただし隠さない
開発をしていると、スケジュールやリソースの限界から、どうしても近道を選ばざるを得ないときがある。仮のデータをハードコードしたり、セキュリティの検証をいったん後回しにしたりといった具合だ。このとき大事なのは、その「負債」をコードの中にこっそり埋めておかないことだ。
私は技術的負債のリストを、プロジェクトのルートフォルダにtech-debt.mdというファイルで明記しておき、その場しのぎの手を使うたびにすぐ記録している。
## 現在のプロジェクトの技術的負債リスト
* [AttractiveWebAI] 分析チャートでまだ仮のMock Dataを使用中(本番デプロイ前にBigQuery APIパイプラインとの連携が必須)
* [ShopifyShopifyデジタル店舗と実店舗をホスティングし、多言語翻訳、グローバル決済、カスタムアプリのエコシステムを提供する世界的なコマースプラットフォームです。Read More →メンバーシップ] 新規会員登録特典の決済処理で、割引検証Webhookの受信部が欠落(本番デプロイ前にセキュリティチェック必須)
* [共通] ユーザーセッションの期限切れで例外が発生したときのログアウト処理が不十分
* [macOSユーティリティ] システムのアクセシビリティ権限の取得確認用に、ハードコードされた待機時間(3秒)がある -> イベント駆動のトリガーに変更が必要
汚いコードを書いたという事実よりも怖いのは、どこに汚いコードを残したのかを忘れてしまうことだ。負債の大きさを目に見える形で管理しておけば、次の開発サイクルで何から改善すべきかがはっきりわかる。
本当に完成したプロダクトのために
AIを使った開発は、開発を「軽い行為」のように感じさせる。プロンプト欄に何度か質問を投げるだけで何百行ものコードが埋まり、ビルドが完了していくのを見ていると、自分がとてつもなく大きなプロダクトをあっという間にコントロールしているような錯覚に陥る。
でも、本当に完成度の高いプロダクトを決めるのは、書かれたコードの量ではない。捨てた仮のコードの量と、確認した例外ケースの数だ。動かない機能を動いているように見せかけただけの、殻だけのプロダクトは、最初のユーザーが入ってきた瞬間に砂の城のように崩れる。
AIは優秀な伴走者であり、タイピングの秘書だ。しかし、プロダクトの完了ラインを引き、品質を保証する最後の砦は、いまも企画し検証する人間の役目だ。華やかな画面の裏に隠れた動作ひとつ、データ一行を厳しい目で分解して確かめる執念こそが、AI時代に個人のつくり手が身につけるべき本当の開発力なのかもしれない。
更新履歴
ShopifyとAttractiveWebAIの開発から得た8つの検証原則。
- •AIコード品質チェックリストを公開
知識のつながり
バックリンク
この記事に言及している記事
アイデアの変遷
DailySayに聞く
Related Posts
続けて読む

PMI韓国支部の教育委員会でボランティアを始めました:合格体験記のその後
PMP合格後にPMI韓国支部の教育委員会でボランティアを始めた理由、支部と教育委員会の活動、一緒に勉強したい人の参加方法をまとめた、「PMP合格ロードマップ」シーズン1の最終回です。
残しておきたいノートを、ときどき。
プロジェクトマネジメント、AI、プロダクト、旅、そしていま作っているものについて、ときどきお届けします。
スパムは送りません。届くのはときどきのノートだけ。詳しくは プライバシーポリシー.


