
ジャクソン構造化プログラミング(JSP )は、英国のソフトウェアコンサルタントであるマイケル・A・ジャクソンによって開発された構造化プログラミングの手法です。これは、彼の1975年の著書『プログラム設計の原理』で説明されています。[ 1 ] JSPの手法は、プログラムが入力として読み込み、出力として生成する必要のあるファイルのデータ構造を分析し、それらのデータ構造に基づいてプログラム設計を作成することで、プログラム制御構造がそれらのデータ構造を自然で直感的な方法で処理できるようにすることです。
JSPは、シーケンス、反復、選択(または代替)という3つの基本構造を用いて、データとプログラムの両方の構造を記述します。これらの構造は、正規表現の視覚的な表現として図式化されます。
マイケル・A・ジャクソンは、 1970年代にJSPを最初に開発しました。彼は1975年の著書『Principles of Program Design』でこのシステムを文書化しました。[ 1 ] 2001年の会議での講演で、[ 2 ]彼はこの方法の背後にある当初の原動力を回顧的に分析し、それをその後のソフトウェアエンジニアリングの発展と関連付けました。ジャクソンの目的は、COBOLバッチファイル処理プログラムの変更と保守を容易にすることでしたが、この方法は、シーケンス、反復、選択(「if/then/else」)などの構造化された制御構造を持つあらゆるプログラミング言語のプログラムを設計するために使用できます。
Jackson Structured Programming はWarnier/Orr 構造化プログラミング[ 3 ] [ 4 ]と似ていましたが、JSP は入力データ構造と出力データ構造の両方を考慮したのに対し、Warnier/Orr 法は出力ストリームの構造にほぼ専ら焦点を当てていました。
JSP が開発された当時、ほとんどのプログラムはテープに格納された順次ファイルを処理するバッチ COBOL プログラムでした。典型的なプログラムは入力ファイルをレコードのシーケンスとして読み込むため、すべてのプログラムが同じ構造、つまりファイル内のすべてのレコードを 1 つずつ処理する単一のメイン ループを持っていました。Jackson は、このプログラム構造はほとんどの場合間違っていると主張し、プログラマーにもっと複雑なデータ構造を探すよう促しました。プログラム設計の原則[ 1 ]の第 3 章で、Jackson は、JSP を使用して設計されたプログラムと、従来の単一ループ構造を使用したプログラムの 2 つのバージョンを紹介しています。以下は、COBOL から Java に翻訳された彼の例です。これら 2 つのプログラムの目的は、ソートされたファイル内の繰り返しレコード (行) のグループを認識し、各レコードとそれがファイル内で出現する回数をリストした出力ファイルを生成することです。
以下は、従来型の単一ループバージョンのプログラムです。
String line = null ; int count = 0 ; String firstLineOfGroup = null ;// 単一のメインループを開始while (( line = in . readLine ()) != null ) { if ( firstLineOfGroup == null || ! line . equals ( firstLineOfGroup )) { if ( firstLineOfGroup != null ) { System . out . printf ( "%s %d%n" , firstLineOfGroup , count ); } count = 0 ; firstLineOfGroup = line ; } count ++ ; } if ( firstLineOfGroup != null ) { System . out . printf ( "%s %d%n" , firstLineOfGroup , count ); }以下は、同じプログラムをJSP形式で記述したものです。従来のプログラムとは異なり、このプログラムには2つのループがあり、1つがもう1つのループの中にネストされています。外側のループは繰り返し出現するレコードのグループを処理し、内側のループはグループ内の個々のレコードを処理します。
int numberOfLinesInGroup = 0 ;String line = in.readLine (); // 外側のループを開始: 1 グループを処理while ( line ! = null ) { numberOfLinesInGroup = 0 ; String firstLineOfGroup = line ;// 内部ループ開始: グループ内のレコードを 1 つ処理しますwhile ( line != null && line . equals ( firstLineOfGroup )) { numberOfLinesInGroup ++ ; line = in . readLine (); } System . out . printf ( "%s %d%n" , firstLineOfGroup , numberOfLinesInGroup ); }ジャクソンは、従来の単一ループ方式が入力ファイルの構造(繰り返しレコードを含むグループのシーケンス)を自然な方法で処理できていないことを批判している。その不自然な設計を示す一例として、正しく動作させるためには、ファイルの最初と最後のレコードを処理するための特別なコードを含める必要があることが挙げられる。
JSPは、半形式的な手順を用いて、プログラムの入力と出力の既存の構造をプログラム自体の構造に取り込む。
その目的は、ライフサイクルを通じて容易に修正できるプログラムを作成することにある。ジャクソンの重要な洞察は、要件の変更は通常、既存の構造に対する微調整であるという点だった。JSPを使用して構築されたプログラムでは、入力、出力、およびプログラムの内部構造がすべて一致するため、入力と出力の小さな変更は、プログラムへの小さな変更に反映されるはずである。
JSPはプログラムを4つのコンポーネントタイプで構成します。
この手法は、まずプログラムの入力を4つの基本的な構成要素タイプで記述することから始まります。次に、プログラムの出力を同様の方法で記述します。各入力と出力は、個別のデータ構造図(DSD)としてモデル化されます。デジタル信号処理(DSP)などの計算負荷の高いアプリケーションでJSPを使用するには、入力と出力ではなく内部データ構造に焦点を当てたアルゴリズム構造図を作成する必要もあります。
入力構造と出力構造は、プログラム構造図(PSD)と呼ばれる最終的なプログラム構造に統合または統合されます。このステップでは、入力と出力を整合させるために、少量の高レベル制御構造を追加する場合があります。プログラムによっては、出力を行う前にすべての入力を処理するものもあれば、1つのレコードを読み込み、1つのレコードを書き込み、それを繰り返すものもあります。このようなアプローチは、PSDに反映させる必要があります。
言語に依存しないPSDは、プログラミング言語で実装されます。JSPは制御構造レベルでのプログラミングを目的としているため、実装される設計では、基本的な操作、シーケンス、反復、選択のみが使用されます。JSPはクラスやオブジェクトレベルでプログラムを構造化するために使用されるものではありませんが、クラスのメソッド内の制御フローを構造化するのに役立ちます。
JSPは、入力、出力、およびプログラムの構造を記述するために図式表記法を使用し、各基本コンポーネントタイプに対応する図式要素を使用します。
簡単な演算は四角形で表されます。
手術一連の操作は、線で結ばれた四角形で表されます。以下の例では、Aは操作B、C、Dからなる一連の操作です。
シーケンス反復処理は、連結されたボックスで表されます。さらに、反復処理される操作のボックスの右上隅には星印が付いています。以下の例では、Aは操作Bを0回以上呼び出す反復処理を表しています。
反復選択はシーケンスに似ていますが、各オプション操作の右上隅に円が描かれています。この例では、Aは操作B、C、Dのうち1つだけを選択したものです。
選りすぐり上記の図では、要素Aがシーケンスまたは反復であり、要素B、C、D(上記の図ではすべて基本要素)ではないことに注意してください。ジャクソンは、要素が何であるかを判断するための「下方参照ルール」を示しています。つまり、要素の下にある要素を見て、それが何であるかを調べます。
例として、JSP プログラマがランレングスエンコーダを設計およびコーディングする方法を以下に示します。ランレングスエンコーダは、入力として、同じ値のバイトが 1 つ以上連続する「ラン」として捉えられるバイトストリームを受け取るプログラムです。プログラムの出力はバイト ペアのストリームであり、各バイト ペアはランの圧縮された記述です。各ペアでは、最初のバイトはラン内の繰り返しバイトの値であり、2 番目のバイトはその値がラン内で繰り返された回数を示す数値です。たとえば、入力ストリーム ("AAAAAAAA") で文字 "A" が 8 回連続する場合、出力ストリームではバイト ペアとして "A8" が生成されます。ランレングスエンコーダは、ビットマップを大まかに圧縮するためによく使用されます。
JSPでは、まずプログラムの入力ストリームのデータ構造を記述する必要があります。このプログラムには入力ストリームが1つだけあり、それは同じバイト値が0回以上連続して出現するものです。以下に、入力ストリームのJSPデータ構造図を示します。

2番目のステップは、出力データ構造を記述することです。この場合、出力データ構造は、0回以上のバイトペアの反復で構成されます。

次のステップは、入力構造と出力構造の構成要素間の対応関係を記述することです。

次のステップは、2つのデータ構造間の対応関係を利用して、入力データ構造を処理し、出力データ構造を生成できるプログラム構造を作成することです。(ただし、これが不可能な場合もあります。下記の構造の衝突に関する説明を参照してください。)

プログラム構造が完成したら、プログラマーはプログラムが実行しなければならない計算操作のリストを作成し、それらの操作を適切な構造要素に紐付けることで、プログラム構造図を具体化していく。
また、この段階では、反復(ループ)や選択(if-then-else文やcase文)に関する条件がリストアップされ、プログラム構造図に追加されます。
図が完成したら、使用するプログラミング言語に翻訳できます。以下はC言語への翻訳例です。
#include <stdio.h> #include <stdlib.h>int main ( int argc , char * argv []) { char first_byte ; int count = 0 ;char c = getchar (); // 最初のバイトを取得while ( c != EOF ) { // 実行中の最初のバイトを処理first_byte = c ; count = 1 ; c = getchar (); // 次のバイトを取得// 実行中の後続バイトを処理するwhile ( c != EOF && c == first_byte && count < 255 ) { // 同じ値のバイトを 1 つ処理するcount ++ ; c = getchar (); // 次のバイトを取得する}putchar ( first_byte ); putchar ( count ); } return EXIT_SUCCESS ; }ジャクソンは『プログラム設計の原理』の中で、特定の種類の設計上の問題を引き起こす状況を認識し、それらに対処するための手法を提供した。
こうした状況の一つに、プログラムが入力ファイルを一つではなく二つ処理する場合がある。1975年当時、標準的な「厄介な問題」の一つは、トランザクション処理プログラムをどのように設計するかであった。このようなプログラムでは、更新レコードのシーケンシャルファイルがシーケンシャルマスターファイルに対して実行され、更新されたマスターファイルが出力として生成される。(例えば、銀行は夜間にバッチプログラムを実行し、その日に行われた預金と引き出しの記録に基づいて顧客の口座残高を更新する。) 『プログラム設計の原理』は、この問題に対する標準的な解決策と、その設計の背後にある論理の説明を提供した。
もう一つの問題は、ジャクソンが「認識困難」と呼んだもので、今日では構文解析問題と呼ばれるものです。基本的なJSP設計手法にPOSITおよびQUIT操作を追加することで、現在でいうバックトラッキング構文解析器の設計が可能になりました。
JSPは、「構造の衝突」と呼ばれる3つの状況(境界の衝突、順序の衝突、インターリーブの衝突)を認識し、それらに対処するための手法を提供しました。構造の衝突が発生する状況では、入力データ構造と出力データ構造の互換性が著しく低いため、入力ファイルから出力ファイルを作成することができません。事実上、2つのプログラムを作成する必要があります。1つ目のプログラムは入力ストリームを処理し、それをより小さなチャンクに分割して、それらのチャンクを中間ファイルに書き込みます。2つ目のプログラムは中間ファイルを読み込み、目的の出力を生成します。
JSPはオブジェクト指向技術が利用可能になるずっと前に開発されました。JSPとその後継メソッドであるJSDは、現在「オブジェクト」と呼ばれるものを多かれ少なかれ独立したメソッドの集合として扱いません。代わりに、CAR Hoareの研究に従って、JSPとJSDはソフトウェアオブジェクトをコルーチンとして記述します。[ 5 ] [ 6 ]
{{citation}}: CS1 maint: location (リンク) CS1 maint: location 発行元が見つかりません (リンク)