構造化プログラミング
構造化プログラミングは、コンピュータプログラムの処理手順の明瞭化、平易化、判読性向上を目的にしたプログラミング手法である。一般的には順接、分岐、反復の三種の制御構造(control structures)によって処理の流れを記述することと認識されている。制御構造は制御構文、構造化文(structured statement)、制御フロー文(control flow statement)とも呼ばれる。また、プログラムを任意に分割した部分プログラム(サブルーチンとコードブロック)の階層的な組み合わせによるプログラムの構造化も指している。
このプログラミング手法の普及に貢献したのは、1968年の計算機科学者エドガー・ダイクストラによるACM機関紙への投書「Go To Statement Considered Harmful」と言われている。しかし同じくダイクストラが、1969年度NATOソフトウェア工学会議で発表した論文「Structured Programming」との混同を招いてこちら側の名称で知られるようになった。現在に到るまでの国内外の多くの書籍で、構造化プログラミングは制御構文に関する説明に結び付けられている。なお、1969年の論文内容はプログラム正当性検証のための設計技法を扱っており、トップダウン設計、段階的な抽象化、階層的なモジュール化、抽象データ構造と抽象ステートメントを連携させる共同詳細化といった考え方が提唱されていた。
制御構文(control structures)とは、goto文によるフロー分岐やループ表現を、if文の選択構文やwhile文の反復構文に置き換えるためのプログラム記法を意味している。ラベル先にジャンプするというgoto文の機能を、if文やwhile文は「特定のコード群だけを実行する」という概念に置き換えている。goto文を用いた制御フローは、(1)データの照合/比較の結果にしたがって次の実行コード群を選択するパターンと、(2)データの照合/比較の結果が任意条件を満たしているならば実行コード群を反復するパターンの、二通りに集約されることが経験則で知られていたので、これを専用の記号で形式化したのが制御構文であった。
コード群とは命令コード(instruction code)のまとまりであり、構造化定理では部分プログラム(subprogram)と定義されている。部分プログラムはステートメント(statement)コードブロック(code block)サブルーチン(subroutine)の総称である。ステートメントは命令コードの一行を意味する。コードブロックは一行以上のステートメントをまとめたものである。サブルーチンは一行以上のステートメントまたは一個以上のコードブロックを内包している。部分プログラムは直列状または入れ子状に配置される。その実行順序を決定するものが制御構文であり、以下の三つがある。
順次(sequence)部分プログラムを順々に実行する。
選択(selection)条件式が導出した状態に従い、次に実行する部分プログラムを選択して分岐する。
反復(repetition)条件式が導出した特定の状態の間、部分プログラムを繰り返し実行する。
制御構造の導入は1960年公開の「ALGOL60」まで遡れるが、当時広く使われていたFORTRANやCOBOLでの正式導入は1977年以降だったので、多くの開発現場では馴染みのないものであった。1966年にコラド・ベームらが「順次・選択・反復」のフロー万能性を数学的に証明したが、それはあくまで論理的研究だった。それを参考にしたとされるダイクストラの1968年の投書「goto文は有害」はいわゆるgoto文論争を引き起こしたが、同時に制御構造への関心を大きく高めた。1970年代、goto文が多用される開発現場での制御構造の普及を重視していたIBM社のハーラン・ミルズは、1969年にダイクストラが発表していた論文題名から知名度を得ていた「構造化プログラミング」を自社の技術セミナーマーケティングに活用するために、上述のベームらの数学的証明を「構造化定理」という独自のタイトルで復刻させて、彼らが勧めるフローチャート制御構造の裏付け理論にした。こうして構造化プログラミングは、IBM社が提唱する構造化定理を論拠にした制御構造を用いるプログラミング手法として世間に定着することになった。
制御構造を導入したプログラミング言語を指しての「構造化言語」というワードが浮上したのは1970年代からであり、これは当時のgoto文中心だったFORTRANやCOBOLやBASICを意識してそれと線引きするための用語として存在していた。
上述の制御構文をコーディング視点の下流工程テクニックとすると、構造化設計(structured design)はプログラムデザイン視点の上流工程テクニックであり、こちらも構造化プログラミングと呼ばれるものである。構造化設計では、サブルーチン(subroutine)をまとめたサブルーチン複合体と、データ要素をまとめたデータ構造(data structure)が主要な役割を果たしている。段階的詳細化に則ったサブルーチン複合体の階層的な組み合わせと、それに必要なデータ構造を連携させてプログラム全体を構築するというテクニックが構造化設計である。サブルーチン複合体はプログラムモジュール(program module)とも読み替えられ、モジュール凝集度と結合度もここから生まれている。
1974年頃から当初はIBM社が主導する形で、いずれも構造化(structured)が接頭辞につく数々のテクニックが発表されるようになり、1975年発表「ジャクソンの構造化プログラミング -Jackson structured programming(JSP)-」、1975年発表「構造化設計 -structured design(SD)-」、1978年発表「構造化分析 -structured analysis(SA)-」、1981年発表「構造化分析設計技法 -structured analysis and design technique(SADT)-」、1980年代発表「構造化体系分析設計手法 -structured systems analysis and design method(SSADM)-」、1989年発表「モダン構造化分析 -modern structured analysis-」などが広く普及している。著名な専門家としては、グレンフォード・マイヤーズ、ラリー・コンスタンティン、マイケル・ジャクソン、エドワード・ヨードン、トム・デマルコなどがいる。これらは「構造化開発」と総称されるようになり、1980年代までのソフトウェア開発の主流になった。
この構造化設計と、ダイクストラの構造化プログラミングの違いは、前者がサブルーチン複合体とデータ構造の連携を中心にしたテクニックであるのに対して、後者は専属サブルーチンを通して扱われる抽象データ構造を中心にしたテクニックであるという点である。後者では、段階的に抽象化した各モジュールの階層的な連結と、抽象データ構造と抽象ステートメントを連携させる共同詳細化といった考え方が提示されており、この詳細については後節で述べられる。ダイクストラが提唱した抽象(abstraction)指向の構造化は、その思想の前衛性から1970年代を通して理解を得られることはなく、発案者本来の構造化プログラミングは上流工程視点からも普及することはなかった。
第一幕
構造化プログラミングの誕生は、1960年代から浮上したソフトウェア危機問題と密接に結びついている。ソフトウェア危機とはコンピュータ性能の進化に伴うソフトウェア要求度の高まりが、プログラムサイズの際限無い肥大化と複雑化を招き、近いうちに現実的な期間内でのプログラム開発が不可能になるだろうとする悲観的予測である。実際に1960年代のソフトウェア開発現場では仕様不一致、納期遅れ、予算超過といった事態が頻発していた。当時のプログラムはgoto文を多用するタコ足フローチャートによるものが大半だったので、すぐにスパゲティコード化することが多く、複雑怪奇なジャングルフロー図と化しているものも珍しくなかった。1959年に計算機科学者ハインツ・ツェマネクは、goto文の多用に警鐘を鳴らす論文を発表している。1960年に公開されたプログラミング言語「ALGOL60」は、BEGINとENDで区切られたコードブロックを制御するIF選択文とFOR反復文を初めて提供していた。計算機科学者ニクラウス・ヴィルトはこれらを構造化文(structured statement)と呼んだ。1966年に計算機科学者コラド・ベームとジュゼッペ・ヤコピーニは、あらゆるフローチャートは順次・選択・反復の組み合わせで表現できることの数学的証明をし、これはベームとヤコピーニの証明と呼ばれた。計算機科学者ドナルド・クヌースは、これらの潮流を構造化文の第一幕と定義した。
第二幕
1968年、計算機科学者エドガー・ダイクストラのACM機関紙への投書「Go To Statement Considered Harmful -goto文は有害-」は、その物議を醸す題名でコンピュータプログラミング界隈にいわゆるgoto文論争を巻き起こした。これは構造化文の認知度を高めることに貢献している。これを構造化文の第二幕と定義したクヌースは「第二幕はそのムーブメントの大きさによって、多くの人にとっての第一幕になった」と評した。1968年度開催のNATOソフトウェア工学会議でソフトウェア危機は正式な用語になり、産業界と計算機科学共通の懸案事項になった。翌69年度開催の同会議においてダイクストラは「Structured Programming -構造化プログラミング-」と題した論文を寄稿した。これが「構造化プログラミング」の正式な初出である。その論旨はソフトウェア危機解決策としてのソフトウェア正当性検証技術の確立であり、プログラムを適切に分割し抽象化して良く構造化(well-structured)しておけば、プログラムサイズ拡大に関係なくその正当性を証明できるとしていた。その具体的手法としてはトップダウン設計、段階的な抽象化、階層的なモジュール化、抽象データ構造と抽象ステートメントを連携させる共同詳細化などが挙げられていた。goto文抑制など構造化文に関する事柄は数行に留まっていたが、goto文論争に熱心なプログラマの間ではこの論文を昨年の投書の延長と見る向きも少なからず存在していた。後年のダイクストラは構造化プログラミングという言葉を作った際に二つの失敗をしたと述べている。商標登録しなかった事と、厳密な定義化を避けた事である。
第三幕
1960年代からの構造化文第一幕の潮流は、産業プログラム界隈にも影響を及ぼしており、こちらでは制御構造(control structures)などの名義でフローチャートに導入されていた。産業コンピュータ市場の最大手であるIBM社の上席研究員ハーラン・ミルズは制御構造を重視し、ニューヨーク・タイムズ社のニュースアーカイブシステム構築プロジェクトで大きな成功を収めた。順次・選択・反復の制御構造は、IBM社のプログラミング規範をまとめたImproved Programming Technologies通称「IPT」に採用され、後に同社の技術セミナーなどを通して広く流布されるようになった。1970~71年頃から計算機科学者デビッド・ハレルは、前述のベームとヤコピーニの数学的証明に「Structure theorem -構造化定理-」という全く新しい題名を付けて主に産業ソフトウェア開発界隈で紹介した。ハレルはこの命名が実はハーラン・ミルズの提案であったことを後に明かしている。構造化定理はIPTの合理性を裏付ける根拠として盛んに引用されたので、構造化(Structured)プログラミングと言えばIBM社の発明品だと信じるプログラマたちも続出した。IBM社が1974年頃から発表するようになった所属研究員たちによるプログラム開発方法論の数々にも構造化(Structured)の接頭辞が付けられていたが、それらは抽象化を重視するダイクストラの構造化とは異なり、サブルーチン複合体とデータ構造を適切に連携させるための構造化であった。その違いを指摘して本来のダイクストラ方式を改めて紹介する動きもあったが、抽象化指向のダイクストラ理論は産業界ではむしろ不人気でさえあった。クヌースの言葉を借りれば、構造化文の第三幕はIBM社とハーラン・ミルズがプロモートした制御構造の舞台になり、構造化プログラミングに対する世間一般の認識はこちらの方で定着するようになった。
終幕
後年、ダイクストラは自身が作った構造化プログラミングという言葉に不快感を示して避けるようになった。この言葉を作った時、彼はプログラミングが手工芸から科学へ発展することを期待していた。しかし構造化プログラミングという言葉は実利を求めるために使われるようになった。次のような逸話がある。構造化開発の第一人者エドワード・ヨードンの事務所にセミナー依頼の電話がかかってきた。プロジェクトメンバー全員に構造化プログラミングを1日で叩きこんで欲しいという内容である。それが終わったらプロジェクト期間を半分にするという。その理由は「構造化プログラミングは生産性を2倍にするという話ですから」であった。
「Structured Programming」という言葉を作ったのは計算機科学者エドガー・ダイクストラであり、1969年のNATOソフトウェア工学会議で発表された論文が初出とされている。彼は2001年のノートで自分が作り出した「構造化プログラミング」という用語は結局異なる解釈で持ち去られてしまったと述べている。
ダイクストラが提唱した構造化プログラミングは、プログラム正当性検証技術の確立を原点にして構想された数々のプログラム開発理論の複合体である。遅くとも1967年からその構想は始められていた。1968年のgoto文に依存しないシーケンスの制御、1969年のトップダウン設計、抽象化、モジュール化、共同詳細化から始まり、1972年には抽象データ構造、情報隠蔽、階層的プログラム構造といった考えも取り上げられていた。1972年の共著は、ダイクストラの第一章・構造化プログラミングから始まり、オルヨハン・ダールの第三章・階層的プログラム構造で締め括られている。ダールはオブジェクト指向プログラミング言語の草創Simula67の開発者である。
goto文#goto文論争1968年のACM機関紙への投書「Go To Statement Considered Harmful」は、そのセンセーショナルなタイトルで当時のプログラマの間に大きな論争を巻き起こした。その要約は次の通りである。
プログラマの仕事は正しいプログラムを作り上げた時に終結し、コンピュータにそのプログラム実行が委託されるとプログラマの手を離れて、コンピュータ内の動作形態であるプロセスに作り替えられることになる。
私たち人間の能力は、静的なプログラムの内容を把握するのには向いているが、コンピュータ内で逐一変化していく動的なプロセスの状態を把握することには向いていない。従って私たちは静的なプログラムと動的なプロセスの間にあるギャップを埋めなければならない。
そのためには、動的なプロセスの動態指標(dynamic index)と正確に対応できる静的なプログラムの文体指標(textual index)の表現が必要になる。goto先ラベルはその要求を満たしていない。「if B then A」「if B then A1 else A2」の選択節や「while B repeat A」「repeat A until B」の反復節の方が適している。
gotoとラベルを用いた選択文と反復文の記述では、状態判定とジャンプが個々に並べられるので、これはプログラムの混乱の原因になる。特にラベルの多用は取り除かれるべきであり、それに伴ってgotoの使用数も削減される。
ただし、前述の節(clause、選択節と反節復)使用の徹底であらゆる必要性をまかなえるという訳ではない。goto文の論理冗長性は証明されているが、goto文削減がそのままフロー明瞭化に繋がる保証はないので推奨まではしない。
この投書は、当時のソフトウェア開発現場で横行していたgoto先ラベルの安易な使用に警鐘を鳴らすためのものであったが、添えられた学術的注釈と文芸的比喩の数々が却って読み手の理解を妨げてしまい、冒頭のタイトル印象のみを先走りさせて、goto文論争を発生させることになった。この投書は比較的さり気ないもので、当時のダイクストラが方々の現場で目にしていたラベル多用をたしなめたい所感から書かれていた。ダイクストラが記していた元々の題名はA case against goto statement(goto文への訴え)であり、その時の編集者によって挑戦的なタイトルにすげ替えられていたのが事の真相である。
goto文論争はプログラミング分野の一つの流行として1970年代から80年代までの長きに渡って続いており、多くのプログラマにとっても馴染み深いテーマになっている。goto文と構造化定理の応酬はプログラミング談義の定番でもあった。ダイクストラは後年の著作で自分が提唱した構造化プログラミングの本質の一つは、この投書のテーマであった状態遷移の適切な表現方法と把握手段の確立としている。
1969年度NATOソフトウェア工学会議に寄稿されたこの「Structured Programming」は、プログラム正当性の効率的な検証技術に重点を置き、当時問題視されていたコードサイズの際限なき肥大化によるソフトウェア危機の解決策として従来のボトムアップ設計からトップダウン設計への移行を推奨していた。
論文の前半では、プログラムサイズの肥大化に伴い、各プログラム部品およびそれらを組み合わせた際のプログラムの正当性(program correctness)の立証(demonstration)に必要な労力が指数的に増加して完遂が不可能になるというソフトウェア危機の問題について述べている。ダイクストラはプログラムの正しさに対して証明を与える従来の研究を分析して、証明の手続きを考えずに書かれたプログラムは証明に必要な労力がプログラムのサイズに対して爆発するとし、「与えられたプログラムに対してどうやって証明をするか」ではなく「証明がしやすいプログラムの構造とは何か」についてフォーカスするとした。
後半ではそのための方法について説明している。まず推論しやすい構造として、ステートメントが順に並んだだけのものを挙げている。また、if文1つだけも推論しやすいとしている。しかし、if文がN個並んだ場合、そのままでは2のN乗ステップの推論が必要であるとしている。そこでif文を抽象ステートメントで1つずつ置き換える段階的抽象化(step-wise abstraction)により、Nに比例する推論で正しさを示せるとした。また、そのためには制御のジャンプを制限し、制御構造は順次の他に、選択、反復、および手続き呼び出しに限るべきとしている(なお、順次、選択、反復のいわゆる制御構造(control structures)に触れているのはこの文節だけである)。この例のように詳細なプログラムを抽象化(abstraction)していくのではなく、逆に抽象的なプログラムから始めて詳細化(refinement)していくというやり方を示している。
詳細化の際には共同詳細化(joint-refinement)という考え方が示されている。これは抽象データ構造の詳細化と共にそれを扱う抽象ステートメントを同時に詳細化し、それを1つのプログラムテキストのユニットに分離するというものである。このユニットをダイクストラは真珠(pearl)と呼んだ。また、抽象的な真珠が1段階具体的な真珠に依存し、その真珠がさらに具体的な真珠に依存していったものをネックレスに例えた。そしてネックレスの上部は下部に関わらず正しさを証明することができ、また下部を取り替えることでプログラムのバリエーションを労力をかけずに作れるとした。
1972年の共著「Structured Programming」は計算機科学界の錚々たる三名による三章構成で、第一章はエドガー・ダイクストラの「structured programming」、第二章はアントニー・ホーアの「data structuring」、第三章はオルヨハン・ダールの「hierarchical program structures」となっていた。結びの章の「階層的プログラム構造」を著したダールはSimula67の開発者である。Simula67はオブジェクト指向プログラミングの草分けであり、この章名から継承によるクラス階層構造を重視していたことが伺える。ダイクストラの構造化プログラミングは、制御構文と構造化定理と構造化設計の影に隠れながらも、Simula67をモデルにしたオブジェクト指向プログラミング発展の歴史に組み込まれて受け継がれていったと言える。1983年にC++を開発したビャーネ・ストロヴストルップは「What Is Object-Oriented Programming?」において、オブジェクト指向を抽象データ構造と階層的プログラム構造の発展形として解説し、同時にSimula67の言語仕様を紹介している。
ダイクストラ提唱の構造化プログラミングを支持するドナルド・クヌースは、1974年に自著「Structured Programming with go to Statements」を発表し、その中でgoto-lessの本質に関する補足と解説を加えている。これは当時のgoto文論争に一つの区切りを付けるものであったが、幅広い認知を得るには到らずにgoto文論争は1980年代になっても散発的に繰り広げられた。1970年代後半からマイコンが普及してBASICなどを扱うパーソナルユーザーが増えると、goto命令を使わないのが構造化プログラミングといった見解が取り上げられて再び議論が始まるなど、この論争の影響は後年まで根強く残っている。
ダイクストラは、プログラマは正しいプログラムを作り出すばかりでなく納得のいくやり方で正しさを証明(検証)することも仕事の一つであるという立場を取っていた。プログラムがどんなに巨大化しても良く構造化(well-structured)されていれば、サイズに関係なくその正当性を検証できるというのが彼の信念であった。well-formed formula(論理式)に因んでいるwell-structuredには、数理論理学の証明論をソースコードにも導入する意図が込められていた。1967年のノート「Towards Correct Programs」でダイクストラは、良く構造化するための三つのメンタルツール(mental tool)をこのように示している。
列挙(enumeration): 一人の人間の能力でできる範囲でプログラムの命令の妥当性を一つ一つ確認していく作業
数学的帰納(mathematical induction): while文など計算機特有の多数の繰り返し文についてのみ数学的帰納法を用いて確認する作業
抽象(abstraction): プログラムのブロックなどに名前をつけ、さらに中身を見ないで正しいと仮定することで検証作業を後回しにする操作
プログラムが正しいことを確認するには、それを証明しなければならない。テストはプログラムに対する疑いを全て取り除くには不十分であるという意見が上がった。これについてダイクストラは「テストはバグの存在を示すには有効だが、バグが存在しないことは証明できない」という表現を好んで用いた。構造化プログラミングの支持者らは、プログラムの正しさの重要性と証明の方法や表明(assertion)の使い方について熱心に説いた。理想的にはテストだけに依存せず、プログラムの正しさの証明も与えるべきだと言われている。所与のプログラムの正しさを後付けで証明することは、はじめから証明を意識して作られたプログラムの場合より難しいことが経験的に知られている。ダイクストラは、プログラミングと同時にプログラムの証明を(わずかに証明を先行して)進めることを推奨している。そのようなアプローチでプログラムの正当性の問題にあたれば、複雑な問題であっても知的管理が可能であると述べた。しかし形式的な証明は、時として非人間的な長さの記述になることもダイクストラは認めている。同氏は、プログラムの証明が形式的であることにはこだわらないという意見を明らかにした。
構造化定理1970年代初頭に計算機科学者デビッド・ハレルは、1966年に発表されていたベームとヤコピーニの数学証明に、構造化定理(Structure theorem)という全く新しいタイトルを付けて主に産業ソフトウェア開発界隈で紹介した。ハレルが後に明かしたところによると「構造化定理」という名称は、当時IBM社の上席プログラマーであったハーラン・ミルズの提案だったという。ダイクストラの提唱内容とは全く異なる、制御構造(順次・選択・反復)主体の構造化プログラミングは、IBM社のIPT(Improved Programming Technologies)に採用されており、同社主催の技術セミナーなどを通して当時のプログラマに広く流布されていた。その中で恐らく意図的にダイクストラのそれと名称を似せた「構造化定理」は、彼らが勧める制御構造の合理性を数学的にも証明した根拠として盛んに引用されていた。このような経緯から制御構造の使用と構造化定理は同一視されるようになり、ダイクストラのgoto文有害説から誤解された構造化プログラミングとも同一視されるようになった。goto文論争の中で引き合いに出されていた構造化定理もまた、ベームとヤコピーニから見れば誤解であった。
なお、ベームとヤコピーニの証明は、フローチャートやそれによって表現されるプログラム・関数・チューリングマシンなどの理論的側面に注目している。これは任意の論理回路がNAND素子の組み合わせによって表現できるとか、ラムダ式がSとKの2つのコンビネータによって表現できるとかいった研究に近い。回路設計者が直接NANDを組み合わせて電子回路を設計しないのと同じように、構造化定理は良いプログラムの作成を(少なくとも直接的には)意図していない。ハレルも構造化定理は実際の内容以上に引用されて民間伝承定理(folk theorem)化していると指摘していた。
ダイクストラは2001年のノート「」(構造化プログラミング表記の由来)でこのように述べている。
1968年の自分は「A case against goto statement」(goto文への訴え)と題した記事(article)をCommunications of the ACM(ACMの機関紙)に投稿したが、当期の刊行を急ぐ編集担当者の意向で投書(letter to the Editor)にされる事になり、更にその担当者独自の考えで「The goto statement considered harmful」(goto文は有害)という全く新しい題名を付けられた。その担当者とはニクラウス・ヴィルトであった。また、自分が提唱した構造化プログラミングの本質的内容の普及を好まない某社がハーラン・ミルズの主導で、まるでgoto文を廃止するかのようなプログラミング手法へと矮小化し、構造化プログラミングという用語まで持ち去ってしまった。