AIコード説明

コードを分かりやすい言葉で理解

見知らぬコードの読み方:外から内へ

経験豊富なエンジニアは、コードを散文のように上から下へは読みません。外から内へ読みます。AI説明ツールも、同じやり方で使うときに最も役立ちます。 まず境界から。何が入り、何が出ていくのか。エントリーポイント(エクスポートされた関数、ルートハンドラ、メインループ)と出口(戻り値、投げられるエラー、データベースやファイルへの書き込み)を見つけます。各行が何をするか尋ねる前に、入力・出力・副作用を挙げてもらいましょう。その1つの質問が地図を描いてくれます。 2周目:具体的な値を1つ、コード全体で追跡します。現実的な入力(たとえば「ordersが空配列のuserオブジェクト」)を選び、1行ずつ追ってもらいます。特定の値を追跡すると、汎用的な要約が塗りつぶしてしまう分岐・破壊的変更・早期リターンが露わになります。 3周目:イディオムに名前を付けます。大半のコードは8割がパターン、2割が判断です。デバウンスのラッパー、指数バックオフ付きリトライループ、リデューサー — パターンに名前が付けば、本当に注意すべきはパターンからの逸脱だけになります。率直に聞きましょう。このうちどこが標準パターンで、どこがそこから外れているのか? 行単位で読むのはその後、しかも3つのパスを経てなお本当に不明瞭な部分だけです。200行のファイルなら、重要な行はたいてい20行ほどしか残りません。

AIコード解説が間違える箇所

AIによる解説の誤りにはパターンがあり、そのパターンはチェックできる程度に予測可能です。 幻覚APIは古典的な失敗です。存在しないパラメータ、別のライブラリにある似た名前のメソッド、別のメジャーバージョンの挙動を説明してしまう。モデルは学習時に見た何百ものライブラリを混ぜ合わせるため、lodashの呼び出しの説明がこっそりUnderscoreの挙動を述べていたり、pandasのコード解説が2バージョン前に削除された引数を引用していたりします。 副作用の欠落はより巧妙です。解説は関数が何を計算するかは要約しても、引数を破壊的に変更する、キャッシュに書き込む、個人情報をログに残す、分析イベントを送るといったことは省きます。要約は戻り値に偏りますが、現実のバグは副作用に住んでいます。必ず別途尋ねてください。このコードは自分のスコープの外でどんな状態を変えるのか? 古いイディオムの問題は両刃です。モデルは完全に現代的なコードを「時代遅れ」と呼ぶこともあれば、廃止されたパターン(var、componentWillMount、Python 2の除算の意味論)を普通のものとして提示することもあります。どちらの時代も学習データに存在するからです。「現在のベストプラクティス」に関する主張は、デフォルトで期限切れとみなしましょう。 最後に、自信満々の計算量の主張。「これはO(n log n)で動く」は、モデルが流暢に、そして間違って生成する典型的な文です。sortやincludes、スプレッドのようにライブラリ呼び出しの中にループが隠れている場合は特に。計算量が重要なら、自分で導出するか、公式を断言させるのではなく具体的な入力サイズで演算回数を数えさせてください。

説明の深さを合わせるプロンプト

「このコードを説明して」は、コードを自然言語で言い直しただけの段落を生みます。技術的には正しく、ほとんど役に立ちません。解決策は、自分が既に知っていることと、その説明が支えるべき判断を宣言することです。 初心者なら、比喩とトレースをセットで要求しましょう。「このコードがすることを現実世界の比喩で説明し、次に例の入力を1つ、ステップごとに通してみせて」。トレースのない比喩は漠然とした安心感しか与えず、比喩のないトレースは状態変化の壁を築くだけです。 言語は読めるがこのコードベースは初めてなら、構文は丸ごと飛ばします。「JavaScriptはよく知っている前提で、意図、自明でない判断、保守者が驚きそうな箇所だけを説明して」。コードレビューの準備において、最もレバレッジの効くプロンプトです。 デバッグ中なら、説明ではなく反論を求めてください。「作者はこの関数がソート済みのコピーを返すと信じている。特定の行を根拠に、その信念への賛否を論じて」。モデルは語り手より批評家として振る舞わせたときのほうが、目に見えて問題を見つけるのが上手くなります。 このツールのレベル選択は、こうした枠組みを代わりに書いてくれます。生成されたプロンプトを編集し、漠然としたレベルではなく実際の言語経験を明記してください。
Instead of:
"Explain this code."

Try:
"I know Python well but have never used asyncio.
1. What is the intent of this function in one sentence?
2. Trace the input [3, 1, 2] through it line by line.
3. List every side effect (I/O, mutation, global state).
4. What would surprise a maintainer? What could break
   under concurrency?
Do not explain basic syntax."

実例:言い直しの説明と役に立つ説明

ほとんどの解説ツールが同じように浅く説明する、5行の関数を見てみましょう。下のスニペットはメールアドレスでユーザーを重複排除し、最後の出現を残します。 言い直しの説明はこう言います。「この関数はusers配列を反復し、メールアドレスをキーとするMapを構築し、Mapの値を配列として返す」。一語一句正しい。そして何も役に立ちません。コードを音読しただけです。 役に立つ説明は、コードが投げかける疑問に答えます。なぜSetやオブジェクトではなくMapなのか?(Mapは挿入順を保持し任意のキー型を許します。ここでは順序こそが要点です。)なぜ最後の重複が勝つのか?(Map.setは上書きするので、後の要素が前の要素を置き換えます。配列が古い順に並んでいれば、このコードは静かに最新レコードを残します。それが意図かどうかは別問題です。)鋭い角はどこか?(大文字小文字だけ違うメールは別物として扱われ、undefinedのメールは1つのバケツに潰れ、返される配列は新しくても中のuserオブジェクトは共有参照なので、変更すると呼び出し元に影響します。) この最後の段落こそ、あらゆる解説ツールに要求すべきものです。コードが何をするかではなく、何を決め、何を仮定し、どこであなたを傷つけ得るか。説明の中に「注意点」で始まる文が1つもなければ、もう一度聞き直してください。
function dedupeUsers(users) {
  const byEmail = new Map();
  for (const u of users) byEmail.set(u.email, u);
  return [...byEmail.values()];
}

Shallow: "Builds a Map keyed by email and returns its values."

Useful:  "Keeps the LAST user per email (Map.set overwrites).
          Case-sensitive: [email protected] and [email protected] stay separate.
          Returned array is new, but user objects are shared
          references — mutating them affects the original."

2分でできる検証ルーチン

すべてのAI解説を、自信満々のインターンの下書きとして扱ってください。だいたい正しく、ときどき重要な箇所で間違え、その違いを自分では決して認識しません。 言及されたAPIは実際のドキュメントと照合しましょう。モデルの記憶とではなく。説明が特定の関数の挙動(radixなしのparseInt、その場で破壊的にソートするArray.sort、ライブラリのデフォルト値)に懸かっているなら、ドキュメント確認は30秒で済み、最も被害の大きい誤りを捕まえられます。 トレースを実行してみましょう。解説ツールが入力をコードに通してみせたなら、その入力をREPLや使い捨てテストで実際に実行して比較します。語られたトレースと実際の出力のずれは、説明が間違っているという最強のシグナルです。 危険な主張は反対尋問にかけます。並行処理・破壊的変更・エラー処理・性能に関する内容は、新しいセッションで表現を変えて同じ質問をもう一度。一貫した答えは正しさの弱い証拠であり、一貫しない答えは、いま見ているものが当て推量だという強い証拠です。 どれも大した手間ではありません。その代わりに、検証されていない言い換えだけで理解したコードを出荷すること — それこそが、微妙な本番バグの生まれ方です。