ミスに気づかないのはなぜ|黙るコマンド・遅れる影響・思い込み
エラーが出ないから成功、とは限りません。ミスが静かに通り抜ける仕組みと、それでも気づくための習慣を整理します。
本番作業のミスで厄介なのは、ミスそのものより「ミスに気づくのが遅れること」です。誤った 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 が混ざっても読み飛ばしている。
- 前回と同じ作業なので、今回の出力を前回の記憶と比べている。
毎回出る警告は特に危険です。いつも出ている警告を放置していると、警告そのものに目が慣れ、本当に重要な警告が出ても同じ色の文字として流れていきます。消せる警告は消す、消せない警告は手順書に「この警告は既知」と書いておく、という整理をすると、新しい警告が目に入りやすくなります。
気づく仕組みを作業の中に入れる
ミスに気づけない理由はどれも、頭の中だけで判断していることに行き着きます。対策は、判断の基準を頭の外に出し、作業とは独立した手段で確かめることです。次の手順は、どれも今日の作業からすぐに始められます。
- 実行前に期待値を書く。「更新は 3 件」「ファイルは 12 個」「応答は 200」を作業記録に先に書き、実行後の数字と並べる。
- 実行後は別の手段で確かめる。UPDATE の後は変更後の値で数え直す、デプロイ後はバージョンを返す画面やファイルのハッシュで確かめる。
- 第三者に見てもらう。手順と結果を、作業の前提を知らない人が読んで同じ結論になるかを確かめる。
- 監視とアラートを確認手段に含める。エラー率や処理件数のグラフを作業の前後で見比べる。
- 時間をおいてもう一度見る。キャッシュやバッチをまたぐ変更は、確認の時刻を決めて記録に残す。
- 他人が読める作業記録を残す。実行したコマンド、時刻、出力の要点、確かめた範囲と確かめていない範囲を書く。
-- 期待値: 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 つです。下の問題では、出力や件数から「静かな失敗」を見つける練習ができます。
問題で確かめる
この記事の内容を、制限時間つきの問題で確かめられます。