再現性のないバグに対処する


73

チームが(驚くほど!)正常に動作しているソフトウェアシステムを作成するとします。

ある日、エンジニアの1人が、DBデータの一部を変更するいくつかのSQLクエリを誤って実行し、それを忘れてしまいました。

しばらくして、破損した/誤ったデータを発見し、誰もがコードのどの部分がこれを引き起こしたのか、なぜそうなったのかについて頭を掻きます。一方、プロジェクトマネージャーは、それを引き起こしたコードの一部を見つけると主張しています。

これにどう対処しますか?


32
エンジニアがそれを忘れた場合、どうしてそれが起こったことを知っていますか?バグではなく、スクリプトを実行している人によってどのように破損しましたか?
DaveG

18
彼は1日か2日後にひらめきを感じました。これは、彼が簡単にそうだったかもしれないことを覚えていなかった場合の仮説です。
ニックキリアキデス

12
これは仮説です。彼が覚えていなかったなら、PMは私たちにこれを追いかけるだろうと確信しています。私はそうすることを知っています。
ニックキリアキデス

59
xkcd.com/583 ;)[NSFW言語]
Baldrickk

100
「あなたのチームが正常に動作しているソフトウェアシステムを作成していると仮定します。」不可能な空想で私をからかうのをやめてください!
ポールD.ウェイト

回答:


134

プロジェクトマネージャーがこのような問題に無限の時間を費やさないことは明らかです。彼らは同じ状況が再び起こるのを防ぎたい。

この目標を達成するために、そのような失敗の根本原因を見つけることができない場合でも、いくつかの対策を講じることが可能です。

  • そのような障害が再発した場合に、早期に検出する
  • 同じ障害が再び発生する可能性を低くする
  • 特定の種類の不整合に対してシステムをより堅牢にする

たとえば、より詳細なロギング、よりきめ細かいエラー処理、または即時のエラーシグナリングは、同じエラーが再び発生するのを防ぐ、または根本原因を見つけるのに役立ちます。システムでデータベーストリガーの追加が許可されている場合、最初の段階で導入される不整合を禁止するトリガーを追加することができます。

あなたの状況で適切な行動が何であるか考えて、それをチームに提案してください。あなたのプロジェクトマネージャーは喜んでいるでしょう。

ある日、エンジニアの1人が、DBデータの一部を変更するいくつかのSQLクエリを誤って実行し、それを忘れてしまいました。

他の人が述べたように、このような手順を禁止することもお勧めです(システムの運用方法に影響がある場合)。データベースの内容を変更する文書化されていないアドホッククエリの実行を誰にも許可しないでください。このようなクエリが必要な場合は、クエリを実行日、実行した人の名前、および使用された理由とともに文書化された場所に保存するポリシーがあることを確認してください。


8
@NicholasKyriakidesおそらく両方。これらはすべて、「遅延」デバッグを簡単にする常識的な手段です。それらはおそらく無数の手順で書かれているでしょう。
ニックハートリー

29
実稼働システムで何らかの深刻な問題が発生し、多大な労力を費やしても原因を特定できない場合が時々あります。最終的に、あなたはそれを宇宙線に帰し、報告を改善しようとするので(もしそれが再び発生すれば、原因を見つける可能性が高くなります)、緩和(もしそれが再び発生すれば、ダメージは最小限になります)とそれを確認します繰り返します。
デビッドシュワルツ

2
@Nicholas Kyriakides:数十年にわたる個人的な経験。
ドク・ブラウン

4
また、バグがあったとしても、もう存在しない可能性が非常に高いことに注意してください。ときどきできる最善のことは、データを修正し、テスト/手順を改善して、同じ問題が二度と起こらないようにすることです。
kutschkem

2
断続的な問題を見つけることは、ログを記録し、発生時にそれらを検出できるチョークポイントを見つけることです。エラーのいつ/どこでハンドルを取得するために、トリガーや、ノイズの多いエラーロギングを伴うコードのデプロイなどの不快なものが必要になる場合があります。
アーロンLS

51

これはバグではありません

少なくともあなたのコードにはありません。それはあなたのプロセスのバグです。プロジェクトマネージャーは、コードよりもプロセスについてずっと心配する必要があります。

これにどう対処しますか?

簡単に言えば、エンジニアに生産データベースや共有開発データベースを変更させないことです。


これが共有開発データベースであると仮定します。

理想的には、可能な限り、そもそも共有データベースを使用しないでください。代わりに、短命の開発者ごとのデータベースを用意します。これはスクリプトを使用して自動化する必要があります。そうしないと、テストのコストが非常に高くなり、テストを行わないインセンティブがあります。これらのデータベースは、開発者のワークステーションまたは中央サーバーに配置できます。

何らかの理由で共有データベースが絶対に必要な場合は、フィクスチャを使用する必要があります。基本的に、使用する必要があるたびにデータベースを既知の良好な状態に設定するものです。これにより、開発者が他の人の変更に悩まされるのを防ぎます。

データベースに永続的な変更を適用する必要がある場合は、ソース管理にコミットする必要があります。開発者がデータベースに直接書き込む許可を持たないようにデータベースを設定し、ソース管理から変更を取得して適用するプログラムを用意します。

最後に、デバッグの方法に関する説明から、CIを使用していないように思えます。 CIを使用します。セットアップするのは少し苦痛ですが、長い目で見ればかなりの時間を節約できます。言うまでもなく、再現性のないデータベースのバグを心配する必要はありません。あなたは今、ヘイゼンバグについて心配するだけです!


これが本番データベースであると仮定します:

開発者が本番データベースを変更している場合、たとえ変更が完全に正しいとしても、多くのことがひどく間違っています。

開発者は本番データベースにアクセスしないでください。絶対に理由はなく、非常多くの間違いが起こる可能性があります。

あなたがする必要がある場合は修正本番データベースで何かを、最初のバックアップ、上でそのバックアップをリストア異なる(開発)インスタンス、およびその後、その開発データベースを中心に遊びます。(ソース管理上で)修正の準備ができたら、復元を再実行し、修正を適用して、結果を確認します。次に、物事を再度バックアップした後(理想的には同時更新を防止します)、実稼働インスタンスを修正します。理想的にはソフトウェアパッチを使用します。

本番データベースで何かをテストする必要がある場合...いいえ、そうではありません。必要なテストが何であれ、開発インスタンスで実行する必要があります。テストを行うためにデータが必要な場合は、そこにそのデータを取得します。


12
だから、あなたの推奨される解決策はタイムトラベルですか?
ベヌバード

7
これは与えられた例に対してはまともな解決策ですが、問題は再現できないバグと、それらを説得することを望むマネージャーに対処するという、より一般的なコンテキストを持っています。これは、データベースの問題や権限の管理だけでなく、はるかに適用できます。この答えは、意図された質問に実際に答えているのではなく、与えられた例だけに答えているように感じます。
カイルワードル

@KyleWardle同意しました。Doc Brownの答えは、一般的なケース(詳細なロギングとエラー処理、ガード条件)を非常によくカバーしていると思います。そもそも問題の原因となったプロセスの失敗について誰も言及していないのを見たので、私はほとんど私のものを追加しました
-goncalopp

2
@Benubird答えは「あなたがこれに対処する方法はそれが再び起こらないようにすること」に要約されると思います。ソフトウェアエンジニアリングの観点から、破損した運用データベースを「解決」できるとは思いません。
goncalopp

1
devデータベースにデータを入れるためにコードを変更するつもりはありません。大企業を含め、私が働いたすべての場所で、開発者はテストデータを挿入し、アプリケーションが使用するのと同じ資格情報を自由に使用できます。
デビッドコンラッド

13

運用データベースには、フルアクセスのログ記録とロールベースのアクセス制御が必要です。したがって、データベースに対してWHOが何をしたかについての確固たる証拠があるはずです。そのため、コードから注意を運用上のセキュリティに移します。


2
データ破損がいつ発生したかを正確に把握していない可能性があるため、調査する必要のあるログを把握するのが困難になる可能性があります。
ナタナエル

3
残念ながら、これらの1つをトレースすると、ログも破棄されていることがわかりました。(はい、それ。バグは本物でした。)
ジョシュア

夜間だけでも、データの整合性をチェックするスケジュールされたジョブとログを組み合わせると、問題に早期にフラグを立てて解決できます。本当に注意したい場合は、変更についてピアレビューを要求します。
キース

私が働いたすべての場所で、開発者はアプリが使用するのと同じ資格情報でデータベースに接続するため、アクセスロギングは、そのIDが変更を行ったときにのみ表示され、プログラムではなく人間によって行われたものではありません。タイムスタンプをアプリケーションログと比較して、その時点でアプリケーションがデータベースに書き込みを行っていたかどうかを確認できると思います。
デビッドコンラッド

@DavidConrad:アプリが本番環境で使用する資格情報に開発者がアクセスできるのはなぜですか?これらの資格情報は、実稼働アプリケーションサーバーから、アプリケーションサービスアカウントを除いて読み取ることさえできないように、何らかの種類のシークレット管理を使用する必要があります。
ダニエル・プライデン

6

この場合、あなたは最終的に原因を理解しましたが、あなたがしなかったと仮定して...

まず、変更点を分析します。以前にシステムが正常に動作していた場合、最近行われたすべてを注意深く見ると、バグの原因となった変更が明らかになる可能性があります。バージョン管理、CI /展開システム、および構成管理を体系的に確認して、変更がないか確認します。git bisectまたは同等のメカニズムを実行して、バイナリ検索を実行します。ログを確認してください。知らなかったログを探しましょう。システムにアクセスできるすべての人と話し、最近何かをしたかどうかを確認します。問題については、このプロセスを十分に徹底すれば、忘れられたSQLクエリが明らかになるはずです。

第二に、計装。バグの原因を直接見つけられない場合は、その周りにインストルメンテーションを追加して、問題に関するデータを収集します。「コマンドでこのバグを再現できたら、デバッガで何を見たいか」と自問し、それをログに記録します。問題をよりよく理解するまで、必要に応じて繰り返します。Doc Brownが示唆するように、バグに関連する状態のログを追加します。破損したデータを検出するアサーションを追加します。たとえば、バグがアプリケーションのクラッシュである場合、クラッシュロギングメカニズムを追加します。既に素晴らしいものがある場合は、クラッシュログに注釈を追加して、クラッシュに関連する可能性のある状態を記録します。並行性の問題が関係しているかどうかを検討し、スレッドの安全性テストします

第三に、弾力性。バグは避けられないので、バグからの回復がより簡単になるように、システムをより回復力のあるものに改善する方法を自問してください。バックアップを改善(または既存)できますか?監視、フェイルオーバー、アラートの改善?冗長性がさらに増えましたか?より良いエラー処理?依存するサービスを互いに分離しますか?データベースアクセスと手動クエリに関するプロセスを改善できますか?せいぜい、これらのことはあなたのバグの結果をそれほど厳しくしないでしょう、そして、最悪の場合、それらはおそらくとにかく良いことです。


5
  1. 最も可能性の高い原因は手動データベースアクセスであると考えていることをプロジェクトマネージャーに説明してください。
  2. それでもこの問題の原因となったコードを探してもらいたい場合は、コードをもう一度見てください。
  3. 数時間(または他の適切な時間)に戻って、これを引き起こしたコードが見つからないと言うので、おそらく最も可能性の高い原因は手動のデータベースアクセスであると考えています。
  4. それでもコードを探しもらいたい場合は、どのくらいの時間を費やしてほしいか尋ねてください。これを実行している間は、機能X、バグY、または機能強化Zに取り組んでいないことを微妙に思い出させます。
  5. 彼らが尋ねる限り多くの時間を費やしてください。それでも最も可能性の高い原因が手動データベースアクセスであると思われる場合は、これを伝えてください。
  6. 彼らは場合まだあなたがコードを見てみたい、これは明らかにあなたのチームの時間の非生産的使用となっているとして、問題をエスカレート。

また、手動でデータベースにアクセスしてこの種の問題を引き起こす可能性を減らすために、追加のプロセスを追加する必要があるかどうかを検討することもできます。


1
エンジニアの1人が手動で更新したことや、エンジニアがデータベースに対して直接クエリを実行したことはほとんどありませんでした。これは、1回限りのことでしたが、忘れてしまいました。私たちは1日を費やし、何が悪いのかを見つけるのに丸1週間を費やす準備をしました。私の質問は、原因を見つけることができず、潜在的な原因が何であるかを示唆できない場合に何が起こるかです。
ニックキリアキデス

5
「私の質問は、原因を見つけることができず、潜在的な原因が何であるかを示唆できない場合に何が起こるかです」これは、「修正できない-複製できない」フラグが発明された正確な理由です。
-esoterik

4

顧客が破損したデータベースがあると報告したとき、メインフレームデータベース製品の開発チームで働いていました。ディスク上のビットの内部状態により、データベースソフトウェアを介してデータベースが読み取れなかったという意味での破損。メインフレームの世界では、顧客は何百万ドルも払っていますが、これを真剣に考える必要があります。これが私たちがやったことです。

ステップ0:データベースを修復して、顧客が再び立ち上げて実行できるようにします。

ステップ1:ディスク上のファイルを16進レベルで調べることにより、破損が体系的であると判断しました。同じ破損のインスタンスが多数ありました。そのため、データベースソフトウェアのレベルで間違いなく発生しました。実際、マルチスレッドの問題を除外できると感じたのは十分に体系的でした。

他の多くの理論を排除した後、データベースの物理的な再編成に使用できるユーティリティを使用しました。適切なレベルでデータにアクセスできる唯一のコードのように見えました。その後、問題を再現するオプションを慎重に選択して、このユーティリティを実行する方法を発見しました。顧客はこれが彼らがしたことであることを確認または否定することができませんでしたが、それは私たちが思いつくことができる唯一の説明であったため、私たちはそれが可能性のある原因であると判断し、彼らは私たちの診断を受け入れる以外の選択肢はありませんでした。

ステップ2:次に、ソフトウェアに2つの変更を加えました。(a)「はい、私がやっていることを知っています」のユーザーインターフェースを介して誤ってこの効果を引き起こすことを困難にしました。再び発生した場合、ユーザーのアクションの記録があります。

したがって、基本的には(a)損傷を修復してライブランニングを復元し、(b)根本原因を見つけ、(c)再発を防ぐために必要なことをすべて実行するか、再発した場合に簡単な診断を有効にします。


3

私の経験から、あなたの上司が望むのは、これが再発しないというある程度の保証です。コードが原因ではない場合、それは単一テストで保証されているため、コードベースのテストカバレッジが既にあると仮定すると、ソリューションはデータベースに「テスト」を追加する必要があります。彼がそこに釘付けにしたので、私はドン・ギルマンを引用します:

運用データベースには、フルアクセスのログ記録とロールベースのアクセス制御が必要です。したがって、データベースに対してWHOが何をしたかについての確固たる証拠があるはずです。そのため、コードから注意を運用上のセキュリティに移します。

ただし、本番環境でのデータ変更に関する標準操作手順も必要です。たとえば、DBAがデータを変更したり、開発者が自分で変更を実行したりすることはできません。また、SOPで定義されているように、メールまたはチケットによる変更を互いに正式に要求する必要があります。

どこかにこのような引用がなければなりません。そうでない場合は、引用してください:

シェフがトイレを掃除する責任を負わないという完全な理由があります。


1

再現性のないバグを処理する必要があることがいくつかあります。

  1. チケットを作成する

チケットを作成し、考えられるすべてをチケットに記録します。また、この「バグ」が以前に記録されているかどうかを確認し、チケットをリンクします。最終的には、バグを再現するためのパターンを確立するのに十分なチケットを取得できます。これには、回避を試みるために使用される回避策が含まれます。これが唯一のインスタンスである場合でも、最初の時間があれば、最終的には2回目になります。原因が見つかったら、原因を説明してチケットを閉じて、それが再び発生した場合に何が起こったのかをしっかり把握できるようにします(不正なマージで失われた修正)

  1. 強化分析を行う

システム、失敗したもの、および失敗した方法を見てください。失敗する可能性を減らすために更新できるコードの領域を見つけてください。いくつかの例...

  • 以下のような専用コール(とアドホックコードを置き換えますexecute(<query>)executeMyStoredProcedure(<params>)
  • 毎晩検証スクリプトを実行して、データの整合性を検証します(これにより、次回24時間以内に検出できるようになります)
  • ロギングとアーカイブ(バックアップ)を追加/改善します。
  • 不適切なセキュリティ制限を変更します(たとえば、データの読み取りのみを行う人/プログラムには書き込み権限がありません。本番を担当しない開発者が本番サーバーにログインできないようにします)
  • 欠落している場所にデータ検証/衛生を追加

これはバグを修正しないかもしれませんが、たとえそれが修正されない場合でも、システムは今ではより安定/安全であるので、それはまだ報います。

  1. システムアラートを追加する

2の一部ですが、何かが起こったので、いつ再び起こるかを知る必要があります。システムを監視するためのヘルスチェックスクリプト/プログラムを作成して、バグのリサーフェシングから24時間以内に管理者にアラートを送信できるようにする必要があります(遅延が少ないほど、合理的です)。これにより、クリーンアップがはるかに簡単になります。(データベースのログに加えて、OSはデータベースにログインするユーザーと、実行する読み取り以外のアクションもログに記録する必要があることに注意してください。少なくとも、そのマシンへのトラフィックのネットワークログが必要です)


0

問題の原因はソフトウェアの障害ではなく、誰かがデータベースをいじっていることです。物事がうまくいかないことを「バグ」と呼ぶと、あなたのバグは簡単に再現できます。誰かがデータベースに対して愚かなことをすると、物事は常にうまく行かないでしょう。また、この「バグ」を回避する方法があります。データベースを手動で変更できないようにするか、テストされていないソフトウェアを使用して、データベースを変更できるユーザーを厳密に制御します。

データベースの障害を「バグ」と呼ぶだけであれば、再現性のないバグはなく、バグはまったくありません。バグレポートがある場合もありますが、問題はバグが原因ではないという証拠もあります。したがって、「再現不可能」ではなく、「破損したデータベース」などのバグレポートを閉じることができます。調査でバグがないことを示すバグレポートがあることは珍しくありませんが、ユーザーがソフトウェアを誤って使用した、ユーザーの期待が間違っていたなどです。

その場合、繰り返したくない問題があることがわかっているので、最初の場合と同じアクションを実行します。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.