1.なぜAIが書いたコードを検証するのか
AIコーディングアシスタントは、数秒でもっともらしいコードを書いてくれます。文法もきれいで、説明も自信ありげです。しかしAIは「よく見かける形のコード」を生み出しているのであって、自分のデータと自分の状況で実際に動かしてから答えているわけではありません。そのため、ありふれた入力では正しいのに空の値や境界値では間違えるコードや、動くことは動いても危険なコードが混じることがあります。
コードを実行し、その結果を使うのは自分です。売上の合計が間違って報告書が誤ったまま出ても、パスワードの入ったコードが公開されても、「AIがそう書いた」では済みません。結果を確かめて責任を負うのは、そのコードを使った人と組織です。第9講までに学んだ値・条件・繰り返し・関数・配列・文字列の知識は、まさにこの検証のための道具です。短いコードを自分で読めれば、AIをずっと安全に、上手に使えます。
検証は大きく四つに分かれます。コードが何をするのかを読んで理解すること、自分で作ったテストで結果を確かめること、セキュリティ上の危険を点検すること、ライセンスや個人情報のようなコードの外の問題を確認することです。この講義ではこの順に一つずつ練習します。
- 読む:この関数は何を受け取り、何を返すのか
- テスト:ありふれた入力、空の値、0、境界値で期待どおりの値が出るか
- セキュリティ:秘密情報、検証していない入力、
eval、見慣れないパッケージはないか - コードの外:ライセンスの条件と会社・学校の方針、個人情報を守ったか
2.1行ずつ読む — 入力・処理・出力
AIからもらったコードを読むときは、最初から最後までざっと眺めるのではなく、第1講で学んだ「入力 → 処理 → 出力」の枠に当てはめて見ます。関数名と引数を見て何を受け取るのか、return を探して何を返すのかを先に確かめます。それから途中の行を一つずつ指でたどり、「この行が終わったとき変数には何が入っているか」を言葉で説明してみます。説明に詰まる行こそ、確かめるべき場所です。
読みながら「もしも」の問いを投げかけます。配列が空だったら?値が文字列で入ってきたら?0や負の数だったら?下の平均の関数は、ふつうの点数では正確ですが、空の配列だと 0 / 0 となって NaN が出ますし、CSVから取り出した文字列の点数が入ってくると + が連結になって、とんでもない値を返します。エラーメッセージも出ずに間違った値が出るので、なおさら危険です。
わからない書き方が出てきたら、AIに「この行がしていることを初心者向けに説明して」と尋ねてもかまいません。ただし説明を聞いたあとは、第8講で学んだとおり console.log で途中の値を出して、その説明が実際と合っているかを自分で確かめます。説明もAIの答えなので、確かめる対象です。
// AIコーディングアシスタントが書いた関数(そのまま)
function averageScore(scores) {
let sum = 0;
for (const s of scores) {
sum += s;
}
return sum / scores.length;
}
console.log(averageScore([80, 90, 100]));
console.log(averageScore([]));
console.log(averageScore(["80", "90"]));90 NaN 4045
3.テストを自分で作る — 境界値がバグを見つける
テストとは、「この入力を入れたらこの値が出るはずだ」を前もって書いておき、コードで確かめることです。期待値は、コードを見る前に自分の手で決めます。AIにテストまで任せると、コードと同じ思い違いをテストにも入れてしまうことがあるので、少なくともいくつかは自分で作ります。下の check 関数のように、受け取った値と期待値を比べて「合格/不合格」を出す小さな道具があれば十分です。
よいテストの組には、ふつうのケースと一緒に境界のケースが入っています。空の配列・空文字列、0、負の数、値が一つだけの場合、条件が切り替わるちょうどその値(第3講の境界値)、桁数の違う数、同じ値がいくつもある場合などです。バグはたいてい、こうした端のほうに隠れています。
下は「AIが書いた上位の点数を取り出す関数」です。2桁の点数だけで試すと合格するので、正しいコードに見えます。ところが100点が混じると間違えます。JavaScriptの sort() は、比較関数を渡さないと値を文字列に変えて辞書順に並べるため、"100" が "80" より前に来るのです。しかも sort は元の配列の順序を変えてしまうので、この関数を呼び出した側のデータまでこっそり変わります。
function check(name, got, want) {
const same =
JSON.stringify(got) === JSON.stringify(want);
console.log(same ? "合格" : "不合格", name, got);
}
// AIが書いた関数:高い点数をn個
function topScores(scores, n) {
return scores.sort().reverse().slice(0, n);
}
check("2桁", topScores([70, 90, 85], 2), [90, 85]);
check("100点", topScores([100, 95, 80], 2), [100, 95]);
check("nが0", topScores([70, 90], 0), []);
const mine = [70, 90, 85];
topScores(mine, 1);
console.log("元の配列", mine);合格 2桁 [ 90, 85 ] 不合格 100点 [ 95, 80 ] 合格 nが0 [] 元の配列 [ 90, 85, 70 ]
(a, b) => b - a で並べ替え、大きい数から順に置きます。function topScores(scores, n) {
const copy = [...scores];
copy.sort((a, b) => b - a);
return copy.slice(0, n);
}
const mine = [100, 95, 80];
console.log(topScores(mine, 2));
console.log(topScores([], 3));
console.log("元の配列", mine);[ 100, 95 ] [] 元の配列 [ 100, 95, 80 ]
// AIが書いた関数(そのまま)
function shippingFee(price) {
return price > 50000 ? 0 : 3000;
}
for (const p of [49999, 50000, 50001]) {
console.log(p, shippingFee(p));
}49999 3000 50000 3000 50001 0
- ステップ1 規則から境界を見つけます。条件が切り替わる値は50,000ウォンです。
- ステップ2 境界のすぐ下・境界・すぐ上を選びます:49,999ウォン → 3,000、50,000ウォン → 0、50,001ウォン → 0。
- ステップ3 端の値やおかしな値を加えます:0ウォン、負の数、文字列 "50000" を入れたときにどうすべきかを先に決めます。
- ステップ4 実行してみると、50,000ウォンで3,000が出ました。コードを読むと、
>=ではなく>と書かれていました。
> を >= に直すべきことを見つけ出しました。4.セキュリティ — 秘密情報、入力の検証、`eval`
まず守るべき原則は、パスワード・APIキー・アクセストークンのような秘密情報をコードやプロンプトに入れないことです。コードに書かれたキーは、ファイルの共有、リポジトリの公開、画面のキャプチャから簡単に漏れます。AIアシスタントにエラーについて尋ねるとき、キーの入ったコードを丸ごと貼り付けるのも同じ危険です。キーの部分は "YOUR_API_KEY" のような偽の値に置き換えて見せ、本物のキーは各サービスが案内する方法(環境変数、設定ファイル、秘密情報の管理機能など)でコードの外に置きます。キーがすでに漏れてしまったなら、消すだけでは足りないので、そのサービスでキーを無効にして新しく発行し直します。
二つ目は入力の検証です。利用者の入力、ファイル、ほかのプログラムから来る値は、いつでも予想と違う可能性があると考え、使う前に形と範囲を確かめます。AIが書いたコードは「正常な入力」だけを前提にしていることがよくあります。下のように受け入れる形を先に決め、それ以外の値は null で断るやり方が安全です。「悪い値を選んではじく」より「よい値だけを受け入れる」ほうが漏れが少なくなります。
三つ目に、信頼できない入力を eval や new Function に渡してはいけません。eval は文字列をコードとして実行するので、入力に隠された命令がそのまま実行されるおそれがあります。電卓や設定の読み込みを頼んだのに、AIが eval を使ったコードを返してきたら、別の方法を求めましょう。データのやりとりが目的なら、第6講のJSONを JSON.parse で読めば済みます。JSON.parse はデータを読むだけでコードは実行せず、形式が間違っていればエラーを出します。
^\d+$ は「最初から最後まで数字だけ」という意味です。受け入れる範囲の外はすべて null です。// 0〜150の整数の年齢だけを受け入れる
function parseAge(input) {
const s = String(input).trim();
if (!/^\d+$/.test(s)) return null;
const n = Number(s);
if (n > 150) return null;
return n;
}
const tries = ["35", " 7 ", "-3", "2.5", "abc", "", "999"];
for (const x of tries) {
console.log(JSON.stringify(x), "→", parseAge(x));
}"35" → 35 " 7 " → 7 "-3" → null "2.5" → null "abc" → null "" → null "999" → null
JSON.parse は、コードのように見える文字列を実行せず、SyntaxError で断ります。try { … } catch (e) { … } は、エラーが起きても止まらずに catch 側でエラーを受け取って処理する書き方です。const input = '{"name": "健太", "score": 90}';
const data = JSON.parse(input);
console.log(data.name, data.score);
try {
JSON.parse("console.log('こっそり実行')");
} catch (e) {
console.log("拒否:", e.name);
}健太 90 拒否: SyntaxError
5.存在しないパッケージ — インストールの前に確かめる
実務のコードでは、ほかの人が作って公開したパッケージ(ライブラリ)をインストールして使うことがよくあります。ところがAIアシスタントは、もっともらしいのに実際には存在しないパッケージ名をでっち上げたり、ずっと前に保守が止まったパッケージを勧めたりすることがあります。さらに大きな問題は、誰かがこうしてよくでっち上げられる名前や、有名なパッケージと1文字だけ違う名前で、悪意のあるパッケージを先に登録しておけるという点です。確かめずにインストールのコマンドをそのまま実行すると、自分のコンピューターで他人のコードが動くことになります。
そこで、インストールのコマンドを実行する前にいくつか確かめます。そのパッケージが公式のパッケージリポジトリに実際にあるか、名前のつづりが公式ドキュメントとまったく同じか、最近まで保守されているか、公開されたソースリポジトリとドキュメントがあるか、広く使われているかを見ます。会社や学校では、許可されたパッケージの一覧やセキュリティ審査の手続きが別にあることもあるので、その決まりにまず従います。
小さな仕事なら、パッケージなしで解決できないかも尋ねてみましょう。第9講のテキスト整理や合計の計算は、JavaScriptの標準機能だけで十分でした。依存するパッケージが少ないほど、確かめることも、問題が起きる場所も減ります。ただし、本物のCSVファイルの読み込みや暗号化のように規則が込み入った仕事は、自分で書くより実績のあるパッケージを選ぶほうが安全です。
- 公式のパッケージリポジトリにその名前が実際にあるか
- つづりが公式ドキュメントとまったく同じか(1文字違いの偽の名前に注意)
- 最近の更新があり、保守されているか
- ソースリポジトリ・ドキュメント・ライセンスが公開されているか
- 会社・学校の許可リストとセキュリティの手続きを守ったか
6.著作権・ライセンスと個人情報
公開されているコードだからといって、自由に使ってよいわけではありません。オープンソースのコードにはライセンスが付いており、ライセンスとは「この条件を守れば使ってよい」という約束です。条件はライセンスごとに異なります。著作権表示とライセンスの文言を一緒に残すという条件がよく見られ、ライセンスによっては、そのコードを組み込んだプログラムを配布するときにソースコードを同じ条件で公開するよう求めるものもあります。ライセンスの表示がまったくないコードは、公開されていても利用を許可したという意味ではないことがあります。
AIが作ったコードが、既存の公開コードとよく似ている可能性もあります。長いコードの断片をそのまま製品に入れる前には、出どころを確認できるか、会社や学校にAI生成コードやオープンソースの利用に関する方針があるかを調べましょう。下の表はよくある種類の一般的な特徴にすぎず、法的な助言ではありません。実際の条件はライセンスの原文を読んで確かめ、判断が難しければ所属先の担当部署や専門家に確認します。
個人情報もコードの外の大切な問題です。AIにコードを頼むときに実際の顧客名簿、生徒の成績、電話番号を貼り付けると、その情報は自分の管理から離れてしまいます。コードを作るのに必要なのはデータの「形」であって、本物の値ではありません。下のように偽のデータを作って見せ、本物のデータは自分のコンピューターの中だけで動かしましょう。例に使うアドレスには、説明用に予約されている example.com のようなドメインを使えば、実在の人に届くことはありません。結果を共有するときは、電話番号の真ん中を隠すなど、必要な分だけを見せます。
function fakeCustomers(n) {
const list = [];
for (let i = 1; i <= n; i++) {
const no = String(i).padStart(4, "0");
list.push({
id: i,
name: "顧客" + i,
phone: "090-0000-" + no,
email: "user" + i + "@example.com",
});
}
return list;
}
console.log(fakeCustomers(2));[ { id: 1, name: '顧客1', phone: '090-0000-0001', email: '[email protected]' }, { id: 2, name: '顧客2', phone: '090-0000-0002', email: '[email protected]' } ]| 種類 | 例 | よくある条件 |
|---|---|---|
| 寛容型 | MIT, BSD | 複製・改変・商用利用を広く認める。著作権表示とライセンスの文言を一緒に残す |
| 寛容型(特許条項つき) | Apache-2.0 | MITと同様に広く認める。ライセンスの写しと告知を残し、変更したファイルには変更した旨を示す。特許に関する条項がある |
| コピーレフト | GPL系 | そのコードを含むプログラムを配布するとき、同じライセンスでソースコードを提供しなければならないなど、条件がより強い |
| 表示なし | ライセンスファイルのない公開コード | 公開されていても利用の許可があるという意味ではないことがある。使う前に確認する |
7.検証の手順を習慣に
AIからコードを受け取るたびに同じ順序で確かめる習慣をつければ、見落としが減ります。まず、自分が頼んだことと、コードがしていることが同じかを読み、わからない行は説明を聞いたうえで console.log で確かめます。次に、期待値を自分で決めたテストを、ふつうのケース二、三個と境界のケース三、四個で作って実行します。
テストが不合格なら、不合格になった入力と受け取った値、期待値を整理して、AIにもう一度尋ねればよいのです。第8講で学んだように、「間違ってる」よりも「入力 [100, 95, 80] に対して期待は [100, 95]、実際は [95, 80]」のほうがずっと早く直ります。直したコードを受け取ったら、最初のテストをすべてもう一度実行し、一か所を直したせいでほかの場所が壊れていないかを確かめます。直す前後のコードをテキスト比較ツールに入れれば、何が変わったかを正確に見られます。
最後に、セキュリティとコードの外の点検をします。秘密情報が残っていないか、入力を検証しているか、eval がないか、見慣れないパッケージは確かめたか、ライセンスと個人情報の決まりを守ったかを見ます。この手順を経たコードであってこそ、「自分が責任を持てるコード」になります。これでコーディングの基礎のコースは終わりです。もう短いコードを読み、試し、直せるのですから、AIを助手にして、繰り返しの作業を一つずつコードに置き換えてみましょう。
- 目的の確認:頼んだことと、コードがしていることが同じか
- 1行ずつ読む:入力・処理・出力。詰まった行は
console.logで確かめる - テスト:期待値は自分で決め、境界値を必ず入れる
- 再実行:直したあとは、すべてのテストを最初から
- セキュリティ・コードの外:秘密情報、入力の検証、
eval、パッケージ、ライセンス、個人情報
📌 要点まとめ
- AIのコードは、ありふれた入力では正しく、境界では間違えることがある — 使う人が検証する
- 期待値を先に自分で決め、空の値・0・境界値・桁数の違う値をテストに入れる
sort()は比較関数がないと文字列の順に並べ替え、元の配列を変えてしまう- 秘密情報はコードにもプロンプトにも入れず、入力は検証し、信頼できない入力に
evalを使わない - パッケージは実在して保守されているかを確かめ、ライセンスの条件と方針を確認し、個人情報の代わりに偽のデータを使う
🧪 コード実習
AIが書いたように見えるコードの隠れたバグをテストで見つけて直し、入力の検証と個人情報を隠す関数を作ります。テスト結果では、まず不合格になった入力を見てください。
コードはこのブラウザの中の隔離された場所でだけ実行され、サーバーには送られません。ネットワークには接続できず、2秒を超えると止まります。書き換えたコードはこのブラウザにだけ保存されます。Ctrl+Enter(⌘+Enter)で実行、Tabキーは空白2つ(Escの後のTabで次へ移動)。
JavaScriptが無効なので実行はできませんが、問題・最初のコード・自動チェックの内容・解答例はそのまま読めます。
1平均の関数の境界を直す
AIが書いた average(nums) は、空の配列で NaN を返します。空の配列なら0を、それ以外なら平均を返すように直してください。配列には数値だけが入ってきます。
average([80,90,100])期待値90average([])期待値0average([0,0])期待値0average([-10,10,30])期待値10average([7])期待値7
💡 ヒント
関数のいちばん最初で、nums.length === 0 ならすぐに return 0; しましょう。
解答例を見る
function average(nums) {
if (nums.length === 0) return 0;
let sum = 0;
for (const x of nums) {
sum += x;
}
return sum / nums.length;
}2上位の点数の関数の並べ替えバグ
AIが書いた topScores(scores, n) は、高い点数 n 個を大きい順に返すはずですが、100点が混じると間違えます。数値の大きさで並べ替えるように直し、元の配列は変えないでください。n が配列の長さより大きいときは、ある分だけを返します。
topScores([70,90,85], 2)期待値[90,85]topScores([100,95,80], 2)期待値[100,95]topScores([5,100,20,9], 3)期待値[100,20,9]topScores([60,70], 0)期待値[]topScores([], 3)期待値[]topScores([88], 5)期待値[88]
💡 ヒント
[...scores] でコピーしてから sort((a, b) => b - a) で大きい数から並べ、slice(0, n) します。
解答例を見る
function topScores(scores, n) {
const copy = [...scores];
copy.sort((a, b) => b - a);
return copy.slice(0, n);
}3注文数量の入力を検証する
関数 parseQuantity(input) を完成させてください。文字列 input の前後の空白を消したあと、数字だけでできた整数で、1以上99以下ならその数を、そうでなければ null を返してください。"2.5"、"-1"、"1e3"、空文字列はすべて null です。
parseQuantity("3")期待値3parseQuantity(" 12 ")期待値12parseQuantity("0")期待値nullparseQuantity("100")期待値nullparseQuantity("2.5")期待値nullparseQuantity("1e3")期待値null
💡 ヒント
/^\d+$/.test(s) で数字だけかを見て、n < 1 || n > 99 なら null です。Number("") が0になる点にも注意しましょう。
解答例を見る
function parseQuantity(input) {
const s = input.trim();
if (!/^\d+$/.test(s)) return null;
const n = Number(s);
if (n < 1 || n > 99) return null;
return n;
}4電話番号の真ん中を隠す
結果を共有するときに個人情報を隠す関数 maskPhone(s) を作ってください。s が 090-1234-5678 のように数字の3-4-4の形なら、真ん中の4桁を **** に置き換えた 090-****-5678 を返し、この形でなければ null を返してください。
maskPhone("090-1234-5678")期待値"090-****-5678"maskPhone("090-0000-0001")期待値"090-****-0001"maskPhone("09012345678")期待値nullmaskPhone("")期待値nullmaskPhone("090-12-5678")期待値null
💡 ヒント
正規表現 /^\d{3}-\d{4}-\d{4}$/ は「数字3個-4個-4個」だけを通します。通らなければ null です。
解答例を見る
function maskPhone(s) {
if (!/^\d{3}-\d{4}-\d{4}$/.test(s)) return null;
const parts = s.split("-");
return parts[0] + "-****-" + parts[2];
}🤖 AIにはこう聞いてみましょう
コピーして [ ] の部分を自分の状況に書き換えて使います。答えはそのまま信じず、本文と比べて確かめましょう。
AIからもらったコードを理解したいとき
下のJavaScriptのコードを、初心者に説明するように1行ずつ説明してください。各行が終わったあとに主な変数に何が入っているかを、例の入力[例の入力]でたどってください。空の値・0・文字列が入ってきたらどうなるかも指摘してください。 [コード]
テストすべきケースを漏れなく洗い出したいとき
下の関数の目的は[目的]です。ふつうのケース、境界値、空の値、間違った入力に分けて、テストする入力の一覧を作ってください。期待値は私が自分で決めるので、入力と「なぜこのケースが大切か」だけを書いてください。 [関数のコード]
コードのセキュリティ・ライセンスを点検してほしいとき
下のコードをセキュリティの観点から点検してください。コードに残った秘密情報、検証していない入力、`eval` のような危険な機能、使っているパッケージが実在して保守されているかを確かめる方法を一覧にまとめてください。オープンソースのコードを持ってきた部分があれば、確認すべきライセンスの条件も一般的な範囲で教えてください(法的な助言でなくてかまいません)。コードのキーと個人情報は偽の値に置き換えてあります。 [コード]
🧰 関連ツール
この講義で扱ったJSON・正規表現・テキストを、その場で確かめたり整えたりできるツールです。本物の個人情報やパスワードは貼り付けないでください。
- MDN Web Docs — Array.prototype.sort、JSON.parse、evalのリファレンス(evalの使用を避けるよう勧める説明を含む)
- OWASP — 入力の検証と秘密情報の管理についての一般的な手引き
- Open Source Initiative — オープンソースライセンス(MIT、Apache-2.0、GPLなど)の原文と一般的な説明
学習目標をすべて達成できたら完了を押しましょう。
このブラウザでは保存できないため、この画面でのみ表示されます。