チームが(驚くほど!)正常に動作しているソフトウェアシステムを作成するとします。
ある日、エンジニアの1人が、DBデータの一部を変更するいくつかのSQLクエリを誤って実行し、それを忘れてしまいました。
しばらくして、破損した/誤ったデータを発見し、誰もがコードのどの部分がこれを引き起こしたのか、なぜそうなったのかについて頭を掻きます。一方、プロジェクトマネージャーは、それを引き起こしたコードの一部を見つけると主張しています。
これにどう対処しますか?
チームが(驚くほど!)正常に動作しているソフトウェアシステムを作成するとします。
ある日、エンジニアの1人が、DBデータの一部を変更するいくつかのSQLクエリを誤って実行し、それを忘れてしまいました。
しばらくして、破損した/誤ったデータを発見し、誰もがコードのどの部分がこれを引き起こしたのか、なぜそうなったのかについて頭を掻きます。一方、プロジェクトマネージャーは、それを引き起こしたコードの一部を見つけると主張しています。
これにどう対処しますか?
回答:
プロジェクトマネージャーがこのような問題に無限の時間を費やさないことは明らかです。彼らは同じ状況が再び起こるのを防ぎたい。
この目標を達成するために、そのような失敗の根本原因を見つけることができない場合でも、いくつかの対策を講じることが可能です。
たとえば、より詳細なロギング、よりきめ細かいエラー処理、または即時のエラーシグナリングは、同じエラーが再び発生するのを防ぐ、または根本原因を見つけるのに役立ちます。システムでデータベーストリガーの追加が許可されている場合、最初の段階で導入される不整合を禁止するトリガーを追加することができます。
あなたの状況で適切な行動が何であるか考えて、それをチームに提案してください。あなたのプロジェクトマネージャーは喜んでいるでしょう。
ある日、エンジニアの1人が、DBデータの一部を変更するいくつかのSQLクエリを誤って実行し、それを忘れてしまいました。
他の人が述べたように、このような手順を禁止することもお勧めです(システムの運用方法に影響がある場合)。データベースの内容を変更する文書化されていないアドホッククエリの実行を誰にも許可しないでください。このようなクエリが必要な場合は、クエリを実行日、実行した人の名前、および使用された理由とともに文書化された場所に保存するポリシーがあることを確認してください。
これはバグではありません
少なくともあなたのコードにはありません。それはあなたのプロセスのバグです。プロジェクトマネージャーは、コードよりもプロセスについてずっと心配する必要があります。
これにどう対処しますか?
簡単に言えば、エンジニアに生産データベースや共有開発データベースを変更させないことです。
これが共有開発データベースであると仮定します。
理想的には、可能な限り、そもそも共有データベースを使用しないでください。代わりに、短命の開発者ごとのデータベースを用意します。これはスクリプトを使用して自動化する必要があります。そうしないと、テストのコストが非常に高くなり、テストを行わないインセンティブがあります。これらのデータベースは、開発者のワークステーションまたは中央サーバーに配置できます。
何らかの理由で共有データベースが絶対に必要な場合は、フィクスチャを使用する必要があります。基本的に、使用する必要があるたびにデータベースを既知の良好な状態に設定するものです。これにより、開発者が他の人の変更に悩まされるのを防ぎます。
データベースに永続的な変更を適用する必要がある場合は、ソース管理にコミットする必要があります。開発者がデータベースに直接書き込む許可を持たないようにデータベースを設定し、ソース管理から変更を取得して適用するプログラムを用意します。
最後に、デバッグの方法に関する説明から、CIを使用していないように思えます。 CIを使用します。セットアップするのは少し苦痛ですが、長い目で見ればかなりの時間を節約できます。言うまでもなく、再現性のないデータベースのバグを心配する必要はありません。あなたは今、ヘイゼンバグについて心配するだけです!
これが本番データベースであると仮定します:
開発者が本番データベースを変更している場合、たとえ変更が完全に正しいとしても、多くのことがひどく間違っています。
開発者は本番データベースにアクセスしないでください。絶対に理由はなく、非常に多くの間違いが起こる可能性があります。
あなたがする必要がある場合は修正本番データベースで何かを、最初のバックアップ、上でそのバックアップをリストア異なる(開発)インスタンス、およびその後、その開発データベースを中心に遊びます。(ソース管理上で)修正の準備ができたら、復元を再実行し、修正を適用して、結果を確認します。次に、物事を再度バックアップした後(理想的には同時更新を防止します)、実稼働インスタンスを修正します。理想的にはソフトウェアパッチを使用します。
本番データベースで何かをテストする必要がある場合...いいえ、そうではありません。必要なテストが何であれ、開発インスタンスで実行する必要があります。テストを行うためにデータが必要な場合は、そこにそのデータを取得します。
運用データベースには、フルアクセスのログ記録とロールベースのアクセス制御が必要です。したがって、データベースに対してWHOが何をしたかについての確固たる証拠があるはずです。そのため、コードから注意を運用上のセキュリティに移します。
この場合、あなたは最終的に原因を理解しましたが、あなたがしなかったと仮定して...
まず、変更点を分析します。以前にシステムが正常に動作していた場合、最近行われたすべてを注意深く見ると、バグの原因となった変更が明らかになる可能性があります。バージョン管理、CI /展開システム、および構成管理を体系的に確認して、変更がないか確認します。git bisectまたは同等のメカニズムを実行して、バイナリ検索を実行します。ログを確認してください。知らなかったログを探しましょう。システムにアクセスできるすべての人と話し、最近何かをしたかどうかを確認します。問題については、このプロセスを十分に徹底すれば、忘れられたSQLクエリが明らかになるはずです。
第二に、計装。バグの原因を直接見つけられない場合は、その周りにインストルメンテーションを追加して、問題に関するデータを収集します。「コマンドでこのバグを再現できたら、デバッガで何を見たいか」と自問し、それをログに記録します。問題をよりよく理解するまで、必要に応じて繰り返します。Doc Brownが示唆するように、バグに関連する状態のログを追加します。破損したデータを検出するアサーションを追加します。たとえば、バグがアプリケーションのクラッシュである場合、クラッシュロギングメカニズムを追加します。既に素晴らしいものがある場合は、クラッシュログに注釈を追加して、クラッシュに関連する可能性のある状態を記録します。並行性の問題が関係しているかどうかを検討し、スレッドの安全性をテストします。
第三に、弾力性。バグは避けられないので、バグからの回復がより簡単になるように、システムをより回復力のあるものに改善する方法を自問してください。バックアップを改善(または既存)できますか?監視、フェイルオーバー、アラートの改善?冗長性がさらに増えましたか?より良いエラー処理?依存するサービスを互いに分離しますか?データベースアクセスと手動クエリに関するプロセスを改善できますか?せいぜい、これらのことはあなたのバグの結果をそれほど厳しくしないでしょう、そして、最悪の場合、それらはおそらくとにかく良いことです。
また、手動でデータベースにアクセスしてこの種の問題を引き起こす可能性を減らすために、追加のプロセスを追加する必要があるかどうかを検討することもできます。
顧客が破損したデータベースがあると報告したとき、メインフレームデータベース製品の開発チームで働いていました。ディスク上のビットの内部状態により、データベースソフトウェアを介してデータベースが読み取れなかったという意味での破損。メインフレームの世界では、顧客は何百万ドルも払っていますが、これを真剣に考える必要があります。これが私たちがやったことです。
ステップ0:データベースを修復して、顧客が再び立ち上げて実行できるようにします。
ステップ1:ディスク上のファイルを16進レベルで調べることにより、破損が体系的であると判断しました。同じ破損のインスタンスが多数ありました。そのため、データベースソフトウェアのレベルで間違いなく発生しました。実際、マルチスレッドの問題を除外できると感じたのは十分に体系的でした。
他の多くの理論を排除した後、データベースの物理的な再編成に使用できるユーティリティを使用しました。適切なレベルでデータにアクセスできる唯一のコードのように見えました。その後、問題を再現するオプションを慎重に選択して、このユーティリティを実行する方法を発見しました。顧客はこれが彼らがしたことであることを確認または否定することができませんでしたが、それは私たちが思いつくことができる唯一の説明であったため、私たちはそれが可能性のある原因であると判断し、彼らは私たちの診断を受け入れる以外の選択肢はありませんでした。
ステップ2:次に、ソフトウェアに2つの変更を加えました。(a)「はい、私がやっていることを知っています」のユーザーインターフェースを介して誤ってこの効果を引き起こすことを困難にしました。再び発生した場合、ユーザーのアクションの記録があります。
したがって、基本的には(a)損傷を修復してライブランニングを復元し、(b)根本原因を見つけ、(c)再発を防ぐために必要なことをすべて実行するか、再発した場合に簡単な診断を有効にします。
私の経験から、あなたの上司が望むのは、これが再発しないというある程度の保証です。コードが原因ではない場合、それは単一テストで保証されているため、コードベースのテストカバレッジが既にあると仮定すると、ソリューションはデータベースに「テスト」を追加する必要があります。彼がそこに釘付けにしたので、私はドン・ギルマンを引用します:
運用データベースには、フルアクセスのログ記録とロールベースのアクセス制御が必要です。したがって、データベースに対してWHOが何をしたかについての確固たる証拠があるはずです。そのため、コードから注意を運用上のセキュリティに移します。
ただし、本番環境でのデータ変更に関する標準操作手順も必要です。たとえば、DBAがデータを変更したり、開発者が自分で変更を実行したりすることはできません。また、SOPで定義されているように、メールまたはチケットによる変更を互いに正式に要求する必要があります。
どこかにこのような引用がなければなりません。そうでない場合は、引用してください:
シェフがトイレを掃除する責任を負わないという完全な理由があります。
再現性のないバグを処理する必要があることがいくつかあります。
チケットを作成し、考えられるすべてをチケットに記録します。また、この「バグ」が以前に記録されているかどうかを確認し、チケットをリンクします。最終的には、バグを再現するためのパターンを確立するのに十分なチケットを取得できます。これには、回避を試みるために使用される回避策が含まれます。これが唯一のインスタンスである場合でも、最初の時間があれば、最終的には2回目になります。原因が見つかったら、原因を説明してチケットを閉じて、それが再び発生した場合に何が起こったのかをしっかり把握できるようにします(不正なマージで失われた修正)
システム、失敗したもの、および失敗した方法を見てください。失敗する可能性を減らすために更新できるコードの領域を見つけてください。いくつかの例...
execute(<query>)
とexecuteMyStoredProcedure(<params>)
これはバグを修正しないかもしれませんが、たとえそれが修正されない場合でも、システムは今ではより安定/安全であるので、それはまだ報います。
2の一部ですが、何かが起こったので、いつ再び起こるかを知る必要があります。システムを監視するためのヘルスチェックスクリプト/プログラムを作成して、バグのリサーフェシングから24時間以内に管理者にアラートを送信できるようにする必要があります(遅延が少ないほど、合理的です)。これにより、クリーンアップがはるかに簡単になります。(データベースのログに加えて、OSはデータベースにログインするユーザーと、実行する読み取り以外のアクションもログに記録する必要があることに注意してください。少なくとも、そのマシンへのトラフィックのネットワークログが必要です)
問題の原因はソフトウェアの障害ではなく、誰かがデータベースをいじっていることです。物事がうまくいかないことを「バグ」と呼ぶと、あなたのバグは簡単に再現できます。誰かがデータベースに対して愚かなことをすると、物事は常にうまく行かないでしょう。また、この「バグ」を回避する方法があります。データベースを手動で変更できないようにするか、テストされていないソフトウェアを使用して、データベースを変更できるユーザーを厳密に制御します。
データベースの障害を「バグ」と呼ぶだけであれば、再現性のないバグはなく、バグはまったくありません。バグレポートがある場合もありますが、問題はバグが原因ではないという証拠もあります。したがって、「再現不可能」ではなく、「破損したデータベース」などのバグレポートを閉じることができます。調査でバグがないことを示すバグレポートがあることは珍しくありませんが、ユーザーがソフトウェアを誤って使用した、ユーザーの期待が間違っていたなどです。
その場合、繰り返したくない問題があることがわかっているので、最初の場合と同じアクションを実行します。