4
5

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

AIが書いたコード、「読めない」まま進めてませんか — 未経験が最初に押さえる「読む技術」5観点

4
Posted at

「コードは書けなくていい。AIに書かせればいいんだから」

最近この言葉をよく聞きます。半分は本当です。実際、Claude Code に頼めば動くものはすぐ出てきます。

でも、残り半分を放置すると詰みます。動いたコードの中身を読めないまま進めると、後で『自分のアプリなのに、自分で直せない人』になるからです。

バグが出ても、どこを直せばいいか分からない。「ここに機能を足して」とAIに頼んでも、出てきたものが正しいか判断できない。これは未経験の方が最初の数週間でいちばんハマる落とし穴だと、メンタリングをしていて毎回感じます。

AI時代に価値が上がったのは、実は「書く力」より「読む力」— コードを理解して、自分で先に進めていく力です。そして読む力は、いきなり全部を読めるようになる必要はありません。観点を絞れば、未経験でも今日から読めます。

この記事では、AIが書いたコードを読むときに最初に押さえたい5つの観点を、コード例とそのまま使えるプロンプト付きで紹介します。

この記事は「危険なコードを見抜く(セキュリティ)」話ではありません。「コードを理解して、後で自分で直せるようになる」ための読み方の話です。

題材:AIが書いた「投稿を保存するAPI」

Next.js(App Router)+ Supabase でよくある、投稿を1件保存する API です。Claude Code に「ログインユーザーの投稿を保存する API を作って」と頼むと、だいたいこんなコードが返ってきます。

// app/api/posts/route.ts
import { createClient } from '@/lib/supabase/server'
import { NextResponse } from 'next/server'

export async function POST(request: Request) {
  const supabase = await createClient()
  const body = await request.json()

  const { data: { user } } = await supabase.auth.getUser()
  if (!user) {
    return NextResponse.json({ error: 'unauthorized' }, { status: 401 })
  }

  const { data, error } = await supabase
    .from('posts')
    .insert({ title: body.title, content: body.content, user_id: user.id })
    .select()
    .single()

  if (error) {
    return NextResponse.json({ error: error.message }, { status: 500 })
  }

  return NextResponse.json({ post: data }, { status: 201 })
}

20行ちょっと。だいたいこのまま動きます。でも、未経験の方がこれを「ふーん、動いたしOK」で閉じてしまうと、手元には何も残りません。この同じコードを、5つの観点で「読んで」みます。

観点① データの流れ(入力 → 処理 → 出力)を追う

最初にやるのは、1行ずつ理解しようとしないことです。代わりに「入力・処理・出力」の3ブロックに分けます。

  • 入力request.json() で受け取った bodybody.titlebody.content
  • 処理auth.getUser() でログイン中の本人を確認 → posts テーブルに保存
  • 出力:保存できたら post を返す/ダメなら error を返す

この3つさえ自分の言葉で言えれば、その関数の大部分は読めています。AIにはこう聞きます。

このファイルを、入力・処理・出力の3つに分けて、
それぞれ1行で説明して。専門用語はできるだけ使わないで。

「全部説明して」と聞くと教科書みたいな長文が返ってきて、余計に分からなくなります。読みたい枠を先に指定して要約させるのがコツです。

観点② この関数の役割を、AIに1行で説明させる

流れがつかめたら、次は「で、結局これは何をする関数なの?」を1文に圧縮します。

この POST 関数は結局"何をする"関数ですか?
小学生に説明するつもりで、1文で言い切ってください。

返ってくる答えはこんな感じです。

ログイン中の人が投稿のタイトルと本文を送ると、その人の投稿としてデータベースに保存して、保存結果を返す関数です。

これが大事な理由は、関数名やコメントは平気で嘘をつくからです。createPost という名前でも、中で別のことをしていることはよくあります。名前ではなく中身から役割を要約させると、コードの実態がつかめます。ファイルが増えてきたら「このファイル群、それぞれの役割を1行ずつで」と聞くと、アプリ全体の地図ができてきます。

観点③ 正常系と異常系の「分かれ道」を読む

次は、コードがうまくいったとき失敗したときで、どう振る舞いが分かれるかを読みます。エラーハンドリングが「ある/ない」をチェックする、と言い換えてもいいです。

さっきのコードには、分かれ道が2つあります。

if (!user) {
  // ① ログインしていない
  return NextResponse.json({ error: 'unauthorized' }, { status: 401 })
}
// ...
if (error) {
  // ② DBの保存に失敗した
  return NextResponse.json({ error: error.message }, { status: 500 })
}
// ③ どちらも問題なければ 201 で投稿を返す
  • ログインしていない → 401 を返してそこで終わり
  • DBの保存でエラー → 500 を返してそこで終わり
  • どちらも問題なければ → 201 で投稿を返す

ここを読んでおくと何が嬉しいか。バグ報告が来たときに「どの分かれ道に落ちたか」を最初に当てられるようになります。「投稿できないんですけど」と言われたら、まず返ってきたのが 401 なのか 500 なのかを見る。それだけで原因の範囲が一気に狭まります。これは後でデバッグする自分への置き手紙みたいなものです。

逆にここを読めていないと、body.title が空のまま送られたらどうなる?といった抜け道に気づけません。AIにはこう聞きます。

このコードで失敗する可能性がある箇所を全部挙げて、
それぞれ失敗したときユーザーに何が返るか教えてください。
まだ直さなくていいです。読んで把握したいだけです。

「まだ直さなくていい、読みたいだけ」と添えるのがポイントです。これを言わないとAIは勝手にコードを書き換え始めて、また読めないコードが増えていきます。

観点④ 外部依存(API / DB)の在処を把握する

未経験の方が「動かない!」とハマるとき、原因の多くは自分が書いたロジックではなく、外部とのつなぎ目です。テーブル名が違う、環境変数が未設定、APIキーが切れている。だから「このコードは外の何に頼っているか」を地図にしておきます。

さっきのコードを読むと、依存はこの行に出ています。

import { createClient } from '@/lib/supabase/server' // ← Supabase に依存
// ...
await supabase.auth.getUser()      // ← 認証(ログイン情報)に依存
await supabase.from('posts')...    // ← posts テーブルに依存

さらに Supabase は、裏で環境変数に依存しています。

# .env.local
NEXT_PUBLIC_SUPABASE_URL=...
NEXT_PUBLIC_SUPABASE_ANON_KEY=...

この地図があると、切り分けが速くなります。「保存できない」→ まず posts テーブルが本当にあるか、カラム名が合っているかを見る。次に env が読めているかを見る。自分のコードを疑う前に、つなぎ目を疑えるようになります。AIへのプロンプトはこれです。

このファイルが依存している"外部のもの"
(DBのテーブル・外部API・環境変数・ライブラリ)を
全部リストにして。それぞれ何のために使っているかも添えて。

観点⑤ 「直すならどこを触るか」を特定する

最後が、読む力がいちばん効いてくる観点です。仕様を変えたいとき、どのファイルのどこを触ればいいかを、書く前に特定できるか。ここができると一気に自走できます。

例として「投稿に"公開/非公開"を付けたい」を考えます。読めている人なら、こう分解できます。

  1. DBposts テーブルに is_public カラムを足す
  2. 入力body から isPublic を受け取る
  3. 保存insertis_public: body.isPublic を足す
.insert({
  title: body.title,
  content: body.content,
  is_public: body.isPublic, // ← 追加するのはここ
  user_id: user.id,
})

ここまで自分で地図を描いてから、AIに書かせます。

投稿に「公開/非公開」を付けたいです。
このコードと関連ファイルで、変更が必要な箇所を
上から順に、ファイル単位で教えてください。
まだコードは書かないで、変更計画だけ出してください。

ここでも「まだ書かないで、計画だけ」が肝です。いきなり書かせると、自分が理解しないまま差分だけが増えていきます。先に変更地図をAIに出させて、自分が納得してから書かせる。この順番を守るだけで、「AIに振り回される」から「AIを動かす」に変わります。

そしてこれこそが、プログラミングのスキルとAIと協働するスキルが同時に身につく瞬間です。コードを読む観点を持つと、AIへの指示が一段くっきりするんです。

まとめ:読む力は「1問のプロンプト」から育つ

5つの観点は、全部「AIに1問投げる」だけで始められます。

観点 これ1問で読むプロンプト
① 流れ 入力・処理・出力に分けて、それぞれ1行で説明して
② 役割 この関数を1文で。小学生に説明するつもりで
③ 分岐 失敗しうる箇所と、その時ユーザーに返る結果を全部
④ 依存 依存している外部(テーブル/API/env/ライブラリ)を用途付きで
⑤ 改修 "○○したい"。変更が必要な箇所をファイル単位で。コードはまだ書かないで

「動いた」で閉じるか、この5問を投げてから閉じるか。差は小さく見えますが、積み重なると自分のアプリを自分で育てられるかどうかという大きな差になっていきます。AIが書く時代だからこそ、読む力がそのまま自走力です。


未経験者向けの講座を運営しています

未経験から Next.js + Supabase + Claude Code で Webアプリを公開するまで を、全20セッションで体系化した教材です。今回のような「AIが書いたコードを読んで、自分で直す」練習を、手を動かしながら進められます。プログラミングと、AIと協働するスキルが同時に身につく構成にしています。

※ Qiita 読者の方にはやさしすぎる内容です。未経験の知り合いへの紹介や、社内研修・新人育成の参考としてどうぞ。

4
5
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
5

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?