トラブルシューティングの極意―達人に訊く問題解決のヒント

第11回 [ソフトウェア開発編]むやみやたらにデバッグ+テストしていませんか?―「ソースコード」の指紋からわかるバグの原因

この記事を読むのに必要な時間:およそ 3 分

一般的な開発シーンで,静的解析ツールを利用して文法的な誤りを検出するアプローチがあります。さらに全網羅テスト(考え得る組み合わせを全数テストすること)なども一般的に行われています。また,トラブルが発生した場合に「全員総掛かり」で,しかもすべてのコードを1本目から「しらみつぶし」に読破して「確認する!」――といった場面が少なくありません。果たしてそれは効率的な仕事でしょうか?

今回はトラブルの原因をコードの中に追求します。

ソースコードの傾向に見る誤りの予測(初級編)

全網羅テストのムダ

テストをしらみつぶしですると,安心感や自信につながるので,そこに目的と理由があるかもしれません。しかし,これらのアプローチは一見合理的に見えて,実は投入対効果(=投資効率)の観点で非常に無駄が多いのです。

ソフトウェア開発における障害は,そもそもソースコードに起因します。ならば,全コードを目視検査すれば良いのか?̶̶それでは元の木阿弥です。スマートな方法は,バグが発生する原因を「ソースコードの位置」「バグの種類」から特定することです。これならば,短時間で原因追及ができます。いわば「トラブルを狙い撃つ」技術です。

兆候を読み取る技術とは

テストケースは少ないに越したことはありません。従来どおりのテスト手法や製品領域があることも否定しませんが,テストケースにあらかじめ「偏り」を持たせることで,重点的にテスト実施すべき場所か否かといった「加減」ができるようになります。それが兆候を読み取る技術です。これを「Fingerprint Detection(指紋検出)⁠テクニックといいます。

ソースコードの兆候を観察し誤りを予測する

まず,3つの兆候検知方法を次に挙げます。

[方法1]コードの外形
(兆候が現れている対象を選ぶ)
[方法2]コードのデータ
(各種コードメトリクスからのアプローチ)
[方法3]内部の兆候検知
(NGワード/一発でおかしい記述の検出)

端的に言えば,これらは「特異点を見つけ出す」方法です。実はトラブルシュートや問題判別手順に共通な考え方があります。それは,できるだけ「考えられる可能性を排除する」ことです。つまり探索/調査範囲を小さくする手順です。その位置と種類の検出を最優先課題とする思考方法です。実際には希望的観測や認知バイアスが存在するので簡単にはいきません。ですが「段階的に可能性を排除する思考」で,問題判別を迅速に行い被害を最小化できるようになります。

[方法1]コードの外形で兆候検知

ソースコードのファイル群から,目視で問題のあるファイルを狙い撃つには,決定的なポイントがあります。前述のように特異点を見つけることです。もちろんファイルをひとつひとつ開くような手間をかけません。次の方法を行います。

最終更新日付が怪しい

最後に更新された(更新日付が最新の)ファイルを選びます。とくにトラブルが発生した場合などは,トラブルが発生した前後の日付が対象ファイルです。

ファイル名の長さが怪しい

クラス/ソース名を確認し,そのシステムの命名規約から逸脱しているものを優先的に選び出します。名前や長さが異なるものは,リリース後に追加された可能性があります。つまり,開発当初のルールを踏襲していないので,機能が不整合を起こしている可能性があります。

ハイフン付きは怪しい

JavaやC言語では「ハイフン」がファイル名にあるものを選びます図1)⁠これは(特別な命名規約がない限り)ベテランに多い傾向です。汎用機言語(COBOLやPL/I)の名残りです。変数名やファイル名にハイフンを使うのは開発者の「手癖」です。ハイフンによる命名規約が悪いのではなく,他コード群と比べてわずかに人の癖が見える特徴です。

図1 ハイフン付きは怪しい。手癖が原因?

図1 ハイフン付きは怪しい。手癖が原因?

一番サイズが大きいものが怪しい

サイズが大きいコードは,複雑度が高い可能性があります。一般的にコード行数とIF分岐条件には相関があり,高い相関係数を示します。行数が多いコードは,IF文のような分岐文を多く含んでいます。つまり「全部テストしきれていない」可能性が高いのです。

[方法2]データからの兆候検知(各種コードメトリクスからのアプローチ)

次に各種の定量数値(コードメトリクス)を取得し,そのデータから対象を選ぶ方法です。

NGワードの含有率(トラブル誘発因子の検出)

NGワードとは,コードの中に通常では記述されない表現・単語です。NGワードの含有数や含有率(=NGワード数÷コード行数)などが高い数値を示しているものを選びます。たとえば,⁠要検討」⁠要確認」⁠TODO」⁠TBD」などが,コード中にコメントとして残っている場合があります。これは開発時に仕様書を,そのままソースにコピー&ペーストした形跡を示唆しています。未確定仕様があれば,関連する単語がソースコードに残る場合があります。もちろん保守・改変時にもこれらの記述が増える可能性は高く,頻繁に改変を行っているコードに頻出して現れます。

コメント比率の確認(欠陥混入の間接メトリクス)

ソースコード全行数に対する「空行」および「コメントだけの行」の割合です。このメトリクスから,システムや製品の経年劣化状況を確認できます図2)⁠とくに,誤りの予測という観点では,一般的には次のような傾向があります。

  • コメント率が高いコードは,頻繁に改変された可能性が高い(ブロックコメントアウトによる履歴保存=コメント率が高くなるため)
  • 頻繁に改変されたコードは,テストが不足している可能性が高い(十分な回帰テスト工数を投資しているか疑問)
  • 頻繁に改変されたコードは,誤修正欠陥の混入確率が高い(複数人数でテストするため)
  • 急場で作ったコードはコメント率が低い可能性がある
  • 業務アプリケーションや制御のコードではない,移行ユーティリティやテストコードは,コメント率が低い場合がある

図2 コメント率で怪しいものを発見

図2 コメント率で怪しいものを発見

これらの理由から,コメント率の極端に高いものと低いもの(例:コメント率90%やコメント率5%以下)をサンプリング抽出します。

IFとELSEの比率(設計欠陥の間接メトリクス)

いわゆる分岐の片抜け,例外設計,信頼性設計などの確認です。IFとELSEなど,対にならなくてはならないキーワードを数えます。これで内容を推察します。たとえばELSEの個数をIFの個数で割ります。そうすると,ELSEがゼロのものや,極端にIFブロックだけ記載しているコードが浮かび上がってきます図3)⁠逆にIFとELSEがすべてのコードで1対1,つまり同数の場合は,何らかのコードジェネレータを使っている可能性があります図4)⁠

図3 IFとELSEペアの一般的傾向

図3 IFとELSEペアの一般的傾向

①や②はIFが数十~100以上のコードには,ELSEが0 ~10以下というものもあります。これは仕様書にもともとELSEが書かれていない影響もありますが,プログラマ側がELSE/その他の処理について意識する必要があります。とくにテストケース設計時にELSEやレコード0件,Null値などの異常テストケースの設計を見落とす可能性が高いため,テストケース設計基準についても併せて見直しが必要です。

図4 IFとELSEの対応について(自動生成の例)

図4 IFとELSEの対応について(自動生成の例)

もちろんC言語におけるK&R表記を標準とする場合など,標準化ルールやガイドにも関係しますが,一般的にELSE記述は設計段階での「例外略記/例外考慮不足」に最も影響を受ける数値です。これらの数値によって対象を絞り込むと効率よく設計欠陥を検出できるようになります(1本にIFが1,000個ある「おかしい」コードも,言うまでもなく対象です)⁠

著者プロフィール

細川宣啓(ほそかわのぶひろ)

日本アイビーエム株式会社東京基礎研究所 所属

品質エンジニアリング・欠陥エンジニアリング。バグ収集,特に集めたソフトウェア欠陥を眺めてバグ百科事典の編纂。

最近は人工知能やIoT,ロボットの品質保証について考える日々です。

https://www.facebook.com/nobu.dreamstate.hosokawa

バックナンバー

トラブルシューティングの極意―達人に訊く問題解決のヒント

バックナンバー一覧

コメント

コメントの記入