連載
» 2010年01月18日 00時00分 UPDATE

山浦恒央の“くみこみ”な話(15):最もタチの悪いバグが潜むテストフェイズとは?

テストの最終段階で「性能バグ」に振り回されないためには、仕様定義の段階から“性能設計”をキチンと実施しておくべき!!

[山浦恒央 東海大学 大学院 組込み技術研究科 准教授(工学博士),@IT MONOist]

 前回のコラム「『ソフトウェアテスト』と『振り込め詐欺』の関係」では、7つの「基本的な出荷基準」を挙げ、「4.エラー・ゲシング(Error Guessing)を実施した」について解説しました。今回は、その続き、「5.長時間耐久テスト、過負荷テストを実施した」を紹介します。


 まずは、7つの基本的な出荷基準について再掲します。

  1. 全機能をテストした 
    ブラックボックス/ホワイトボックス・テストで同値分割を実施した。
  2. 境界条件をテストした 
    ブラックボックス/ホワイトボックス・テストの境界値分析を実施した。
  3. 未実行コードがない 
    ホワイトボックス・テストのC0パス網羅を満足した。
  4. エラー・ゲシング(Error Guessing)を実施した 
    バグを想定し、それを摘出するためのテスト項目を設計・実施した。
  5. 長時間耐久テスト、過負荷テストを実施した 
    48時間の連続運転や、過負荷状態での稼働テストを実施した。
  6. バグの発生が頭打ちになった 
    いわゆる「バグ摘出曲線」がフラットになった。
  7. 未修正のバグが残っていない 
    摘出したバグは全件修正した。

 それでは、エラー・ゲシングにも関係が深い「5.長時間耐久テスト、過負荷テストを実施した」について詳しく見ていきましょう。

見るだけでご飯が3杯食える曲線

 人口増加や病原菌の繁殖など、何かが増えたり大きくなったりする場合、図1に挙げるS字カーブを描くといわれています。

Gompertz Curve(ゴンペルツ曲線) 図1 Gompertz Curve(ゴンペルツ曲線)

 この成長曲線にはいろいろなモデルや数式がありますが、代表格が「Gompertz Curve(ゴンペルツ曲線)」でしょう。バグの発生数もこの曲線を描くといわれているため、ソフトウェア技術者には非常に縁の深い曲線です。品質制御屋さんは、このS字曲線を眺めるだけで、ご飯が3杯食えるほど元気が出るそうです。ソフトウェア・エンジニアリングの分野は、工学系では珍しく複雑な数式が出てきませんが(そのため、世界的な傾向として、数学が苦手な理科系とナゾナゾが好きな文科系が情報処理系に集まります)、唯一の例外がソフトウェアの信頼性関係でしょう。図1の下に書いた式を見て頭が痛くなった人は、「(数学が苦手な)典型的なソフトウェア技術者」です。

 ゴンペルツ曲線は「増加」だけでなく、「減少」にも適用できます。図2は、図1の曲線を上下に引っくり返した鏡像です。

鏡像のゴンペルツ曲線 図2 鏡像のゴンペルツ曲線

 この曲線もソフトウェア開発におなじみで、例えば、デバッグにおける「未消化(残存)テスト項目数」がこのカーブを描きます。

はじめチョロチョロ、なかパッパ――ゴンペルツ曲線の3つのフェイズ

 バグの発生パターンに適用できるゴンペルツ曲線は、以下のように3つのフェイズに分かれます。

  • フェイズ1:胎動期(準備段階)
  • フェイズ2:成長期(急激に成長する段階)
  • フェイズ3:停滞期(成長が止まり、漸近線に近づく段階)

 おいしくご飯を炊く火加減のコツとして、昔の人は「はじめチョロチョロ、なかパッパ、赤子泣いてもふた取るな」といっています。これは、ゴンペルツ曲線のフェイズにも当てはまります。

 ゴンペルツ曲線をソフトウェアのテストに適用した場合、各フェイズの意味は以下のようになります。

フェイズ1(図3)

テストにおけるゴンペルツ曲線:フェイズ1 図3 テストにおけるゴンペルツ曲線:フェイズ1

 これは、テスト開始の初期段階によく見られるパターンです。テストの最初の目標は、代表的な機能の正常系を最後まで通すことですが、フェイズ1では、プログラムのメイン・ストリートが疎通しておらず、基本機能の正常系のバグ(例えば、機能漏れ)が多く見つかります。

 この基本機能の不良は、山を貫通するトンネルを掘っている最中にぶつかった巨大な岩盤のようなバグで、このバグを修正しない限り先へ進めません。すなわち、「バグ検出」と「バグ修正」を並列・独立に進めることができず、シーケンシャルな作業を強いられます。バグを修正しないと次のテスト項目を実行できず、1件の実行・消化に時間がかかります。

フェイズ2(図4)

テストにおけるゴンペルツ曲線:フェイズ2 図4 テストにおけるゴンペルツ曲線:フェイズ2

 プログラムの代表的なパスが疎通し、基本機能は正常に動くようになった状態です。このフェイズでは、基本機能の枝にある「異常条件」「境界条件」「限界条件」のテストが多くなります。基本機能の枝道のテストですので、そこにバグがあっても、別のテスト項目は独立・並列に実施できます。テスト項目を一挙に消化できるフェイズですし、バグがあっても、単純で再現性がありますので、修正にも時間はかかりません。

 ある意味、「稼ぎ時」のフェイズなのですが、注意点が1つあります。ここでは、多数のバグが出るため、大量に修正することになりますが、修正時に新たなバグを作り込む可能性が大きくなるということです。研究によると、バグ修正時に新しいバグを作り込む割合は20%にもなるそうです。また、「バグ修正で作り込んだ新バグ」は、「通常のバグ」に比べ、非常にタチが悪いといわれています。正常に動作しないのでバグを突き止めようとするのですが、「修正したのでその部分にバグはない」と思い込んで、無意識に「バグ修正のバグ」を捜査対象外にしてしまいます。一度この盲点にはまり込むと、なかなか抜けられません。

フェイズ3(図5)

テストにおけるゴンペルツ曲線:フェイズ3 図5 テストにおけるゴンペルツ曲線:フェイズ3

 基本機能、異常処理も正しく動く状態でのテストです。このフェイズで出るバグは、「特殊条件」「複合条件」に関係するバグ(例えば、タイミング関連)や、性能関連が多くなります。フェイズ3のテストは、フェイズ1、フェイズ2に比べると、数は少ないものの、難度は圧倒的に高く、膨大な時間がかかります。その原因は以下の2つにあります。

(1)再現困難なバグが多い

 バグは、再現条件が分かれば、解決したも同然です。フェイズ3のバグは、タイミングに関係するものが多く、再現させることが簡単ではありません。つまり、摘出・修正に長い時間と忍耐が必要となります。プロセスが順序どおりに動くバッチ系のプログラムでは、再現困難なバグはほとんどありませんが、システムの状況に応じてプロセスの追い越しが起きるリアルタイム系のプログラムでは、不思議な現象が頻発します。例えば、携帯電話を折り畳むと、省電力モードになりますが、この「折り畳んだ」という割り込みが、あるタイミングで発生すると、実行中の別のプロセスに干渉してシステムがフリーズするというバグです。このバグを再現させるため、1ダースの技術者が、一日中カスタネットのように携帯電話をパコパコと際限なく折り畳んでは戻したそうです……。

 ここでの非常に大きな問題は、「バグが再現しない場合、どうするか?」です。再現しない限り、バグの発生条件を把握できず、解決できません。こんなバグを再現させるには、数週間から数カ月かかるでしょう。それまで、製品のリリースをしないのも1つの選択肢です。特に、環境破壊や人命に影響するソフトウェアの場合、バグが再現しないからといって、安易にリリースできません。一方、環境や人命に悪影響を及ぼさないソフトウェアで、かつ、バグが発生しても逃げ道がある場合は(例えば、先ほどの携帯電話の場合、電源のオン・オフでリカバリーが可能)、リリースすることが多いと思います。ただし、再現した場合に、バグ解析のためのデータが採集できるようなロジックを埋め込んでリリースすることが重要です。

(2)準備に時間がかかる

 例えば、「最大512台のPCが同時に稼働するか?」のような最大構成でのテストは、準備に何日もかかります。512台のPCを準備できない場合は、シミュレータを作らねばなりません。「100万件までのデータを処理できる」と仕様書に書いてあれば、実際に、100万件のデータを作って、テストすることになります。最大件数のテストでは、ディスクやメモリを増設する必要もあります。お金と時間と労力がかかりますが、それをサボると、「アメリカやインド方式の品質管理」になってしまい、高品質のプログラムは作れません。

最もタチの悪いバグ

 フェイズ3は、魑魅魍魎(ちみもうりょう)のバグが潜む伏魔殿といえます。その中で最もタチの悪いバグは性能関係のバグです。

 例えば、仕様書に「ネットワークに負荷がない場合、PCから1024バイトのメッセージを送信すると、中央側で処理して30秒以内に応答を返す」と書いてある場合、その応答性能を守らねばなりません。60秒もかかると、顧客から「そんなに遅くては、業務が成り立たない、ビジネスにならない」といわれたりします。性能関係のバグを扱うのは、ほかのバグに比べて圧倒的に面倒です。その理由は「最終段階にならないと摘出できない」「修正が非常に困難」の2つにあります。

 最大構成のテストや過負荷テストは、正常機能、異常処理が問題なく稼働しない限り、実施できません。性能系のテストは、最後の「大トリ」に取っておくことが多いのですが、もし、「応答時間として30秒を期待していたのに、60秒もかかってしまう」というバグが出た場合、簡単には解決できません。「機能漏れ」は、非常に重大なバグといわれていますが、モジュールを追加すれば(比較的)簡単に短時間で解決できます。しかし、性能のバグはそうはいきません。

 まず、顧客と話し合って、本当に30秒以内で応答が返らないと業務が成立しないかを確認する必要があります。30秒とか60秒のような切れのよい数字をテキトーに挙げただけの場合があり、「この機能はほとんど使わないので、60秒でもいいですよ」とあっさりいってもらえる場合があります。現実には、こんなラッキーなケースはほとんどなく、大抵は「何が何でも、絶対に死ぬ気になって、30秒で応答を返してほしい」とネジ込まれます。「仕様書にそう書いてあるでしょう?」といわれてしまえばおしまいです。

 こうなると、処理方式やアルゴリズムを根本から変更しなければならず、作り直しになります。作り直しに伴って大騒動が起き、さらに、新しいバグが20%の確率で忍び込むため、大混乱は避けられず、半年遅れでバグだらけの製品をリリースすることになります。これは、開発側のみならず、発注側も不幸な状況です。

 こうした最悪の事態を避けるには、(もし可能なら)「ハードウェアの入れ替え」で性能バグに対処すべきです。高速の通信回線、メモリやディスクの増設、高速マシンを使って、期待する性能が出るのなら、そうすべきでしょう。技術的な問題はこれで解決します。ハードウェア費用の負担問題は、上層部同士の政治的決着に任せましょう。エラい人は、そのために高給をもらっているのですから。

 ソフトウェアの開発では、機能設計や実装を最重要視し、性能設計の視点からアプローチすることはほとんどありません。テストでも同様です。最終段階で、性能バグに振り回されないためには、仕様定義の段階から、性能設計をキチンと実施しておくべきです。例えば、自動車のエア・バッグを膨らませる場合のように、応答時間が極めてクリティカルなシステムでは、プロトタイプを作って、期待する性能が出るかチェックしておく必要があります。そして、テストのフェイズ3では、「それを再確認するだけ」にすべきです。

48時間耐久テストと過負荷テスト

 長時間稼働させると、想定しない不具合が数多く見つかります。48時間耐久テストと過負荷テストは、フェイズ3で発生する「タチの悪いバグ」を総合的にチェックしているといえます。

 フェイズ3で見つかるバグは、開発・設計手法や、ソフトウェア開発者の人間性のように、根本的なものに関係するものが多く、小手先では解決できません。要求仕様定義の段階から品質設計をしておく必要があります。(次回に続く)

【 筆者紹介 】
山浦 恒央(やまうら つねお)
東海大学 大学院 組込み技術研究科 助教授(工学博士)

1977年、日立ソフトウェアエンジニアリングに入社、2006年より、東海大学情報理工学部ソフトウェア開発工学科助教授、2007年より、同大学大学院組込み技術研究科助教授、現在に至る。

主な著書・訳書は、「Advances in Computers」 (Academic Press社、共著)、「ピープルウエア 第2版」「ソフトウェアテスト技法」「実践的プログラムテスト入門」「デスマーチ 第2版」「ソフトウエア開発プロフェッショナル」(以上、日経BP社、共訳)、「ソフトウエア開発 55の真実と10のウソ」「初めて学ぶソフトウエアメトリクス」(以上、日経BP社、翻訳)。


Copyright© 2017 ITmedia, Inc. All Rights Reserved.