AIに頼んだ関数が動いた。画面にも、それらしい金額が出ている。それでも、自分のアプリへ取り込む直前になると「このまま使って大丈夫だろうか」と手が止まることがあります。
その不安を減らすには、AIにもう一度「正しい?」と聞くより、どの入力なら、いくらになるべきかを自分で決めて確かめる方が判断材料になります。今回の例では、999円と1,001円に正しく答える関数が、間の1,000円だけで間違います。
短い割引関数を使い、期待値を決める、失敗を見つける、修正を確かめる、取り込みを判断するところまで進めます。読み終えたら、手元の小さな計算関数について「何を確認したので採用するか」「何が不明なので保留するか」を説明できる状態を目指します。
Node.jsでファイルを実行できる方が対象です。執筆時はWindows・Node.js v24.19.0で2026年10月30日に実行し、公開前の独立検証でもLinux・Node.js v24.19.0で同じ出力を確認しました。認証や外部通信を伴うアプリ全体の安全性を、この例だけで判定することはできません。
先に決めるのは、正解となる金額
今回の仕様は「購入額が1,000円以上なら100円引き」です。金額は0以上の安全な整数で受け取り、文字列・負数・小数などは拒否します。
ここでコードを見る前に、次の3件の答えを決めてください。
| 購入額 | 期待する支払額 | 確かめること |
|---|---|---|
| 999円 | 999円 | 割引条件の直前では引かない |
| 1,000円 | 900円 | 条件に一致した瞬間から引く |
| 1,001円 | 901円 | 条件を超えても引く |
「1,000円以上」の「以上」が、真ん中の行に現れています。通常の購入額を何十件試しても、この一行を外すと境界の誤りは残り得ます。
期待値をAIの関数から計算すると、同じ誤りを正解側へ写すおそれがあります。まず日本語の仕様から手で答えを出すことが、検証の出発点です。税や端数処理があるなら、その答えを誰が決めるかも先に確定します。
2件は成功する提案例を、境界の1,000円で見破る
新しい練習用フォルダを作り、次をverify.mjsとして保存します。外部パッケージのインストールは不要です。
proposedが検証する提案例、fixedが修正版です。どちらも同じ期待値で評価します。この例にはファイル削除や外部通信はありません。未知のAI生成プログラム一般を、確認せず自分の端末で実行してよいという意味ではありません。
import assert from 'node:assert/strict';
const proposed = yen => yen > 1000 ? yen - 100 : yen;
function fixed(yen) {
if (!Number.isSafeInteger(yen) || yen < 0) throw new TypeError('invalid yen');
return yen >= 1000 ? yen - 100 : yen;
}
for (const [input, expected] of [[999,999],[1000,900],[1001,901]]) {
console.log(`proposed ${input}: ${proposed(input) === expected ? 'PASS' : 'FAIL'}`);
assert.equal(fixed(input), expected);
}
for (const input of [-1, NaN, 1.5, '1000']) assert.throws(() => fixed(input), TypeError);
console.log('fixed: 3 boundary cases + 4 invalid inputs PASS');
保存したフォルダで実行します。
node verify.mjs
実際の出力は次のとおりでした。
$ node verify.mjs
proposed 999: PASS
proposed 1000: FAIL
proposed 1001: PASS
fixed: 3 boundary cases + 4 invalid inputs PASS
終了コードは0(正常終了)でした。proposed 1000: FAILは、練習の失敗ではありません。誤った提案を見つけられた証拠です。提案例の>は1,000円を割引対象に含めません。修正版の>=は含めます。修正版は3件の境界値に加え、不正入力4件を例外として拒否できたので、最後のPASSまで進んでいます。
なお、提案例の不一致は表示するだけなので、このファイルが正常終了したこと(終了コード0)だけでは提案例の合格を意味しません。修正版の検査はassertで止まるようにしてあります。テストの「終了した」と「何が通った」を分けて読んでください。終了コードを自分で確かめたい場合は、bash系のターミナルならnode verify.mjs; echo "exit=$?"、PowerShellならnode verify.mjs; $LASTEXITCODEと実行します。
出力が違ったら、関数を直す前に検証の入口を確かめる
| 起きたこと | まず確認する場所 | 次の行動 |
|---|---|---|
nodeが見つからない |
Node.jsの導入とターミナルの環境 |
node --versionで実行可能か確かめる。まだ関数の問題とは判断しない |
| ファイルが見つからない | 現在のフォルダとファイル名 |
verify.mjs.txtなどになっていないか、保存先を確認する |
| 構文エラーで始まらない | コピーしたファイル | Markdownの囲み記号まで保存していないか確認する |
| 提案例の1,000円までPASSになる |
proposedの条件 |
先に修正版へ置き換えていないか比較する |
| 修正版のassertで止まる | 例外に出た実値・期待値 | 期待値を実値に合わせず、日本語の仕様と変更箇所を照合する |
この表は、結果が一致しない場合の確認順です。各環境トラブルを今回すべて再現したわけではありません。
不一致を見つけるたびに期待値を変更すると、テストが実装に追従するだけになります。「仕様を変えた」のか「実装を直した」のかを区別し、後者なら元の期待値で通るまで確認します。
自分のコードへ移すときは、入力の種類と影響範囲を広げる
割引関数なら、0円、ちょうど1,000円、上限付近、不正な型を候補にできます。文字数制限なら「上限の1文字前・一致・1文字超過」、件数制限なら「0件・1件・上限」に読み替えられます。共通しているのは、処理の分かれ目を、日本語から具体的な値へ変えることです。
ただし、関数だけが正しくても呼び出し側が文字列の'1000'を渡していれば、今回の修正版は拒否します。その場合は関数の検査を外す前に、「入力を数値に変換する責任はどこにあるか」を確認してください。フォームから呼ぶなら、実際の入力がどの型で届くかを別途確かめる必要があります。
自分のプロジェクトに取り込む前には、まずgit status --shortで対象ファイルを確認します。??で表示される新規の未追跡ファイルは通常のgit diffに出ないため、ファイルを直接開いて全体を読みます。差分が空でも、追加されたコードがないとは限りません。
追跡済みの変更には、git diff --checkで空白などの問題を調べ、git diff --で変更内容を確認します。ステージ済みなら--cachedを付けた差分が対象です。これらはコードの正しさや安全性の判定そのものではありません。割引条件の修正に、無関係な設定変更や新しい依存関係が混ざっていないかを読むために使います。
「採用してよい」の範囲を、一文で残す
今回なら、次のように判断できます。
整数の円額に対する100円引き処理として、境界3件と不正入力4件を確認した。税・端数処理・クーポン併用は対象外なので、それらを使う箇所へはこの結果だけで採用しない。
判断を保留すべきなのは、期待値を決められない、テストが失敗する、変更の理由を説明できない、必要な実行環境を用意できない場合です。保留は作業の後退ではなく、何を確かめれば進めるかが明らかになった状態です。
次にAIから関数を受け取ったら、実行ボタンを押す前に「条件が切り替わる入力」を一つ探してください。成功例を眺めるだけだった確認が、採用の根拠を作る確認へ変わります。
参考資料(一次情報)
このテーマを自分でも試して学びたい方へ。プログラミング学習サービスのCodeNestでは、AIに質問しながらコードを書いて学べます(運営:Hatch IT)。
