まえがきこれまでの経験で得た、デバッグのノウハウを書き留めます。プログラミング、テスト、バグトラッキングなどのノウハウには触れていません。不特定多数のテスターを使う※あくまでも私の定義です。業界や組織や個人によって他の分類や異なる定義があります。概略の仕様や必要なテストプレイの内容などを、分かり易く図説を交えた文書にまとめておくと役に立ちます。バグレポートを作成する(してもらう)場合に必要な情報を挙げてみます。バグレポートの提出フォームのようなものを用意すると便利です。Googleフォームを使えば、Googleスプレッドシートにレポートを自動的に蓄積できます。※バグトラッキングのノウハウは、この記事では扱いません。不具合の現象がどのようなものかという話です。「最初に何が起きたのか」が最も重要です。発症後に操作を続けて生じる様々な現象は、既に壊れた実行環境に起因する二次的なものである可能性があり、あまり意味がない場合も多いです。スクリーンショットやムービーがあると分かり易くなります。再現するものもあれば、一度見たきりで、以後、全く見ないものもあるでしょう。バグの原因を究明する難易度は、発症頻度に比例します。レポートを受け取った者が現象を確認するにはどうすれば良いのかという話です。明確な方法が不明な時点では、「発症の前に、どういう状況で、何をしたのか」が重要です。前からのムービーがあるととても参考になります。バージョン情報は必須です。テストリリース毎にバージョンを更新し、実行時に表示して確認できるようにする必要があります。バージョンが確認できない場合は、リリースを入手した日時で代替できる可能性があります。発症した機種やOSなど、取り巻く環境です。テストに使用する環境の詳細スペックをリストアップしておくと便利です。ベータテストなど、不特定多数の場合は、レポートが寄せられる都度、調査して蓄積していきます。プラットフォーマーが、機種データベースを整備している場合があります。症状のどこが問題で、どうなっていることが正しいのかという話です。仕様通りの現象がバグとしてレポートされることもあります。バグを見つけてレポートにします。-※テストプレイでバグを見つける*こつ*は、この記事では扱いません。+※テストプレイでバグを見つける*コツ*は、この記事では扱いません。開発者の手元でバグを再現することは重要です。操作」が重要な手がかりです。確実に修正されたと認めるには、現象とその再現方法が分かっていなければなりません。症状が、どのような現象であるのかを分析します。この分析によって再現方法が明らかになることもあります。「モーダルダイアログが閉じない」という症状が、「確認ボタンが反応するのに閉じない」のか「ボタンが反応しない」のか、「ボタンが表示されない」のか、といった話です。「ボタンが反応しない」のは、「ボタンが応答していない」とか、「ボタンより手前に見えないオブジェクトがあってボタンにイベントが届いていない」とか、といった話もあるでしょう。どのバージョンで発症したのか、どのバージョンまでは正しく動いていたのか、という話です。バージョン間の変更箇所から、次の「何処で起きているか」のヒントまたは答が得られます。※リビジョン管理については、この記事では扱いません。プログラムの何処で起きた現象なのかを探ります。現象の分析から、「何処で起きているか」よりも先に「何が間違っているか」が明らかになる場合もあります。前述の例なら、「ダイアログの初期化の冒頭で例外が発生」といった話です。例外の発生であれば、発症箇所は既に特定できていて、スタックトレースが使えれば呼び出し経路も明かです。ソースで流れを追い、何処まで正しく動き、何処でバグったのかを発見します。トレース可能なデバッガーが使えるなら、経路を順に追うことができます。ブレークポイントが設定できれば、直前までトレースを端折ることができます。デバッガーがなくても、経路に順にコンソールへのデバッグ情報出力を仕込んで走らせることで、流れを追うことができます。デバッグにコンソールが使えない環境では、あらかじめ、画面にオーバーラップするデバッグ情報表示専用のレイヤーを仕込んでおくのも方法です。逐次リアルタイムに更新されるような情報は、コンソールに出すよりも画面の固定位置に表示された方が確認しやすい場合もあります。多数のデバッグ出力を仕込んで、詳細な動作ログをファイルに保存し、実行後に分析するという選択肢もあります。ソースをコメントアウトして、どの処理を飛ばすと発生しなくなるかを調べることもできます。コールバック、コルーチン、別スレッドなどの非同期処理が存在する場合は、そちらの影響も配慮する必要があります。前述の例だと、コールバックされるルーチンにもデバッグ情報出力を仕込み、「ボタン押し下げのイベントが届いているか」を確認する必要があります。非同期処理では、スタックトレースで呼び出しの大元を知ることが難しくなります。データバグなのかプログラムバグなのか、書き間違い程度なのか、計算式が誤っている程度か、クラスの構造やアルゴリズムに起因するような設計ミスなのか、具体的にどう間違ったのか、といった話です。前述の例だと、「未初期化でNULL参照がある」とか、「ボタンのイベントハンドラの設定漏れ」とか、「ダイアログのレイアウトデータの瑕疵」とか、といった話です。ソースを追っても不審な点を見つけられないときは、逆に「どうすればこの現象を起こすことができるか」と考えることで糸口がつかめるかもしれません。前述の例で、「ボタンにイベントが届いていない」場合に、「ボタンの手前に透明なオブジェクトを置いてイベントを横取りすれば...」などと考えるわけです。最後に、環境やツールを疑ってください。実行環境や開発環境を再起動してみましょう。ビルドし直してみましょう。キャッシュやセーブデータを初期化してみましょう。実行環境や開発環境のバージョンを新しくしてみましょう。サーバ側の一時的な不具合を疑ってみましょう。してもダメなら、最小の実証プロジェクトを構築してみましょう。間違いの程度によって、修正方法を検討する必要が生じます。書き間違いや式の誤りであれば話は単純ですが、プログラムの構造に及ぶようなアルゴリズムのバグの場合はやっかいです。自律的なコード群が相互のタイミングに依存していたり、アルゴリズムが錯綜していたりして、アルゴリズムのバグなのか判断が付かない場合は、思い切ってリファクタリングするのも選択肢です。修正版で、現象が再現されなくなっていることを確認します。現象と再現方法が明らかでないと「修正完了」の確認ができず、「発症しなくなったようだ」としか言えません。至る課程で、逐次履歴を残して一元管理しましょう。バグの要素](#%E3%83%90%E3%82%B0%E3%81%AE%E8%A6%81%E7%B4%A0)で例に挙げたスプレッドシートに書き加えていく方法が考えられます。※バグトラッキングのノウハウは、この記事では扱いません。デバッグとは切り分けです。あらゆる可能性を考慮して、最初は大まかに、次第に子細に、該当しないものを外していくと、最後に真理が現れます。長い模索の果てに真理に至るのは便座の上です。灰色の脳髄にコードがロードされ、現象がインプットされていれば、安楽椅子探偵のように、思索のみで答に行き着くことでしょう。冒頭で「バグのないプログラムはない」などと嘯いておきながらアレですが、バグは作らないことがベストですし、そこへ近づけることはできます。コーディング前にアルゴリズムの検証をしましょう。バグが出にくいプログラムにしましょう。計画し小刻みにテストし、確認済みの小さな部品を集めて組み立てましょう。※これらのプログラミングのノウハウは、この記事では扱いません。あとがき最初に触れたプログラミング環境は、16進キーと8桁の16進表示でマシン語を直接読み書きして、命令毎にステップ動作ができるだけでした。開発環境の進歩はめざましいですが、今でも、過去の経験が役に立つこともあるので、記事にしておこうと思いました。書き忘れていることや、うまく表現できていないことも多いと思うので、随時、更新していくつもりです。