ミスに気づかないのはなぜ|黙るコマンド・遅れる影響・思い込み

エラーが出ないから成功、とは限りません。ミスが静かに通り抜ける仕組みと、それでも気づくための習慣を整理します。

ミスが静かに通り抜ける仕組みと、期待値の事前記入や別手段での確認など気づくための習慣の対比
ミスが静かに通り抜ける仕組みと、期待値の事前記入や別手段での確認など気づくための習慣の対比

本番作業のミスで厄介なのは、ミスそのものより「ミスに気づくのが遅れること」です。誤った UPDATE も、すぐ気づいて報告すれば被害は小さく済みます。ところが実際には、作業者は成功したと思って作業を終え、翌朝の問い合わせで初めて発覚する、という流れがよく起きます。気づけないのは注意力が足りないからではなく、ミスが静かに通り抜ける仕組みがいくつもあるからです。この記事では、その仕組みと、気づくための具体的な習慣を整理します。

成功しても失敗しても静かなコマンド

Unix の多くのコマンドは、うまくいったときに何も表示しません。「言うべき意外なことがなければ黙る」という考え方は、Unix の沈黙の原則(Rule of Silence)と呼ばれます。cp、mv、chmod、ln などは成功すると何も出さずにプロンプトへ戻ります。出力を別のコマンドにつなぐ前提の設計としては合理的ですが、人間の側から見ると「何も出ない」が成功の合図になり、確認の習慣が育ちにくくなります。

さらに、失敗まで静かになる書き方があります。rm -f は存在しないファイルを指定してもエラーを出しません。2>/dev/null でエラー出力を捨てていれば、失敗のメッセージは画面に届きません。シェルスクリプトに set -e が無ければ、途中の cp が失敗しても次の行に進み、最後に「完了しました」と表示されます。画面の最後の行だけを見ていると、途中の失敗は見えません。

cp -v app.conf /etc/app/app.conf   # -v でコピーした内容を表示するecho $?                            # 直前のコマンドの終了コード(0 が成功)ls -l /etc/app/app.conf            # 更新時刻とサイズが変わったかdiff app.conf /etc/app/app.conf    # 中身が一致すれば何も出ない
黙るコマンドの結果を自分から確かめる

終了コードは $? で見られますが、次のコマンドを実行すると上書きされるので、確かめるなら直後に見ます。-v(verbose)を付けられるコマンドは、付けて実行するだけで「何をしたか」が画面に残ります。黙るコマンドを使うときほど、結果を自分から問い合わせる一手を足すのが基本です。

エラーではなく「正しく実行された間違い」

エラーは、コンピュータが「その命令は実行できない」と教えてくれる仕組みです。逆に言えば、文法として正しく、権限もある命令は、意図と違っていても黙って実行されます。WHERE user_id = user_id は文法上正しい条件で、NULL でない全行で真になります。日付の範囲を 1 桁間違えた条件も、存在する列を指していれば何の警告もなく通ります。

このとき誤りを知らせてくれる唯一の手がかりが、影響行数です。MySQL なら Query OK, 48213 rows affected、PostgreSQL なら UPDATE 48213 のように、何行が変わったかが表示されます。ところが、この数字を「想定は何件か」と比べなければ、ただの完了メッセージとして読み流してしまいます。エラーが出ないことを確認するのではなく、出た数字が想定どおりかを確認する、と考え方を切り替える必要があります。

桁を見る

想定 300 件に対して 31877 件、1 件のつもりが 48213 件。件数を読むときは、まず桁が合っているかを見ます。細かい数字の一致より先に、桁の違いに気づけるかどうかが分かれ目です。

影響が遅れて出る

作業直後に確認して問題が無くても、誤りが後から表に出ることがあります。変更とその影響の間に、時間差を生む仕組みが挟まっているからです。作業直後の確認は「今見える範囲では問題ない」ことしか示しません。

時間差を生む仕組み作業直後に見えること後から起きること
アプリや CDN のキャッシュ古いキャッシュが返るので画面は正常キャッシュが切れた時点で誤った設定やデータが出る
DNS の TTL手元はまだ古いレコードを引いているTTL が切れた利用者から順に新しい誤った宛先へ向かう
cron や夜間バッチ設定ファイルは書き換わっている夜中のバッチが誤った設定で動き、朝に気づく
翌朝の集計・帳票元データの更新は成功している集計値が前日と大きくずれて問い合わせが来る
証明書・パスワードの期限今は有効なので接続できる期限の日に突然つながらなくなる

時間差のある変更では、作業の記録に「いつ、何で確かめるか」を書き、その時刻にもう一度確認します。キャッシュを経由しない確認方法(オリジンに直接リクエストする、dig で権威サーバーに問い合わせる、バッチを手動で 1 回だけ流すなど)が使えるなら、それも作業手順に入れておきます。

見たいものを見てしまう

確証バイアスとは、自分がすでに持っている考えに合う情報を探し、合うように解釈し、合わない情報を軽く扱う傾向のことです。「この UPDATE は正しい」と思っている人が結果を確認すると、正しいことを示す材料を探しに行きます。数字が多少おかしくても「データが多い日なのだろう」と、自分の考えに合う説明を先に見つけてしまいます。

自分で書いたコマンドや SQL を読み返すときも、書いた本人は意図を知っているので、書かれた文字ではなく頭の中の意図を読んでしまいます。注意深さの問題ではないので、自分の頭の外にある基準(事前に書いた期待値、手順書、他人の目)と比べる必要があります。

確認が自己完結している

確認したつもりでも、確認の前提を自分で作っていると、前提の誤りは見つかりません。たとえば、間違った条件で UPDATE した後に、同じ間違った条件で SELECT して「更新されている」と確かめても、条件の誤りは見えません。間違ったサーバーに入って作業し、同じサーバーで動作を確かめれば、検証は成功します。「検証環境では成功した」のに本番で失敗する、あるいは本番だと思って作業したら検証環境だった、という取り違えも、作業と確認が同じ前提に乗っていることで起きます。

  • 作業と同じ条件・同じ接続・同じ画面で確認している。
  • 「確認しました」と書いたが、どこを何で確かめたかを書いていない。
  • ログに毎回出る WARN に慣れ、新しい WARN が混ざっても読み飛ばしている。
  • 前回と同じ作業なので、今回の出力を前回の記憶と比べている。

毎回出る警告は特に危険です。いつも出ている警告を放置していると、警告そのものに目が慣れ、本当に重要な警告が出ても同じ色の文字として流れていきます。消せる警告は消す、消せない警告は手順書に「この警告は既知」と書いておく、という整理をすると、新しい警告が目に入りやすくなります。

気づく仕組みを作業の中に入れる

ミスに気づけない理由はどれも、頭の中だけで判断していることに行き着きます。対策は、判断の基準を頭の外に出し、作業とは独立した手段で確かめることです。次の手順は、どれも今日の作業からすぐに始められます。

  1. 実行前に期待値を書く。「更新は 3 件」「ファイルは 12 個」「応答は 200」を作業記録に先に書き、実行後の数字と並べる。
  2. 実行後は別の手段で確かめる。UPDATE の後は変更後の値で数え直す、デプロイ後はバージョンを返す画面やファイルのハッシュで確かめる。
  3. 第三者に見てもらう。手順と結果を、作業の前提を知らない人が読んで同じ結論になるかを確かめる。
  4. 監視とアラートを確認手段に含める。エラー率や処理件数のグラフを作業の前後で見比べる。
  5. 時間をおいてもう一度見る。キャッシュやバッチをまたぐ変更は、確認の時刻を決めて記録に残す。
  6. 他人が読める作業記録を残す。実行したコマンド、時刻、出力の要点、確かめた範囲と確かめていない範囲を書く。
-- 期待値: plan を 'pro' にするのは 3 件(id 101, 205, 318。いずれも今は pro 以外)SELECT COUNT(*) FROM users WHERE id IN (101, 205, 318) AND plan <> 'pro';  -- 3 のはずSELECT COUNT(*) FROM users WHERE plan = 'pro';  -- 作業前の件数を控えるUPDATE users SET plan = 'pro' WHERE id IN (101, 205, 318);-- 確認は更新後の値で数える(全体の pro 件数が作業前 + 3 になっているか)SELECT COUNT(*) FROM users WHERE plan = 'pro';
期待値を先に書き、作業とは違う条件で確かめる

最後の SELECT は、作業の条件(id の一覧)ではなく結果の側(plan の値)から数えています。作業前に控えた pro の件数と比べれば、増えた件数が 3 かどうかで、条件の誤りも、ほかの行を巻き込んだことも見つけられます。作業と同じ条件で確かめるより、別の方向から確かめるほうが、前提の誤りに強い確認になります。

ミスに早く気づけた人は、ミスをしなかった人ではなく、気づく仕組みを先に用意していた人です。気づいたら隠さずすぐに報告する。それも、被害を小さくする大事な手順の 1 つです。下の問題では、出力や件数から「静かな失敗」を見つける練習ができます。

問題で確かめる

この記事の内容を、制限時間つきの問題で確かめられます。

参考

よくある質問

エラーが出なければ作業は成功したと考えてよい?

考えてはいけません。多くのコマンドは成功しても何も表示せず、WHERE を誤った SQL のように意図と違っていても文法上正しい命令はエラーなく実行されます。影響行数、終了コード、変更後の状態を自分から確かめます。

自分で書いた SQL やコマンドの間違いに気づきにくいのはなぜ?

書いた本人は意図を知っているため、書かれた文字ではなく頭の中の意図を読んでしまうからです。実行前に期待値を書いておく、手順書と突き合わせる、他人に読んでもらうなど、自分の頭の外にある基準と比べると気づきやすくなります。

作業直後の確認で問題が無かったのに、翌日に障害になるのはなぜ?

キャッシュ、DNS の TTL、夜間バッチ、翌朝の集計のように、変更と影響の間に時間差を生む仕組みがあるからです。時間差のある変更は、いつ何で確かめるかを記録に書き、その時刻にもう一度確認します。

実行後の確認は、作業と同じ条件の SELECT でよい?

それだけでは不十分です。条件そのものが誤っていると、同じ条件で確かめても誤りは見えません。変更後の値から数え直す、作業前後の件数を比べるなど、作業とは別の方向から確かめます。

毎回出る警告は無視してよい?

放置すると警告に目が慣れ、新しい重要な警告を読み飛ばす原因になります。消せる警告は直し、消せないものは手順書に既知の警告として書いておくと、いつもと違う警告に気づきやすくなります。