💡 Key Takeaways
- The $312 Million Bug That Changed How I Debug Forever
- Why Most Developers Debug Backwards
- The Foundation: Building Your Debugging Toolkit
- Step One: Define the Bug Precisely
私のデバッグ方法を永遠に変えた3億1200万ドルのバグ
私がデバッグへのアプローチが根本的に壊れていると気づいた瞬間を今でも覚えています。それは2011年の火曜日、午前2時47分で、私はシニアソフトウェアエンジニアとして働いていた大手金融サービス会社の戦略室に座っていました。私たちはちょうど、3週間にわたって通貨交換を静かに誤算していた取引プラットフォームのバグを発見したばかりでした。推定損失は? 3億1200万ドル。
💡 重要なポイント
- 私のデバッグ方法を永遠に変えた3億1200万ドルのバグ
- ほとんどの開発者が逆にデバッグする理由
- 基盤:デバッグツールキットの構築
- ステップ1:バグを正確に定義する
最悪だったのはお金ではなく—それは確かに十分悪かったですが。悪かったのは、調査中にバグが含まれている正確なファイルを4回も見ていたという現実でした。4回です。私はそれを見過ごし、問題はもっと複雑で興味深い場所にあると確信していました。私は、実際の問題が日付計算の単純なオフバイワンエラーであるにも関わらず、洗練されたアルゴリズムの欠陥を探していました。
その夜は、私のデバッグのアプローチを根本的に変えました。過去18年間ソフトウェアエンジニアとして働いてきた中で—そのうち12年は特に複雑な分散システムのデバッグに費やしました—私は、以前のアドホックアプローチより73%速くバグを見つけるのに役立つ体系的な方法論を開発しました。もっと重要なのは、このシステムが、私がその夜に陥った罠、つまりバグはそれらが存在するシステムと同じくらい複雑でなければならないという仮定を避ける助けになったということです。
今日、私はクラウドインフラストラクチャ会社で15人のエンジニアのチームを指導しており、体系的なデバッグアプローチを200人以上の開発者に訓練してきました。私が学んだのは、デバッグは賢さではないということ—それは方法論的であるということです。直感ではなく—証拠によるものです。そして、コードを見つめ続けて何時間も起きていられるかということでは決してありません。
ほとんどの開発者が逆にデバッグする理由
体系的なアプローチに入る前に、なぜデバッグがそもそもそんなに難しいのかを理解する必要があります。開発者を訓練してきた私の経験から、無駄なデバッグ時間の約80%を占める3つの根本的な間違いを特定しました。
"最も高価なバグはシステムをクラッシュさせるものではなく、数週間静かに動作し続け、時間とともに重なる微妙に不正確な結果を生み出すものです。"
最初の間違いは、私が「ソリューションファーストデバッグ」と呼ぶものです。これは、十分な証拠を集める前に何が間違っているかについて仮説を立てる時です。脳は理論に固執します—以前に見たことのある類似のバグに基づいているかもしれません—そしてその理論を正しいと証明しようと何時間も費やします。開発者がデータベース接続プールの問題を全日調査するのを見たことがありますが、実際の問題は不正に設定されたロードバランサーであることを発見しました。
2つ目の間違いは「ランダムウォークデバッグ」です。これは何かがうまくいくことを期待して半ばランダムに変更を加えるアプローチです。ここで行をコメントアウトしたり、あそこでログステートメントを追加したり、サービスを再起動して何が起こるか見てみたりします。昨年私のチームと実施した研究では、このアプローチを使用している開発者は、体系的なデバッガーが1.3時間で解決したバグを解決するのに平均で4.7時間かかることがわかりました。これは効率の262%の違いです。
3つ目の間違いは「エゴデバッグ」と呼ばれるもので、スキルレベル以下に見える単純な説明から始めることを拒否することです。これが3億1200万ドルのバグに関する私の間違いでした。私は洗練された問題に取り組んでいると確信していたので、明白なものを無視していました。シニアエンジニアが、実際の問題が環境変数のタイプミスであるときに、マルチスレッドコードの競合状態を調査するのを見たことがあります。
これらの間違いは共通の根本原因を持っています:それらはすべて論理的プロセスではなく感情の反応です。ソリューションファーストデバッグは、知識を持っているように見えることから生じます。ランダムウォークデバッグは、フラストレーションと焦りから生じます。エゴデバッグはプライドから生じます。これから共有する体系的なアプローチは、完全に計算から感情を取り除きます。
基盤:デバッグツールキットの構築
体系的にデバッグを行うためには、適切なツールが必要です。私は高級なデバッグソフトウェアについて話しているのではありません—それは役立ちますが。私は、体系的なデバッグを可能にするための精神的および実用的なインフラストラクチャについて話しています。
| デバッグアプローチ | 解決までの時間 | 成功率 | 主な特徴 |
|---|---|---|---|
| アドホックハンティング | 非常に変動的(時間から日まで) | 約45% | 直感と推測に依存 |
| プリントステートメントデバッグ | 中程度(2-6時間) | 約60% | 反応的、複数回の反復が必要 |
| バイナリサーチ法 | 速い(30分-2時間) | 約75% | コードセクションの体系的な排除 |
| 仮説駆動型 | 非常に速い(15分-1時間) | 約85% | 証拠に基づく、テスト可能な仮定 |
| 体系的方法論 | 最速(10-45分) | 約92% | 再現可能、文書化され、体系的 |
まず、バグを再現する信頼できる方法が必要です。これは明白に聞こえますが、私の経験では、デバッグに費やす時間の約40%が、一貫した再現ケースを持っていないために無駄になっています。バグを確実に再現できない場合、体系的にデバッグすることはできません。私はかつて、複雑な同時実行問題だと思ったものを追跡するのに3日かかりましたが、実際には毎回異なるデータセットに対してテストしていたため、バグが不定期に発生していました。
あなたの再現ケースは可能な限り最小限にするべきです。バグが15ステップの複雑なユーザーワークフローで発生する場合、最初のタスクは、それを問題を引き起こす最小のシーケンスに減らすことです。私は再現のために「バイナリサーチアプローチ」と呼ぶ方法を使用しています:半分のステップを取り除き、テストし、繰り返します。この方法を使用することで、23ステップの再現ケースをわずか3ステップに削減することができ、実際のデバッグプロセスが10倍速くなりました。
次に、適切なログインフラストラクチャが必要です。私はコード全体にプリント文をばらまくことについて話しているのではありません—私は、効率的にフィルタや検索ができる構造化された階層化されたログについて話しています。私の現在の役割では、47の異なるマイクロサービスにわたる単一のリクエストをトレースできる中央集約型のログシステムを使用しています。このインフラストラクチャは、プロダクションバグの解決までの平均時間を6.2時間から1.8時間に短縮しました。
第三に、仮説ジャーナルが必要です。これは、形成したすべての仮説、これを裏付けたり反証したりする証拠、および実行したテストを記録する文書です。私はタイムスタンプ付きのシンプルなテキストファイルを使用しています。この実践には2つの利点があります:同じ仮説を二度テストすることを防ぎます(私は開発者が何度もそれを行うのを見たことがあります)、また、記録を作成します。