エンジニアの責務範囲は「設計」フェーズから書き出しても幅広い。
図の中の青色がエンジニアの責務。
そんな中「第三者評価」で不具合が報告されると、デバッグ(不具合解析)という作業が追加される。
※不具合分析・上流工程へのフィードバッグなどもあるが今回は省略(詳しくは下記で)
バグは発見しても修正しないと品質は上がらない。
にも関わらず 頭の悪いマネージャーやQA部隊 は、バグ(不具合)を見つけたら品質が上がると思ってる。
なので平気で開発中やエンジニア検証中に同原因の不具合をバンバン報告してきて開発活動を阻害してくる。
しまいには、勝手に不具合分析してきて先んじて評価してきたにも関わらず
我々の部隊に流出した不具合傾向をグラフ化しました。これらに対して「なぜなぜ分析」と「改善策」の検討と発表を行ってください。
とか、さらに開発活動を阻害してくる。
そのようなプロジェクトでは、不具合修正の過渡期には開発者から阿鼻叫喚がアチラコチラから聞こえてきて遅延することが約束されている。
ネットで検索して出てくる品質改善を謳っているコンサル会社でも「不具合原因の分析」とか「不具合発見するためのテスト」などは大量に出てくるのに、
不具合箇所の早期発見方法
という内容は一切書かれてない。
「不具合」を報告するだけて品質上がるならエンジニアいらない。
近年、アンドロイド等のマルチスレッドで複雑なOS上で動作するソフトウェアとなり、不具合箇所の特定がどんどん難しくなっている。
にも関わらず、デバッグ(不具合解析)は教育機関で学べる機会は多く無い。
失敗と苦労を重ねて体得した経験を整理したとしても、組み込みソフト、スマホアプリ、Webサービス……など対象ソフトウェアやデバイスによって知識が役に立たない事も多い。
なお、デバッグの作業者をデバッガーと呼ぶ。
コンピュータープログラムの誤り・不具合・欠陥といったバグを探して取り除き、修正する(デバッグする)作業を専門に行うソフトウェア、または作業者。「デバッガ」ともいう。
ただし多くのサイトでデバッガーとテスターが混在しており
プログラミングスキルは不要
とか書いてある。
理由は募集が「デバッガー」となっていても、実際の業務は修正の作業を行わない場合もあるらしい。
QAディレクター・デバッグリーダー
【職務概要】
同社にてゲームのデバッグ業務のディレクションをお任せします。【職務詳細】
・テスト計画書/設計書の作成
・デバッグスケジュールの作成
・デバッグメンバーの工数及びスケジュール管理
・外部業者との折衝
・プロジェクト内で発生した課題解決推進
・フローの構築や改善、最適化など【必須】
・Excel、基本的なPC操作
・社内外の関係者との調整
・テストケースの設計経験
・リーダー経験(1年以上)など
デバッグ(不具合解析)してねーじゃねーかww
そもそも、プログラミングはバグの修正に使う時間がほとんどと言っても過言ではない。
デバッガーはデバッグ(不具合解析・修正)を行う
デバッグは次の2つの過程からなる。
- 不具合解析(エラーの正確な性質と原因となっているプログラム内の箇所を見つけること)
- 不具合修正(エラーを修正すること)
言わんでもがな、これは
エンジニアの仕事
必ずしも、その機能の実装者や設計者でないと修正できない……とは言わないが、
プログラムの処理の流れや概要(コールフロー)
が分かってないと、そもそも不具合箇所の特定が不可能だ。
こんなに簡単だったら良いのにな……。
不具合によっては、アーキテクチャから見直しが必要だったり、他部署とのインターフェースの再議論が必要だったりする。
優秀なエンジニアは、
「こういう場合は、だいたい呼び出し先のmutex処理が怪しい」
と大まかに問題の場所と原因を想定することができる。
このため、手当たり次第に原因調査することがなく、問題解決までのスピードが早い。
つまりデバッグとはエンジニアスキルそのもの
不具合箇所の特定解析
不具合解析に一般的な原則は無い。
方法も多種多様であり まとめる事は容易では無いが「障害発生箇所の局所化」という問題解決的なアプローチを取ると概ね次のようになる。
ドメイン特定 → コンポーネント特定 → 不具合箇所特定
勿論、ASSERTで落ちてる場合は不具合箇所は明確だろうし、解析ソフトウェアの規模に応じても異なる。
ここでは「大規模組み込みソフトウェア」を想定しているが、次のような汎用的アプローチがあるかと思っている。
【不具合(バグ/障害)に関する記録を調べる】
- エラーメッセージ
- エラーログ
- ただのログ
- 入力/出力データ
- メモリダンプしたデータ
【不具合を再現する】
- 二分探索
- printfデバッグ
- 再現手順を最小化
- 大量のデータの流し込み
- ミニプログラムで動作確認
- スレッドの数を大幅に増やす
- 処理の実行速度をわざと遅らせる
【正常に動作と比較する】
- 正常時と異常時のログの出方を比較
- 別のアプリの設定と比較
【直近の修正箇所を疑う】
- コミット内容を確認
【その他】
- 過去不具合より同件/類似案件を検索
繰り返しになるが、デバッグスキルを高めるにはどうすれば良いのか?
正直なところ「経験」が大事
多くのバグを経験することで勘所が分かるようになってくる。
なお記事を書こうと思ったが、下記のQiitaが体系化されて初心者向けには詳しいので、私は簡単に記載しておく。
不具合(バグ/障害)に関する記録を調べる
多くのテック系記事では
再現条件が固定されなければ、バグの改修は不可能
などと書いている。
それ故「何よりも再現する」事を優先した記事ばかりが目に入る。
- 本当に辛い。再現性が低い不具合の調査と対策方針
- ペアデバッグで分かった、ベテラン技術者がバグ原因を特定するまでの手順
- 新人技術者のためのロジカル・シンキング入門(1) ―― いかにしてバグの原因を突き止めるか
そんな訳はなくテスターの報告情報から不具合の原因が分かれば、不具合の修正は可能だ。
というよりも、
不具合修正が可能なような事前の仕込みをしておく
事がエンジニアに求められている。
これは「デバッガビリティ(Debuggability):デバッグ容易性」と呼ぶ設計活動の一つだが、今回は詳細には紹介しない。
まぁ、誰もがすぐに思いつくのがログの出力。
ログは最大限に活用することで、不具合時の調査コストを下げることに繋がる。
ただし、むやみに出力を行うとログ出力量が膨大になり出力を増やしすぎると性能に影響するため、通常はシステム内でログレベルが決められている。
とにかく再現性が低い不具合だって存在するので、不具合発生時に取得可能な情報から不具合解析可能な状態にしておくに越したことはない。
そもそもアンドロイドであれば「bugreport」が取得できる。
Android バグレポートには、dumpsys、dumpstate、logcat のデータがテキスト(.txt)形式で含まれており、不具合特定可能な情報が大量に存在する。
アンドロイドのリブート(Reboot)問題であれば、不具合箇所の特定は、ある程度判断できる。
- フレームワーク部分処理で無限ループ/デッドロックで処理が止まり、Watchdocからリブート(WDT : Watchdog timer)
- Initで起動されるSystem権限のサーバ類が例外で落ちてリブート
不具合を再現する
再現の目的は「不具合箇所の特定」だけど、これはテスターでも手伝えるためエンジニアの負荷軽減にも繋がる。
- テスター観点(発生頻度や再現方法を明確/単純化するために再現させる)
- インテグレーション観点(コミットされたソースコード履歴からrevert等を行い、再現しなくなる事を確認する)
- デバッガー観点(ログ等の追加解析情報を追加して再現させた不具合解析情報を調査する)
- デバッガー観点(GDB/JTAG等のデバッガツールを使い不具合解析を行うために再現を行う)
効率的なバグの再現,あるいはエラーによる影響の明確化。
ロギング(print文)
最も古く、そして最もよく用いられるデバッグ手法はprint文を使う方法。
学生時代の20年前から何も変わってない。
具体的にはプログラムコードにprint文を挿入することで、
- どの部分が実行されたのか?
- レジスタや変数の実際の値はいくつなのか?
といった情報を表示させる。
ただし、ソフトウエアの動作に変更が加わるため、本来の動作とは異なるものとなったり再現しなくなることがある。
私は入社時にチューターより
print文でしか不具合解析できないエンジニアは、ユースケースやコールフローが分かってない無能だ。
と言われたのを今でも覚えているし、的は得ている。
デバッグツール(デバッグモニター)
前述どおりprintfは 入れただけで挙動が変わるので使えないケースが多い。
このような場合には、アプリレイヤはAndroid Studioを利用したり、Nativeレイヤではgdbなどを使って実行中のプロセスへのアタッチする事が考えられる(デバッグモニター(リモートデバッガ))
GDBに関しては使い方を新人の頃にまとめた。また、実際にデッドロックの調査方法を昨年まとめておいた。
また書籍でも詳しいものがある。
……で、その他に関しては詳しい他のサイトを見つけたから省略する。
検索ヒットを見越して他のデバッグモニターも紹介しておく。
インサーキットエミュレータ(ICE) | 基板上のCPUをプローブに差し替えることにより、CPUの動作をそのままエミュレートする。便利だが高価 |
---|---|
JTAGエミュレータ | CPUを基板から取り外すことなく実装した状態で、そのままデバッグする。広く普及 |
AIによるデバッグの現状
バグの自動修正(automatic repair)はここ数年ソフトウェア工学の国際会議ではかなり盛り上がってる研究トピック。
調査した限りだと
静的解析ツールが検出したソフトウェアの潜在バグ箇所に対して、AIが修正パターンを当てはめながら修正案を開発者に推奨する技術
※株式会社三井住友フィナンシャルグループ/株式会社日本総合研究所/富士通株式会社
は存在していた。
これぐらいCoverity等の商用ツールなら標準サポートして欲しい。
それより前に、FacebookがMark Harmanが陣頭指揮を取って開発した自動バグ修正ツール「SapFix」を社内で活用しているという記事も見つけた。
- 過去の修正から人手で作った修正パッチのテンプレートを、そのまま持ってくるか、あるいはそれがハマらなければミューテーションを使ってテンプレートを変形してパッチを作成。
- 上で出来上がったパッチを元に、さらに複数のパッチを生成。
- 生成したパッチがコンパイルを通るようなら、さらに開発者が人手で書いたテストとSapienzで生成したテストを流して、このパッチでもうクラッシュが起こらないか+別のクラッシュが発生しないかチェック。
- チェックを通ったパッチは人間がレビューして、良さそうならそのパッチを適用。
まだ、この程度か。
まぁ……私が死ぬまでには出来ると良いな。ぐらいかな。
おわりに
詳細に記載すると長くなりそうなので、今回は単なる概要紹介に留まる。年末にやる事じゃないからね……。
また次の機会にデバッグおよびデバッガビリティに関して記載したい。
「こんな方法もあるよ」的なフィードバックは大歓迎。正直不具合が追いつかず困ってます。