公開: 2021年7月23日
更新: 2021年9月7日
利用者が「道具」としてコンピュータを使っている時、利用者の思い通りに「道具」が働かないことがあります。その原因の最期の一つは、「ソフトウェア」に潜んだ「誤り」です。利用者が、要求仕様書をまとめる時に、開発技術者達に伝えようとしたことと、でき上った「道具」の働きに違いがあるとすれば、ソフトウェアの開発を決められた手順通りに進めていたとすれば、そのどこかの作業手順で、間違いが入り込んだことになります。また、ソフトウェアの開発を手順通りに進めていない場合は、そのこと自体が、間違いを生み出す原因になります。
ソフトウェア開発の手順は、「間違いを起こす」人間か集まって、数多くの「コンピュータを動かすプログラム」を作り出すためにどうすれば、最も間違いを減らすことができるのかを、経験に基づいてまとめた「やり方」が基本です。現在までに、いくつかの「やり方」提案されていますが、完全と言える「やり方」は、分かっていません。最も普通のやり方としては、「ウォーターフォール開発」と呼ばれる方法が有名です。この方法では、最初に「何を作るのか」を決め、そして、「それをどう作るのか」を決め、決めた内容に従って「それをプログラムにし」て、最後に、「作成したプログラムが思った通りに動くか」を確認します。
このやり方は、人間が建築物を建てたり、大きな船を作ったり、飛行機を作ったり、自動車を作る時にやっているやり方を、ソフトウェアを作るために応用したものです。それまでに人間が作ってきたものと、ソフトウェアの違いは、ソフトウェアには形がなく、それがどのように働くのかは、「言葉によってしか」説明できない点です。建築物も機械も、形があるため、個々の部品がどのようなものであるのかを、絵にして、図形で示すことができます。ソフトウェアの場合は、それができません。唯一できることは、数学の定理などと同じように、言葉や記号を使って説明することだけです。
言葉や記号だけで説明されるものは、それを考えている人以外の人が、書かれた言葉や記号を読んで理解しようとしても、簡単には理解することができません。この性質が、ソフトウェアを作る時に、間違いが入り込みやすい状況を作り出します。それを書いたAさんと、それを読んでいるBさんの理解が、一致しないことがよく起こるからです。これは、数学の証明に間違いがあっても、なかなか発見されないことと似ています。特に、規模が大きな、何百万行にもなるソフトウェアでは、そのすべてを読んで、理解し、それが正しいことを確認していると、時間がかかり過ぎて、実際には、期限までに作ることができなくなってしまうからです。
すでに説明した様に、コンピュータを動かしているのは、{プログラム」です。そのプログラムを集めたものを、「ソフトウェア」と呼びます。「ソフトウェア」は、どの様な計算をして欲しいのかを書いた、「仕様書」と呼ばれる書き物と、その仕様書に書かれた計算を、どの様にしてコンピュータにやらせれば良いのかを書いた、「設計書」と呼ばれる書き物、そしてその設計書に書かれたコンピュータの動かし方を、コンピュータに対する指示として書いた、「プログラム」の、主として3種類の文書から成っています。このうち、仕様書と設計書は、日本語の様な普通に使われている言葉で書かれます。プログラムは、コンピュータが読めるプログラミング言語と言う特殊な言葉を使って書かれます。仕様書には、特別な専門用語は、あまり使われません。設計書には、プログラムを作成する人ならば理解できる専門用語が使われます。そして、プログラミング言語は、多くの場合、英語を基にして作られた、英語に似た言葉です。
ソフトウェアを作る時、できたプログラムをコンピュータ上で動かして、自分が与えた入力に対して、思い通りの出力を得たいと考えているユーザ(コンピュータを使う人)と、そのプログラムを作成するチームの代表者が集まって、ユーザとプログラムの作成者の両方の人々が理解できる言葉(例えば、日本語など)で、どんな入力に対して、どの様な計算をして、どの装置に、どんな出力を出せば良いのかを決めます。この仕様書は、それほど複雑ではない文書の集まりで、与えられる入力、ユーザが期待している出力、入力から出力を得るための「計算のあらすじ」などが、一つ一つの文章で書かれています。
この仕様書を書く過程で、ユーザが予め、プログラムの作成者達に伝えておくべき事柄を、はっきりと伝えていなかったりすると、ユーザが期待していた計算を、プログラムが行わないと言うことが発生します。また、ユーザが言っていることを、プログラム作成チームの代表者が、正確に理解せずに、文章にまとめてしまうと、ユーザが期待していることと、プログラム作成者が理解することが違ってしまうので、作成されるプログラムは、ユーザが期待する様な計算をせずに、ユーザが期待している出力を、期待している装置から出すことができません。この様な問題の発生を防ぐために、仕様書を作り終わった段階では、ユーザの代表者とプログラム作成チームの代表者が一緒になって、仕様書を最初から最後まで、通して読み合わせます。これによって、どんなプログラムを作れば良いのかを、お互いに確認し合うわけです。
ところが、ユーザの代表者は、仕様書を書く専門家ではないことが多く、書いてある事柄を、自分の都合の良い様に受け取り、後でプログラム作成チームの人が読んで、何が書いてあるのかを理解しようとした時、間違って読まない様に、分かり易い表現で書いておくことに、あまり注意をしません。この様なことが、正しいプログラム、ユーザが期待している様に動くプログラム、の開発を妨げることになる例は、少なくありません。また、ユーザが述べたことをプログラム開発チームの代表者が文章に書き起こすと、プログラム作成者の言葉で仕様を書くことになる例が多く、書かれた文章をユーザが読んだ時、それが自分が言いたかったことなのかどうか、はっきりと言えていない様に感じられることも少なくありません。これをしっかりと確認していないと、ユーザが期待しているプログラムの動作と、プログラム作成者が理解したプログラムの動作が、一致しないことが発生します。
ユーザの代表者と、プログラム作成チームの代表者の両方が合意できた仕様書が出来上がると、プログラム開発チームでは、その仕様書通りに、入力から期待される出力を出すプログラムをどう作れば良いのかを考えます。多くの場合、この作業は、仕様書通りに動作するプログラム全体を、どの様な小さなプログラムの集まりとして、作り上げるべきかを考えます。これは、どの様な計算をする部品の組み合わせで、仕様書に書かれている一つ一つの動作(機能)を実現するのが最も、楽な方法になるのかを考える問題になります。部品への分解がうまく行かないと、全体が複雑に絡み合うので、うまく動かない例が生じやすくなります。また、新しい問題が生じた時に、それに対処するために、新しい部品を追加したり、新しい組み合わせで仕事を行うプログラムを足したりすることが必要になるので、それがし難いプログラムになったりもします。
このプログラムを構成するために、プログラム全体をどの様な部品に分解するのかを決める仕事は、大変難しい仕事で、経験の豊富な技術者にしかできません。普通は、トップダウンと言って、大まかなプログラムを決めて、それから徐々に、少しずつ細かな部品に分けて行く方法が使われます。 この方法は、船や飛行機、自動車などを作る時に使われている方法を「まねた」もので、作ることが難しいプログラムを数多くの人々が協力して作るのに適した方法と言われています。ただ、船や飛行機、自動車などでは、細かな部品は、すでにできているものを使うので、その意味では、問題は少し簡単です。プログラムの場合、ほとんど全ての部品を毎回、作り上げなければならないことが多いため、トップダウンにやっても、簡単には行きません。ソフトウェアの問題の多くが、この段階で入り込むと言われています。
さらに、最近のコンピュータでは、回路の高速化が行われているので、膨大な量の計算を短時間で行うことができます。それでも、コンピュータの利用者から与えられる入力情報の量が急激に増大しているので、コンピュータは計算時間を短くしなければなりません。そのために、プログラムを考える人々は、コンピュータが計算をしている時間と、人間からの入力を待っている時間、計算結果を人間が理解できる文字や、画像にして表示するまでに、印刷装置や表示装置が処理を行う時間を測りました。そして、コンピュータが計算をしている時間が、全体のごく一部であることを突き止めました。
この事実を基に、仕様書からプログラムを考える人々は、人間からの情報の入力を待つ時間や、人間のために出力情報を出力し終わるまでに待つ時間の間、コンピュータを別のプログラムの実行のために使うことを考えました。つまり、あるプログラムが、人間からの情報の入力を待つ動作に入った時、そのプログラムのための動作を中断して、別のプログラムを動かすためにコンピュータを使えば、コンピュータを有効に使えるからです。これは、家庭の台所で、料理をしている人が、鍋で煮物を作りながら、電子レンジで食材を温めたり、電気釜でご飯を炊いたり、空いているコンロにヤカンをかけてお湯を沸かすことなどを、一人で一度にやっているのと同じです。料理をしている人を、コンピュータの様に考えれば良いわけです。
煮物の途中で、電子レンジが食材の温めが終わったことを知らせるために、「チン」と言う音を出して、それを知らせます。その音を聞いた人は、 電子レンジに行って、温まった食材を取り出し、煮物を作っているお鍋の中に入れ、料理を続けたりします。この様に、電子レンジなどを利用して、短い時間で、数多くの料理を完成させることができます。この料理の例と同じ様に、コンピュータが行わなければならない計算と、入力処理や出力処理で生まれるコンピュータの待ち時間をうまく組み合わせることで、全体として一定時間内に終わらせることができる処理の量を増やすことができます。つまり、コンピュータを有効に使うことができる様になるわけです。
この様に、同時に複数のプログラムを動かして効率よく、コンピュータを利用することを、「並行処理」と呼びます。その様な並行処理ができる様にするためには、個々のプログラムにも、特別な仕掛けがされていなければなりません。例えば、一つ一つのプログラムは、どの計算の途中でも、別のプログラムの計算に移り、それが終わった時点で、もう一度、計算を再開できる様にしておかなければなりません。さらに、特別な計算をしている間は、他のプログラムの計算に移れない場合もあります。それは、電子レンジでの食材が終わっても、煮物の法の準備が終わっていないため、すぐには温め終わった食材を煮物に入れることができない状態にあるのと、似ています。
この様な問題を解決するために、仕様書からプログラムの作り方を考える人々は、どのプログラムとどのプログラムが同時に動くかも知れないかを考えます。そして、その様なプログラムが見つかると、プログラム全体を並列処理させない様にすべきか、それてもプログラムの一部分だけを並行処理させない様にすべきかを決めます。プログラム全体を並行処理させない様にするためには、そのプログラムが動き始めるときに、そのプログラムは他のプログラムとは並行処理できないことを宣言するための命令を書き、そのプログラムの計算が終わったときに、その並行処理禁止の宣言を解除します。この禁止解除をせずにプログラムを終了させると、それ以後、コンピュータでは、全く並行処理が行われなくなるため、全体の処理が著しく遅くなります。
また、プログラムのある部分だけを並行処理させない様にするためには、並行処理を禁止する部分に計算が到達したとき、並行処理の禁止を宣言します。そして、並行処理を禁止しなければならない部分の計算が終わったところで、並行処理禁止の宣言を解除します。この場合も、解除の宣言を忘れてはいけません。並行処理を禁止する部分が短ければ短いほど、コンピュータの効率は良くなり。全体として処理の効率が良くなります。例えば、同じプログラムを同時に動く様にして、たくさんの利用者からの入力を効率よく処理しようとするとき、どのプログラムで受け取った入力が何番目の入力かを決めようとするとき、その入力順を決める部分は、並行処理させずに、順番を一つずつ決めてゆかなければなりません。そのため、順番を決める計算の前で、並行処理の禁止を宣言し、順番を決める計算が終わったところで、順番の値を記憶させて、並行処理の禁止解除を宣言します。そうしないと、順番がバラバラになって、途中まで計算が進んでいたのに、後から入力されたデータの処理が、途中から始まってしまいます。
仕様書に基づいて、プログラムをどう作るべきかを決めると、実際にその「設計」に従って、プログラムの作成を始められます。この仕事は、仕様書に基づいて決められたプログラムの骨格に基づいて、細かな計算をプログラミング言語で書く仕事です。ここでは、計算に使う変数を決めて、それを記憶装置の特定の場所に割り当てます。次に、個々の計算で、どの記憶装置にしまわれている変数の値を使って、どの様な計算を行い、その結果をどの変数にしまうかを決めます。また、その計算は、どの変数の値がどの様な値であるときに行う計算であるのかを決めます。さらに、その計算結果がどの様な値の時、次にどの様な計算を行うべきかも決めます。この様な変数にしまわれている値を調べて、どんな計算をするのかの指定を誤ると、プログラムの計算は、仕様書に書かれているものとは違ってしまいます。この様な間違いは、プログラムを作成する作業で、頻繁に発生します。
計算結果をある変数にしまう時、その変数の名前を間違って指定すると、それが直接、コンピュータの利用者に出力される場合には、分かりますが、そうでない場合には、利用者は気づかないでしょう。別の利用者が同じプログラムを使った時、初めて、誤りがあることに気付きます。これは、発見が難しい誤りの一つで、注意して出力を検討していないと、見逃されてしまう誤りです。例えば、文書の編集を行うプログラムで、編集が終わった後、作成した文書をファイルにしまう部分に、その様な誤りがあると、利用者が作成した文書を、次に読み出そうとする時、正しい文書を読み出せないと言う問題が起こります。問題が単純で、いつも読み出せなければ、その問題はすぐに見つかるでしょう。しかし、偶数回目の編集処理でこの誤りが起きる様になっていると、2回目の編集をやってみなければ、その誤りを見つけることはできません。
ソフトウェアを開発するときには、その様な問題がソフトウェアに残らないように、多くの人々が参加して、ソフトウェアを動かし、「問題が残っていないか」を確認します。この確認作業は、そのような誤りがソフトウェアに残ることを避けるために実施します。しかし、上で説明したような、並列処理を禁止するような宣言の部分などに間違いが残っている場合、実際に並行処理が起きる条件を作り出すことができなければ、その問題の存在を知ることはできません。長いプログラムのほんの一部分にある並列処理禁止部分が、2つ以上の同時並行動作で、まさにその部分を動かすことができなければ、その問題を発見することはできません。このような理由から、プログラム作成が終わった後での動作の確認作業では、そのような問題を発見することは、簡単ではありません。
つまり、ソフトウェアの開発で、プログラム作成後に行われる、プログラムの動作確認作業では、プログラムに残っている全ての誤りを発見し、その誤りを見つけて、完全に取り除くことは不可能としか言えません。比較的に動作が単純なコンピュータの開発でも、このソフトウェアの誤りのように、発見が難しく、コンピュータが完成しているにもかかわらず、利用者がコンピュータを利用している時に、問題に気付く例は少なくありません。ソフトウェアの場合は、プログラムに残っている誤りの発見と、その除去は、もっと難しいのです。それは、コンピュータに比べて、コンピュータ上で動作するプログラムは、多様性が高く、同じ計算手順の繰り返しが少なくなるからです。