目次
- 本番テスト失敗とは?なぜ起きるのか
- 失敗が発覚した瞬間の初動3原則
- 問題を切り分ける4つの視点
- 効果的なログ調査テクニック
- チームへの報告・共有の型
- ロールバックと緊急修正の判断基準
- 再発防止と信頼回復のアクション
1. 本番テスト失敗とは?なぜ起きるのか
本番環境でのテスト失敗は、リリース直後や機能追加後に「期待した動作をしない」「エラーが出る」状態を指します。開発環境やステージング環境では問題なかったのに、本番だけで起きるケースが典型的です。
よくある5つの原因パターン
パターン1:環境差異による問題
- データベースのバージョンが開発環境と異なる
- 本番だけにある大量データで性能劣化
- 環境変数の設定ミス(APIキー、接続先URLなど)
パターン2:タイミング依存の問題
- 同時アクセスによる競合状態
- キャッシュの不整合
- バッチ処理との干渉
パターン3:外部サービス連携の問題
- サードパーティAPIの仕様変更
- 決済システムやメール配信サービスとの連携エラー
- ネットワーク遅延やタイムアウト
パターン4:データ移行・初期化の問題
- マスターデータの不足
- 既存データとの整合性エラー
- 初期セットアップの漏れ
パターン5:権限・セキュリティの問題
- ファイアウォール設定による通信ブロック
- アクセス権限の不足
- CORS(Cross-Origin Resource Sharing)エラー
本番テスト失敗が起きやすい3つのタイミング
- 新機能リリース直後:実装した機能が本番データと組み合わさって初めて問題が顕在化
- インフラ変更後:サーバー移行、DBアップグレード、CDN設定変更など
- ピーク時間帯:アクセス集中時に性能問題やリソース不足が発覚
2. 失敗が発覚した瞬間の初動3原則
テスト失敗を発見したら、まず次の3つを徹底してください。
原則1:即座にチームへ第一報(30秒以内)
【第一報テンプレート】
⚠️ 本番テスト失敗を確認しました
・機能:〇〇機能
・症状:△△ができない/エラーが出る
・影響:ユーザーの□□操作に影響あり
・対応:現在調査中、5分後に続報します
SlackやTeamsなど、チームの決まったチャンネルに投稿します。完璧な情報でなくてOK。とにかく「問題が起きている」ことを知らせることが最優先です。
原則2:影響範囲を3段階で評価
- レベル1(軽微):一部ユーザー、特定条件下のみ、回避策あり
- レベル2(中程度):多くのユーザーに影響、主要機能は動作
- レベル3(重大):全ユーザー影響、サービス停止、金銭的損失の可能性
レベル3なら即座にリーダーやマネージャーへエスカレーション。レベル2でも15分以内に報告が基本です。
原則3:エラーメッセージとURLを記録
スクリーンショットを3枚撮ります。
- エラー画面全体:ブラウザのURL、日時が見えるように
- デベロッパーツールのConsoleタブ:JavaScriptエラーを確認
- デベロッパーツールのNetworkタブ:失敗したAPIリクエストを確認
スマホで画面を撮影してもOKです。証拠は多いほど後で役立ちます。
3. 問題を切り分ける4つの視点
焦ると「どこから調べればいいか分からない」状態になります。次の4つの視点で順番に切り分けましょう。
視点1:再現性を確認する
3回テストして傾向を掴む
- 1回目:同じ操作を繰り返す → 毎回失敗?たまに成功?
- 2回目:別のアカウントやデータで試す → 特定条件だけ?
- 3回目:別のブラウザやデバイスで試す → 環境依存?
判断の目安
- 100%再現する → ロジックエラーの可能性大
- ランダムに失敗する → タイミング問題、リソース不足の可能性
- 特定条件でのみ失敗 → データ依存、権限問題の可能性
視点2:フロントエンドかバックエンドか
切り分けチェックリスト
□ ブラウザのコンソールにエラーが出ている → フロントエンド問題
□ API呼び出しが404や500エラーを返す → バックエンド問題
□ 画面表示は正常だが、データが保存されない → バックエンド問題
□ ボタンを押しても反応しない → フロントエンド問題
実践例
あなたが「ユーザー登録ボタンを押してもエラー」という問題に遭遇したとします。
- デベロッパーツールを開く(F12キー)
- Networkタブを開いてボタンをクリック
-
/api/registerというリクエストを探す - ステータスコードを確認
- 200 OK → フロントエンド側の処理ミス
- 400 Bad Request → リクエストパラメータの問題
- 500 Internal Server Error → サーバー側のバグ
視点3:本番環境特有の要因を疑う
本番環境チェックリスト
□ 環境変数が正しく設定されているか(.envファイルの確認)
□ データベース接続情報は本番用になっているか
□ 外部APIのキーが本番用(テスト用ではない)になっているか
□ ファイルの読み書き権限は適切か
□ ディスク容量は十分か
□ メモリ使用率は正常範囲か(80%以下が目安)
視点4:直近の変更を洗い出す
タイムライン調査法
過去24時間〜72時間で何が変わったかをリストアップします。
| 時刻 | 変更内容 | 担当者 |
|---|---|---|
| 14:30 | 〇〇機能をリリース | 自分 |
| 12:00 | データベースメンテナンス | インフラチーム |
| 10:15 | △△ライブラリをアップデート | Aさん |
問題発生時刻の直前の変更が原因である確率は70%以上です。
4. 効果的なログ調査テクニック
ログはエンジニアの「タイムマシン」です。何が起きたかを時系列で追跡できます。
基本のログ確認4ステップ
ステップ1:エラーログを最初に見る
# アプリケーションのエラーログ
tail -n 100 /var/log/app/error.log
# Nginxのエラーログ
tail -n 100 /var/log/nginx/error.log
tailコマンドで最新100行を表示します。エラーが出た時刻付近を探しましょう。
ステップ2:キーワードでフィルタリング
# "ERROR"という文字列を含む行だけ表示
grep "ERROR" /var/log/app/application.log
# 特定の時刻(例:14:30から14:35)の間のログ
grep "2025-11-04 14:3" /var/log/app/application.log
ステップ3:スタックトレースを読む
エラーログに以下のような表示があります。
ERROR: Uncaught Exception
at UserController.register (controllers/user.js:45)
at Router.handle (express/router.js:284)
...
一番上の行(UserController.register)が問題発生箇所です。controllers/user.jsの45行目を見に行きましょう。
ステップ4:関連するリクエストIDを追跡
多くのシステムでは、1つのリクエストに「リクエストID」が振られています。
[req_abc123] User registration started
[req_abc123] Database connection failed
[req_abc123] Request failed with 500
req_abc123で検索すれば、その処理の全ログを時系列で追えます。
ログがない場合の対処法
本番環境でログが不足している場合は、以下を試します。
対処1:デバッグログを一時的に有効化
アプリケーションの設定ファイルで、ログレベルをINFOやDEBUGに変更します。ただし、機密情報が出力されないよう注意が必要です。
対処2:監視ツールを活用
- New Relic:トランザクション単位で処理を可視化
- Sentry:エラーを自動収集、スタックトレースも記録
- Datadog:インフラとアプリのメトリクスを統合監視
これらのツールがあれば、ログファイルを直接見るより早く原因特定できることもあります。
5. チームへの報告・共有の型
問題を調査しながら、定期的にチームへ状況を共有します。これが信頼を積み上げる最大のポイントです。
5分おきの続報テンプレート
【続報 14:40】
・調査状況:エラーログを確認中
・判明したこと:データベース接続がタイムアウトしている
・次のアクション:DB接続数の設定を確認します
・次回報告:14:45
たとえ進展がなくても「調査中」と伝えることが重要です。
原因判明時の報告フォーマット
【原因特定 15:10】
■ 原因
環境変数`DB_POOL_SIZE`が設定されておらず、
デフォルト値(5)で動作。アクセス増加により接続枯渇。
■ 対応方針
1. 緊急対応:DB_POOL_SIZEを20に増やして再起動(5分)
2. 恒久対応:設定値の妥当性を検証、ドキュメント化(明日まで)
■ 影響
14:30〜15:10の40分間、新規登録が失敗
約15件のエラー発生を確認
対応開始します。
ポイント
- 原因を1〜2行で端的に
- 対応を「緊急」と「恒久」に分ける
- 影響範囲を定量的に(件数、時間)
チームメンバーを巻き込むタイミング
1人で30分調査して手がかりがなければ、素直にヘルプを求めましょう。
調査30分経過しましたが原因特定に至っていません。
以下を確認しましたが手がかりなし:
・アプリケーションログ → 特にエラーなし
・Nginxログ → 502エラーが散発
・DB接続状態 → 正常
次の視点でアドバイスいただけますか?
・インフラ側の変更で影響ありそうな点
・類似事例の経験
具体的に「何を調べたか」を書くことで、相手も答えやすくなります。
6. ロールバックと緊急修正の判断基準
問題への対処は2つの選択肢があります。
選択肢1:ロールバック(前のバージョンに戻す)
こんな時に選ぶ
- 原因が不明で調査に時間がかかりそう
- 影響が広範囲(レベル2以上)
- 修正方法が複雑で、新たなバグを生む危険がある
メリット
- 5〜10分で元の安定状態に戻せる
- リスクが低い
デメリット
- 新機能が使えなくなる
- データの整合性に注意が必要(新バージョンで作成されたデータの扱い)
実行手順例(Git + デプロイツール)
# 前のバージョンのコミットを確認
git log --oneline -5
# ロールバック
git revert HEAD
git push origin main
# または、デプロイツールから
# Heroku: heroku rollback
# AWS CodeDeploy: 前のデプロイIDを再実行
選択肢2:緊急修正(Hotfix)
こんな時に選ぶ
- 原因が明確で修正が1〜2行
- 影響が限定的(レベル1)
- ロールバックすると別の問題が起きる
メリット
- 新機能を維持できる
- 根本解決になる
デメリット
- テストが不十分だと新しいバグを生む
- 作業に15〜30分かかる
安全なHotfixの3原則
- 変更は最小限に:1ファイル、5行以内が理想
- ローカルで必ず動作確認:開発環境で再現させて修正を検証
- 2人以上でコードレビュー:可能なら別のメンバーに目を通してもらう
判断に迷ったら
迷ったらロールバックが鉄則です。特に、影響が大きい場合や金銭に関わる場合は、安全策を選びましょう。
リーダーに判断を仰ぐ時は以下のように提示します。
現在、以下の2案で対応を検討しています。
ご判断いただけますか?
【案1】ロールバック
・所要時間:5分
・影響:〇〇機能が使えなくなる(ユーザー影響小)
・リスク:低
【案2】緊急修正
・所要時間:20分
・内容:DB接続設定の修正(1行)
・リスク:中(新たなバグの可能性)
推奨:案1(安全性優先)
7. 再発防止と信頼回復のアクション
問題を解決して終わりではありません。次のステップで、チームとプロダクトをレベルアップさせます。
解決後24時間以内にやること
アクション1:ポストモーテム(振り返りドキュメント)を書く
A4用紙1〜2枚で以下をまとめます。
# インシデント報告:本番テスト失敗(2025-11-04)
## 概要
新規登録機能のリリース後、データベース接続エラーが発生。
40分間、ユーザーが新規登録できない状態が継続。
## タイムライン
- 14:30 機能リリース
- 14:35 エラー発覚
- 14:40 原因調査開始
- 15:10 原因特定(DB接続プール不足)
- 15:15 設定変更で復旧
## 根本原因
環境変数のDB_POOL_SIZEが未設定。
デフォルト値5では、アクセス増加に対応できず。
## 再発防止策
1. 環境変数チェックリストの作成(1週間以内)
2. ステージング環境での負荷テスト実施(次回リリースから)
3. DB接続数の監視アラート設定(3日以内)
## 学んだこと
- 本番環境固有の設定は、リリース前チェックリストに含めるべき
- 初動の報告が早かったため、チーム連携がスムーズだった
ポイント
- 「誰が悪い」ではなく「何が悪かった」に焦点
- 再発防止策は具体的に、期限を明記
- ポジティブな学びも記載
アクション2:チェックリストに追加
今回の問題を防げたはずのチェック項目を、リリース前チェックリストに追加します。
リリース前チェックリスト(本番環境)
□ 環境変数がすべて設定されているか確認
- DB_POOL_SIZE
- API_KEY(本番用)
- SMTP設定
□ データベースマイグレーションの実行確認
□ 外部API接続テスト(本番エンドポイント)
□ ログ出力レベルの確認(INFO以上)
□ 監視アラートの動作確認
アクション3:ステージング環境の改善
本番と同じ問題がステージング環境で起きていれば、事前に発見できました。
- データ量を本番に近づける(最低でも1000件以上)
- 環境変数を本番と揃える
- 定期的に本番データの一部をステージングへ同期
1週間以内にやること
テストケースの追加
今回のバグを検出できるテストコードを追加します。
// 接続プール枯渇のテスト例
describe('Database Connection Pool', () => {
it('should handle 20 concurrent connections', async () => {
const promises = [];
for (let i = 0; i < 20; i++) {
promises.push(User.create({ name: `user${i}` }));
}
// すべての接続が成功することを確認
await expect(Promise.all(promises)).resolves.toBeDefined();
});
});
ドキュメントの更新
「こういう時はこうする」という知見をチームで共有します。
- READMEに環境変数の一覧と推奨値を記載
- トラブルシューティングガイドに今回のケースを追加
- オンボーディング資料に、本番デプロイ時の注意点を追加
信頼を回復する3つの姿勢
-
自分から情報開示する
- ミスを隠さず、学びを積極的にシェア
- 「次はこう改善します」を言語化
-
小さな改善を積み重ねる
- 再発防止策を確実に実行
- 1ヶ月後に「あの時の対策、ちゃんと効いてますね」と言われるように
-
同じミスをしない
- チェックリストを使う習慣をつける
- 不安なことは事前に相談
トラブルは誰にでも起こります。大事なのは、その後の行動です。
まとめ
本番テスト失敗は、焦りと不安が最大の敵です。この記事で紹介した7つのステップを、実際に手を動かしながら身につけてください。
今日から実践できる3つのこと
-
チームの報告テンプレートを用意する
- Slackの「スニペット」機能などに保存
- いざという時、30秒で第一報を送れるように
-
自分のチェックリストを作る
- リリース前に確認すべき項目を5〜10個リストアップ
- 毎回、これを見ながらデプロイする習慣をつける
-
過去のインシデント事例を読む
- チームの過去のトラブル事例を3つ読む
- 「自分ならどう対処するか」をシミュレーション
最も大切なマインドセット
トラブルは成長のチャンス。
素早く報告し、冷静に対処し、確実に学ぶ。
この3つを実践するエンジニアは、必ずチームから信頼されます。本番テスト失敗は怖いものではなく、あなたのスキルとチームへの貢献を示す機会です。
次にトラブルに遭遇したら、この記事を開いて、1つずつステップを進めてください。あなたなら、必ず乗り越えられます。