
ソフトウェアバグとは、コンピュータソフトウェアの欠陥(バグ)のことです。バグが多い、あるいは深刻なバグのあるコンピュータプログラムは、「バグだらけ」と表現されることがあります。
ソフトウェアのバグの影響は、軽微なもの(ユーザーインターフェースのスペルミスなど)から深刻なもの(頻繁なクラッシュなど)まで多岐にわたります。
2002年、米国商務省国立標準技術研究所が委託した調査では、「ソフトウェアのバグ、つまりエラーは非常に蔓延しており、非常に有害であるため、米国経済に 年間推定590億ドル、つまり国内総生産の約0.6%の損失を与えている」と結論付けられた。 [ 1 ]
1950年代以降、一部のコンピュータシステムは、動作中に様々なソフトウェアエラーを検出したり、自動的に修正したりするように設計されてきた。
欠陥を表す「バグ」という用語は、電子計算機やコンピュータソフトウェアが登場するずっと前の1870年代から、少なくとも工学用語として使われてきました。例えば、トーマス・エジソンは1878年に同僚に宛てた手紙の中で、次のように書いています。
私の発明はすべてそうでした。最初のステップは直感で、閃きとともに訪れますが、その後困難が生じます。この製品は機能しなくなり、そこで「バグ」と呼ばれる小さな欠陥や問題が現れ、商業的な成功または失敗が確実に訪れるまでには、数ヶ月にわたる集中的な観察、研究、作業が必要になります。[ 2 ]
第二次世界大戦中の軍事装備の不具合は、バグまたはグリッチと呼ばれていた。[ 3 ]
アイザック・アシモフは、 1944年に発表された短編小説「ウサギを捕まえろ」の中で、ロボットの不具合を表すのに「バグ」という言葉を使った。

コンピューターのパイオニアであるアメリカ海軍少将グレース・ホッパーは、初期の電気機械式コンピューターで蛾が問題を引き起こしたという話を広めた。[ 4 ]ホッパーが1947年頃、ハーバード大学の教員としてMark IIとMark IIIに取り組んでいたとき、オペレーターはMark IIのエラーの原因がリレーに挟まった蛾であることを突き止めた。蛾は機構から取り除かれ、ログブックに「バグが発見された最初の実際の事例」というメモとともにテープで貼り付けられた。 [ 5 ]伝えられるところによると、後にバージニア州ダールグレンの海軍兵器研究所に所属する ことになるウィリアム「ビル」バークを含むオペレーターたちは、工学用語に精通しており、おそらくバグの2つの意味(生物学的バグと技術的バグ)を混同して駄洒落を言っていたのだろう。冗談だったとしても、この話は当時コンピューター分野でこの用語が一般的に使われていたことを示している。[ 7 ] [ 8 ] [ 9 ] [ 10 ]
ミスの変容(ギリシャ語のmeta = "変化"、morph = "形" に由来)とは、ソフトウェア展開の最終段階における欠陥の進化を指します。ソフトウェア開発ライフサイクルの初期段階でアナリストが犯したミスが、サイクルの最終段階で欠陥につながる変容は、ミスの変容と呼ばれています。[ 11 ]
開発サイクルにおけるミスのさまざまな段階は、ミス、[ 12 ] : 31異常、[ 12 ] : 10障害、[ 12 ] : 31失敗、[ 12 ] : 31エラー、[ 12 ] : 31例外、[ 12 ] : 31クラッシュ、[ 12 ] : 22グリッチ、バグ、[ 12 ] : 14欠陥、インシデント、[ 12 ] : 39または副作用として説明できます。
ソフトウェアのバグは災害と関連付けられている。
ソフトウェアの動作を説明する際に「バグ」という言葉を使うことは、認識の違いから議論の的になることがある。バグという言葉は欠陥が自然に発生したことを示唆するとして、この用語の使用をやめるべきだと主張する人もいる。代わりに「欠陥」という言葉を使うべきだという意見もある。欠陥という言葉の方が、人間が原因であることをより明確に示しているからだ。[ 17 ]
バグは意図的な設計上の決定を隠蔽するために使われている可能性があると主張する人もいる。2011年、ユーザーの位置情報を暗号化されていないファイルに記録して保存していることで米国のアル・フランケン上院議員から批判を受けた後、 [ 18 ] Appleはこの動作をバグと呼んだ。しかし、民主主義とテクノロジーセンターのジャスティン・ブルックマンはこの説明に直接異議を唱え、「彼らがバグと呼ぶものを修正しているのは喜ばしいが、ユーザーを追跡していることを強く否定している点には異議がある」と述べた。[ 19 ]

ソフトウェア開発プロセスのできるだけ早い段階でバグを防止することは、投資とイノベーションの目標である。[ 20 ] [ 21 ]
新しいプログラミング言語は、既存の言語の脆弱性に基づく一般的なバグを防止するように設計される傾向があります。BASICやCなどの古い言語から得られた教訓は、C #やRustなどの後発の言語の設計に役立てられています。
コンパイル言語では、実行時前に(例えば、識別子のスペルミスなど)一部のタイプミスを検出できるため、インタプリタ言語よりもソフトウェア開発プロセスの早い段階で検出が可能になります。
言語には、静的型システム、制限された名前空間、モジュール型プログラミングなどの機能が含まれる場合があります。たとえば、型付きコンパイル言語(C言語など)の場合:
float num = "3";
構文的には正しいが、右辺が文字列であるため、float型の変数に代入できず、型チェックに失敗する。コンパイルエラーが発生するため、開発を再開するにはこの欠陥を修正する必要がある。インタプリタ型言語の場合、このエラーはステートメントが実行されるまで(実行時であればずっと後)発生しない。
一部のプログラミング言語は、バグが発生しやすい機能をあえて排除することで、パフォーマンスの低下を招いています。これは、複雑でバグの多いコードを書くよりも、シンプルで遅くても正しいコードを書く方が一般的に優れているという考えに基づいています。例えば、Javaはポインタ演算をサポートしていません。ポインタ演算は非常に高速ですが、慎重に使用しないとメモリ破損やセグメンテーション違反を引き起こす可能性があります。
一部のプログラミング言語には、一般的なバグを防ぐために実行時オーバーヘッドを追加する機能が含まれています。例えば、多くの言語には実行時境界チェック機能や、境界外エラーが発生した場合にクラッシュするのではなく回復する仕組みが備わっています。
スタイルガイドラインと防御的なプログラミングによって、見落としやすいタイプミス(誤植)を防ぐことができます。
例えば、ほとんどのC系プログラミング言語では、命令が1つしかない場合、命令ブロックを囲む中括弧を省略できます。次のコードは、条件が真のfoo場合にのみ関数を実行しますcondition。
条件が満たされた場合 foo();
しかし、このコードは常に実行されますfoo。
条件を満たす場合 foo();
括弧を使用することで、厳密には必須ではない場合でも、このエラーを確実に防ぐことができます。
if (条件) { foo(); }規約の遵守は、手動(コードレビューなど)で行うことも、リンターなどの自動ツールで行うこともできます。
プログラムの意図する動作を記述したプログラム仕様書を作成することで、バグを防ぐことができると主張する人もいる。しかし、組み合わせ爆発や不確定性の問題があるため、形式仕様書は最短のプログラム以外には実用的ではないと主張する人もいる。
ソフトウェアテストの目的の一つはバグを見つけることです。テスト中の測定によって、残っている可能性のあるバグの数を推定できます。製品のテストと開発期間が長くなるほど、この推定の信頼性は高まります。[ 22 ]
アジャイルソフトウェア開発では、比較的小規模な変更を頻繁に行うソフトウェアリリースが一般的です。欠陥はユーザーからのフィードバックによって明らかになります。
テスト駆動開発(TDD)では、本番コードを作成する際に同時に単体テストも作成され、すべてのテストが作成され、正常に完了するまで本番コードは完成したとはみなされません。
静的コード解析ツールは、コンパイラの能力を超えてプログラムテキストを検査し、潜在的な問題を特定することで、開発者を支援します。一般的に、仕様に基づいてすべてのプログラミングエラーを見つけるという問題は解決不可能ですが(停止問題を参照)、これらのツールは、人間のプログラマーがソフトウェアを作成する際に特定の種類の単純なミスを犯しやすいという事実を利用しています。
ソフトウェアの実行中にパフォーマンスを監視するツールは、ボトルネックなどの問題を特定したり、正しく動作していることを確認したりするために、コードに明示的に組み込むことも(例えば、単に `.` という文を記述するだけで済む場合もあるPRINT "I AM HERE")、ツールとして提供することもできます。処理時間の大部分が特定のコードによって費やされていることに気づいて驚くこともよくあり、こうした前提を取り除くことで、コードの書き直しが必要になる場合もあります。
オープンソース開発では、誰でもソースコードを検証できます。エリック・S・レイモンドが「リーナスの法則」として広めた考え方では、人気のあるオープンソースソフトウェアは、他のソフトウェアよりもバグが少ないかまったくない可能性が高いとされています。なぜなら、「十分な数の目があれば、すべてのバグは浅いものになる」からです。[ 23 ]しかし、この主張には異論があります。コンピュータセキュリティ専門家のエリアス・レヴィは、「複雑で理解されにくく、文書化されていないソースコードに脆弱性を隠すのは簡単だ」と書いています。なぜなら、「たとえ人々がコードをレビューしていたとしても、それが彼らがそうする資格を持っていることを意味するわけではない」からです。[ 24 ]オープンソースソフトウェアのバグの例として、2008年のDebianのOpenSSLの脆弱性があります。
デバッグはソフトウェア開発ライフサイクルの重要な部分になり得る。初期のコンピューティングのパイオニアであるモーリス・ウィルクスは、1940年代後半に「残りの人生の大部分は自分のプログラムのエラーを見つけることに費やされるだろう」と気づいたと述べている。[ 25 ]
通常、バグを見つけるための最初のステップは、バグを確実に再現することです。問題を再現できない場合、プログラマーはバグの原因を特定できず、したがって修正することもできません。
再現が難しい入力によって明らかになるバグもあります。Therac -25放射線治療装置の死亡事故の一因は、治療計画を装置操作者が非常に速く入力した場合にのみ発生するバグ(具体的には競合状態)でした。この操作を習得するには何日も練習が必要だったため、テスト時や製造元が再現を試みた際にはバグは顕在化しませんでした。一方、デバッガを使用してプログラムを実行するなど、バグの発見に役立つように設定を拡張すると発生しなくなるバグもあります。これらはハイゼンバグ(ハイゼンベルクの不確定性原理にちなんでユーモラスに名付けられました)と呼ばれます。
バグは単なる欠陥ではなく、プログラマーの思考や計画の誤りである場合もあります。多くの場合、このような論理エラーはプログラムの一部を全面的に見直したり書き直したりすることを必要とします。これはコードリファクタリングと呼ばれるプロセスです。
コードレビューでは、コードをステップ実行し、実行プロセスを想像したり書き起こしたりすることで、バグそのものを再現することなくエラーを発見できる場合がよくあります。
デバッガと呼ばれるプログラムは、コードを一行ずつ実行したり、変数の値を表示したりするなど、プログラムの内部動作を調べることで、プログラマーが欠陥のあるコードを見つけるのに役立ちます。
デバッガーを使用する代わりに、プログラムの実行を追跡し、値を表示するためにデバッグ情報を出力するロジックをコードに組み込むことができます。出力は通常、コンソール、ウィンドウ、ログファイル、またはハードウェア出力(場合によってはインジケータLEDを駆動する)に行われます。
1990年代以降、特にアリアン5 501便の事故以降、抽象解釈による静的コード解析などのデバッグの自動化支援への関心が高まった。[ 26 ]
組み込みシステムでは、ハードウェアのバグを回避するためにソフトウェアを修正することがよくあります。これは、ソフトウェアの修正の方がハードウェアの修正よりも安価で、システムへの影響も少ないためです。

バグは、文書化、分類、担当者の割り当て、再現、修正、修正済みコードのリリースといった活動を通じて管理されます。
ソフトウェアのバグやその他の問題を追跡するためにツールがよく使用されます。通常、ソフトウェア開発チームが作業負荷を追跡するために使用するツールと、カスタマーサービスがユーザーからのフィードバックを追跡するために使用するツールは異なります。[ 27 ]
追跡対象項目は、バグ、欠陥、チケット、課題、機能などと呼ばれることが多く、アジャイルソフトウェア開発ではストーリーやエピックと呼ばれることもあります。項目は、深刻度、優先度、影響を受けるバージョン番号などの側面によって分類されることがよくあります。
トリアージと呼ばれることもあるプロセスでは、バグの深刻度や優先度、開発スケジュールなどの外部要因などの情報に基づいて、各バグを修正するかどうか、いつ修正するかが決定されます。トリアージには通常、原因の調査は含まれません。トリアージは定期的に行われる場合があり、少なくとも前回のトリアージ以降に発生した新しいバグのレビューから始まり、場合によってはすべての未解決のバグにまで及ぶ可能性があります。参加者には、プロジェクト マネージャー、開発マネージャー、テスト マネージャー、ビルド マネージャー、および技術専門家が含まれる場合があります。[ 28 ] [ 29 ]
深刻度は、バグがもたらす影響の尺度です。[ 30 ]この影響には、データ損失、金銭的損失、信用の喪失、無駄な労力などが含まれます。深刻度レベルは標準化されておらず、業界や追跡ツールなどのコンテキストによって異なります。たとえば、ビデオゲームのクラッシュは、銀行サーバーのクラッシュとは異なる影響をもたらします。深刻度レベルの説明の例としては、クラッシュまたはハング、回避策なし(ユーザーがタスクを完了できない)、回避策あり(ユーザーはタスクを完了できる)、視覚的欠陥(たとえばスペルミス)、ドキュメントエラーなどがあります。深刻度の別の例としては、重大、高、低、ブロッカー、些細などがあります。[ 31 ]バグの深刻度は、修正の優先度と同じカテゴリである場合もあれば、2つを別々に定量化して管理する場合もあります。
優先度とは、他のバグとの関連において、そのバグを解決することの重要性を表すものです。優先度は、1から5などの数値で表される場合もあれば、重大、高、低、延期といった名称で表される場合もあります。優先度は異なる側面ではありますが、その値は深刻度評価と類似または同一である可能性があります。
優先度は、バグの深刻度と修正に必要な労力の組み合わせによって決まる場合があります。深刻度は低いものの修正が容易なバグは、深刻度が中程度でも修正にかなりの労力を要するバグよりも優先度が高くなる可能性があります。
優先度の高いバグは、それを修正するための特別なリリースが必要となる場合があります。このようなリリースは、パッチと呼ばれることもあります。
バグ修正を重視したソフトウェアリリースは、新機能やその他の変更を重視したリリースと区別するために、メンテナンスリリースと呼ばれることがある。
既知の低優先度バグやその他の問題を抱えたままソフトウェアをリリースすることはよくあることです。考えられる理由としては、以下のようなものが挙げられますが、これらに限定されるものではありません。
ソフトウェアのバグが引き起こす損害の量と種類は、ソフトウェアの品質に関する意思決定、プロセス、およびポリシーに影響を与えます。有人宇宙飛行、航空、原子力発電、医療、公共交通機関、自動車安全などの分野では、ソフトウェアの欠陥が人身傷害や死亡事故につながる可能性があるため、例えばオンラインショッピングサイトなどと比べて、はるかに厳格な検査と品質管理が行われます。銀行業務のように、ソフトウェアの欠陥が銀行や顧客に深刻な金銭的損害を与える可能性がある分野でも、例えば写真編集アプリケーションなどと比べて、品質管理はより重要になります。
バグによる損害以外にも、バグの修正に費やされる労力がコストの一部を占めています。1978年にLientzらは、プロジェクトの平均が開発労力の17%をバグ修正に費やしていることを示しました。[ 36 ] 2020年のGitHubリポジトリに関する調査では、平均が20%であることが示されました。[ 37 ]
1994年、NASAのゴダード宇宙飛行センターは、平均エラー数を1,000行のコード( SLOC )あたり4.5件から1件に削減することに成功した。[ 38 ]
1990年の別の研究では、非常に優れたソフトウェア開発プロセスでは、 1000 SLOC あたり 0.1 という低い展開失敗率を達成できることが報告されています。[ 39 ]この数値は、 Steve McConnellのCode Complete [ 40 ]やNASA の Flight Software Complexity に関する研究[ 41 ]などの文献で繰り返し言及されています。一部のプロジェクトでは、欠陥ゼロを達成したものもあります。IBM Wheelwriterタイプライターのファームウェア(63,000 SLOC) や、スペースシャトルのソフトウェア (500,000 SLOC) などです。[ 39 ]
テストとデバッグに関する再現可能な研究を促進するために、研究者は厳選されたバグのベンチマークを使用します。
注目すべきバグの種類:
バグは、仕様に基づいた設計が不十分または不正確であることに起因する場合があります。例えば、仕様が単語リストをアルファベット順に並べることである場合、設計で記号が考慮されていないと、記号を含む単語が正しくアルファベット順に並べられないという設計上のバグが発生する可能性があります。
Numerical operations can result in unexpected output, slow processing, or crashing.[46] Such a bug can be from a lack of awareness of the qualities of the data storage such as a loss of precision due to rounding, numerically unstable algorithms, arithmetic overflow and underflow, or from lack of awareness of how calculations are handled by different software coding languages such as division by zero which in some languages may throw an exception, and in others may return a special value such as NaN or infinity.
A control flow bug, or logic error, is characterized by code that does not fail with an error, but does not have the expected behavior, such as infinite looping, infinite recursion, incorrect comparison in a conditional such as using the wrong comparison operator, and the off-by-one error.
ニュー・アメリカという団体が運営するオープン・テクノロジー・インスティテュート[51]は、2016年8月に「システムのバグ」という報告書を発表し、米国の政策立案者は研究者がソフトウェアのバグを特定して対処できるよう改革を行うべきだと述べた。この報告書は「ソフトウェアの脆弱性の発見と開示の分野における改革の必要性を強調している」[ 52 ] 。報告書の著者の1人は、議会はサイバーセキュリティというより大きな問題に対処するために多くの法案を可決したが、サイバーソフトウェアの脆弱性に対処するには十分なことをしていないと述べた[ 52 ] 。
政府の研究者、企業、サイバーセキュリティの専門家が、通常ソフトウェアの欠陥を発見する人々である。報告書は、コンピュータ犯罪法と著作権法の改革を求めている。[ 52 ]
報告書によると、コンピュータ詐欺および濫用法、デジタルミレニアム著作権法、電子通信プライバシー法は、セキュリティ研究者が正当なセキュリティ研究を行う際に日常的に行う行為を犯罪化し、民事罰を科すものである。[ 52 ]
(コブとミルズ 1990)