🛣️

構造化プログラミングとは

2022/06/21に公開

本記事は、Clean Architectureという書籍の 第四章 構造化プログラミング を読んで自分なりにまとめたものです。プレゼンの台本のような形で記録が残っていたので加筆修正してブログ記事として供養させていただきます。


構造化プログラミング

構造化プログラミングは、gotoを手放すことで機能分割を手に入れる。

構造化プログラミングへの道

構造化プログラミングが生まれた時代は、今のコンピュータと比較して、巨大で壊れやすく、遅く、信頼性が低い、1960年代後半。

そして、ソフトウェア危機が叫ばれ始めた時代でもありました。

ソフトウェア危機とは、ハードの高性能化によって出来ることが増え、したいことも増える。したい事が増えるのでソフトウェアの需要は上がるが、ソフトウェアを作成するコストが増大になり、需要を満たせなくなるというものです。

プログラムが複雑になるにつれて、正しいように見えるプログラムが失敗する。これは、今の現場でも感じることがあると思います。この正しいように見えるというのは、人間の感覚という曖昧なものに頼っているから引き起こされます。

では、どうすればそのプログラムが正しいと言えるのか、学者たちは考えました。

計算機科学者ダイクストラ

ここで登場するのが、計算機科学者ダイクストラです。ダイクストラという名前はどこかで聞いた事がある人はいるのではないでしょうか?

証明をするのが大好きな学問と言えば数学。
ダイクストラは、ソフトウェアの開発に数学の証明を活用するということを思いつきます。
学問として大先輩にあたる数学を、コードに結びつけて証明を可能にする事ができれば、正しいという錯覚に悩まされなくて済むようになります。

分割統治

正しさの証明で大事なことは「分割統治」です。数学で何かを証明するとき、大事なのは証明したい対象を分割する事です。学生の頃経験があると思いますが、証明の回答を記述するときは、上から順に正しい事を並べていき、最終的に証明したいことに繋げます。

この「分割統治」をプログラムに適用したい。しかし、goto文を使うことにより「分割統治」ができない場合があると明らかになります。逆に言えば、goto文を適切に使えば、「分割統治」ができるという事です。

このgoto文の適切な使い方が、選択「if/then/ else」や反復「do/while」といった制御構造に対応します。これらの制御構造のみを使えばプログラムを証明可能な単位まで分割できそうです。

また、当たり前すぎて忘れていましたが、もう一つ大事なものに「順次」がありました。「順次」は処理を順番に実行するというとても単純な構造ですね。

選択・反復・順次

この「選択」「反復」「順次」は以前から特別なものだと知られていました。プログラムが分割統治で証明できそうな可能性が出てくる2年前、ベームとヤコピーニの二人の学者があらゆるプログラムは「順次」「選択」「反復」の3つで特定できるということを特定していたからです。(構造化定理)
https://www.cs.unibo.it/~martini/PP/bohm-jac.pdf

プログラムは、「順次」「選択」「反復」の3つで特定できる
「順次」「選択」「反復」で書いたプログラムは、分割統治が使える。

この2つのの発見によって、「構造化プログラミング」が生まれます。

GOTO文

「GOTO文は有害だと考えられる」
と題された論文が1968年に出版されます。もちろんこの論文を書いたのはダイクストラです。
https://homepages.cwi.nl/~storm/teaching/reader/Dijkstra68.pdf
当時GOTO文は当たり前のように使われていたため、この論文によってプログラミングの世界は炎上します。

今の時代であれば、SNSがあるので幾らでもネガティブな投稿ができますが、当時はそんなものはなかったため、ジャーナル(学術雑誌)に対して非難の投書が行われました。
当初は、その論文を強く支持するものと猛烈に非難するもので対立、議論は論争となり、以後10年間も続いたそうです。

長年の論争の結果ダイクストラの勝利に終わり、現代のほとんどの言語においてgoto文が息を潜めることになりました。

「goto文」論争が終結し始めた1970年代後半から1980年代、構造化についての分析が活発になります。

正しさを数学で証明したい

ここで、最初を振り返りますが、
正しいという錯覚に悩まされないために、数学によってプログラムの正しさを証明したい。」というのが最初のモチベーションでした。

goto文が終わりを迎え、構造化に対する研究が活発になり、最後には正しさが証明される!と思いきや、正式にプログラムの正しさが証明される(ユークリッドの階層が構築される)ことはありませんでした。

ダイクストラのプログラムを数学的に証明するという夢は途絶え、消え去ってしまったのです。

プログラムの正しさ

今日のプログラマーは、その頃に比べてはるかに複雑なプログラムを構築することができています。プログラムを数学的正しいと証明できないにも関わらずです。

なぜでしょうか、もちろん構造化プログラミングの後に続くオブジェクト指向やその他いろんな要因はあると思いますが、シンプルに考えてみましょう。

プログラムの正しさを数学的に証明する。
この世界にあるのは、数学だけではありません。私たちには科学(自然科学)があります。

ということで、科学の力を借りて証明しましょう。

ただ、科学で証明すると言いましたが、これには語弊があります。
実際には、科学の理論や法則は正しいと証明することができません。
また、それが数学との決定的な違いでもありますが、私たちは科学が正しいと信じています。

例えば、運動方程式ma=F
この式が正しいと証明することはできません。
いくら実験をしても、正しそうな結果をいくら重ねても、どうしたって正しくないと証明される可能性が残っています。

ただ、私たちはたくさんの証明されていない式に命を預けています。
それは、科学の世界における正しさは、真ではないということを証明することによって保証されているからです。

数学と科学を比較してみましょう。
数学において、定理を証明する時は、小さな正しいを積み重ねていき、最終的に正しい定理にたどり着きます。
科学において、法則を証明する時は、小さな正しくないをぶつけて、それでもなお残った法則が正しいのです。

偽の証明

科学では真ではないということを証明すると聞いて、プログラミングの世界でも似たようなことを聞いたことがあると思った人がいるかもしれません。

テストです。

ダイクストラは、「テストは、バグの存在を示すことはできるが、存在しないことは示せない」 と述べています。
https://www.cs.utexas.edu/users/EWD/ewd02xx/EWD249.PDF

つまり、テストによって、プログラムが正しいということは証明できないが、正しくないということは証明できる。テストを十分に行って正しくないということが証明できないのであれば、そのプログラムは十分に正しいと言えるのです。

正しい・正しくない・証明できる・証明できないなど少し混乱するとこではありますが、ご理解いただけたでしょうか。
こちらのnoteの記事がより分かりやすかったです。
https://note.com/akiyama924/n/ne92b6ece48a1

プログラミングと科学

プログラムの証明は、科学の証明と似ている。この事実は驚くべきものではないでしょうか?
よく巷ではプログラミングって数学が必要なの?と言われています。
この問いへの回答は様々あると思いますが、世間一般的に、そしておそらくプログラマーの目線でもプログラミングは数学に近いものだと考えられると思います
しかし、このような事実からソフトウェア開発は数学より科学に近いものであると考える事ができるのです。

繰り返しにはなりますが、プログラムはどんだけ頑張っても正しくないことを証明できないことによって、その正しさを証明しているのです。

ただし、これは分割統治が可能なプログラムにおいてです。
一番最初に戻ってください、gotoを制限なしに使ったプログラムでは分割統治ができないという話をしましたね。

まとめ

構造化プログラミングのアイデンティティとは、プログラムを正しくないと証明できる単位にまで分割する事ができるということです。
goto文は分割を不可能にしてしまうため、追放されたのです。

アーキテクチャという大きな枠組みにおいても、機能を分割するというのがベストプラクティスだと考えられている根源がここにあります。

ソフトウェアアーキテクトは、正しくないと証明できない部品の組み合わせによって成り立っているのです。


1年ほど前に書いた資料なので、少し加筆修正して投稿させて頂きました。
Clean Architectureの本題に入る前の内容ですが、私はここに本質的なことがたくさん詰まっているように感じており、非常に好きな章でもあります。
歴史に学ぶとより頭に入ってきやすいことも実感したので、技術の歴史的な背景などにも興味を持って調べていこうかと思います。
ここまで読んでいただきありがとうございました。

Discussion