ソフトウェア品質

ソフトウェアの信頼性

ソフトウェアの信頼性（reliability）は、ソフトウェア品質を測る重要な尺度であり観点である。品質（quality）という用語には主観的（定性的）要素が含まれるが、ソフトウェアの信頼性は客観的な基準で測定可能である。このような測定基準を一般にソフトウェアメトリックと呼ぶ。ソフトウェアの信頼性改善の実際の作業は、ソフトウェア開発を扱いやすく理解可能なものにするという圧力によってなされてきたもので、収益を求めてのものではない。しかし、ソフトウェア産業の成熟と共に、ユーザーがソフトウェア製品に期待する品質レベルは高くなり、信頼性の確保が収益に繋がるという状況ができつつある。
組み込みシステムでは、ソフトウェアの問題は単なる不便以上の問題を生じる。場合によっては人命にも関わる。その原因はユーザインタフェースの貧弱さから直接的なバグまで様々である。多くの人命に関わったプログラムのバグについては、Levenson の論文 Medical Devices: The Therac-25 (PDF) に詳しい。結果として、ソフトウェアの信頼性に関する要求仕様が生まれた。アメリカ合衆国では、アメリカ食品医薬品局 (FDA) と連邦航空局 (FAA) がソフトウェア開発についてその種の要求仕様を策定している。

信頼性の目標

現代の工学分野の技術をソフトウェア開発に適用するため、ソフトウェアの品質を客観的に判断する方法が必要とされる。これは、誰が見てもコンピュータソフトウェアは予定通りの動作をしないという一般的観測結果に基づいた動機である。言い換えれば、ソフトウェアは何らかの問題を抱えていると不適当な動作を見せる。その原因は処理中のデータの問題だったり、ソフトウェアが動作するハードウェアの問題だったり、操作者などがそのマシンに悪影響を及ぼしたためだったりする。経済活動や生産プロセス、生命維持に直接関わるシステムなどのより重要なソフトウェアでは、ソフトウェアの信頼性を評価する必要性も大きくなる。
あるソフトウェアアプリケーションの重要さの度合いによらず、ソフトウェアは我々の生活のあらゆる面に深く浸透している。我々の社会基盤がソフトウェアに依存している限り、この浸透は続くと予想される。社会基盤がソフトウェアへの依存を強めるにつれて、ソフトウェアの信頼性のレベルの向上が求められるようになってきた。すなわち、ソフトウェアは意図したように動作すべきであり、常に改良が求められる。

信頼性への挑戦

前節の循環しているような文章は偶然ではない。これはソフトウェアの信頼性の測定に関する基本的問題を表している。信頼性は判断が難しく、特に事前にソフトウェアがどう使われるかを正確に想定することは難しい。問題は、従来ならば人間が担っていたであろう役割をソフトウェアが代替しているという共通の概念的錯覚から生じる。この問題は2つのレベルに分けられる。第一に、最新のソフトウェアは人間にはできないようなことを実行し、特に人間に比較するとその信頼性は非常に高い。第二に、ソフトウェアは人間の精神的な面を代替することはできない。つまり、融通を利かせるとか、常識を働かせるとか、概念的なことを理解する能力はない。
それにもかかわらず、多くのソフトウェアプログラムは何らかの目的を持つと見なすことができる。目的が明確に定義されるならば、ソフトウェアにある環境であるデータを与えたときに、予測される結果と実際の結果を比較することでその信頼性を客観的に判断することができることが期待される。しかし今のところ、プログラムに環境とデータを与えたときに、予測される結果や実際の結果を正確に求めることが可能かどうか定かではない。そして、そのような手段がなければ、プログラムの信頼性を確実性をもって決定することはできない。
しかし、実際のプログラムやプログラムの理論的記述について、その環境や入力による振る舞いを明らかにしようという試みはこれまでも数多くなされてきた。ソフトウェアの信頼性を改善するためのその種の試みは、実際のソフトウェア開発では様々な工程（要求仕様、設計、プログラミング、テスト、実行時評価）に適用される。ソフトウェアの理論的な信頼性の研究は、主に正当性の概念を扱い、形式言語やオートマトンといった計算機科学の数学的分野から派生している。

要求仕様

プログラムの開発者が「どう動作すべきか」を事前または開発中に詳細に把握していなければ、それが望ましい動作をすることは期待できない。どの程度詳細に把握すべきかは議論の余地がある。完璧な詳細さという考え方は魅力的だが、実際問題としては現実的ではない。なぜなら、「こうあるべき」という要求仕様は試行錯誤的に変化するものだからである。
事前に要求仕様をうまく記述できるかどうかは信頼性の分かれ目であり、要求仕様の形式化（モデリング言語などの利用）が採用されるのはそのためである。また、プログラマ以外の専門家でない人々にそのソフトウェアの振る舞いを正しく伝達する手段でもある。実際には、プログラマも「どう動作するか」を事前に把握していないことが多く、それが要求仕様に関する議論を困難にしている。

設計

要求仕様がプログラムがすべきことを記述するのに対して、ソフトウェア設計ではプログラムがそれをどのようにすべきかを記述する。設計工程の有用性には異論もあるが、信頼性の観点からはソフトウェア設計工程の重要性が指摘されている。ソフトウェア設計では、ソフトウェアを部品にわけ、それらのすべきことを記述する。そのようにしてプログラムを細分化していき、部品群が全体として正しく機能するようにする。
高レベルな設計の目的は次のようになる。アーキテクチャ上の問題やプログラムの概念や構造に関する問題を実際のデータ処理に関わるコード上の問題と分離する。ソフトウェアコンポーネントを細分化することで個々のコンポーネントの開発に関わるものに制約を与え、結果としてバグを作りこみにくくする。コンポーネント間のインタフェースを定義することで複数のチームがそれぞれ別のコンポーネントを並行して開発できるようにし、各チームがその役割を認識できるようにする。また、実装言語を指定せずにプログラムの機能を記述することで、言語に依存した偏向を排除する。

プログラミング

プログラミング言語の開発史は、プログラムの複雑さを克服する試みの歴史であり、言語の発展がなければプログラムはその規模に対して指数関数的に理解が困難になっていただろう。プログラミング言語はコンピュータにより多くの仕事をさせるべく進化したと言う事もできるが、これは同じことを別の観点で言っているだけである。プログラム全体の構造や機能を見失うと、バグを見逃すことが多くなる。従って、よい言語を使えば理解が容易になり、バグも減らせる。
言語はソフトウェア設計の意図していることをなるべく簡単に記述できるよう進化してきた。文、サブルーチン、ファイル、クラス、テンプレート、ライブラリ、コンポーネントといった概念の導入により、プログラムの記述が抽象化・階層化・モジュール化され、コードの理解が容易になってきた。
さらに言語の進化によってデータの構造や利用に関しても正確な制御が可能となってきた。

テスト

プログラムが要求仕様などの通りに動作するかを判定するのがソフトウェアテストである。単体テストは、プログラムのごく一部（多くの場合1つのサブルーチン毎）を対象に仕様通りに動作することを確認する。結合テストは、より大きなモジュール単位での動作を確認する。

実行時

実行時の信頼性の判定はテストと似ているが、その観点はより単純であり、性能、他のコードとの相互運用性、特定のハードウェア構成で動作可能かといった点で評価される。