コンピュータプログラミングにおいて、フローベースプログラミング(FBP)は、アプリケーションをブラックボックスプロセスのネットワークとして定義するプログラミングパラダイムです。これらのプロセスは、メッセージパッシングによって事前に定義された接続を介してデータを交換します。接続はプロセス外部で指定されます。これらのブラックボックスプロセスは、内部を変更することなく、さまざまなアプリケーションを形成するために無限に再接続できます。したがって、FBPは本質的にコンポーネント指向です。
FBPは、バッファの制限、有効期間が定義された情報パケット、名前付きポート、および接続の個別定義に基づいた、データフロープログラミングの特殊な形式です。
フローベースプログラミングは、「データファクトリー」というメタファーを用いてアプリケーションを定義します。アプリケーションを、ある時点から開始し、完了するまで一度に1つの処理を実行する単一のシーケンシャルプロセスとしてではなく、 「情報パケット」(IP)と呼ばれる構造化データチャンクのストリームを介して通信する非同期プロセスのネットワークとして捉えます。この考え方では、アプリケーションデータと、目的の出力を生成するためにデータに適用される変換に焦点が当てられます。ネットワークは、プロセスとは別に、接続のリストとして定義され、通常は「スケジューラ」と呼ばれるソフトウェアによって解釈されます。
プロセスは、固定容量の接続を介して通信します。接続は、プロセス コードとネットワーク定義の間で合意された名前を持つポートを介してプロセスに接続されます。複数のプロセスが同じコードを実行できます。任意の時点で、特定の IP アドレスは単一のプロセスによって「所有」されるか、2 つのプロセス間で転送されているかのいずれかになります。ポートは、単純なものと配列型のものがあり、例えば、後述する Collate コンポーネントの入力ポートで使用されています。ポートと非同期プロセスの組み合わせにより、ソート、マージ、要約など、多くの長時間実行されるデータ処理の基本機能をソフトウェアブラック ボックスの形でサポートできます。
FBPプロセスは、処理するデータと出力先がある限り実行を継続できるため、FBPアプリケーションは一般的に従来のプログラムよりも実行時間が短く、特別なプログラミングを必要とせずにマシン上のすべてのプロセッサを最適に活用できます。[ 1 ]
ネットワーク定義は通常図式で表され、より低レベルの言語または表記法で接続リストに変換されます。FBPはこのレベルではビジュアルプログラミング言語であることが多いです。より複雑なネットワーク定義は階層構造を持ち、「スティッキー」接続を持つサブネットから構築されます。他の多くのフローベース言語/ランタイムは、より伝統的なプログラミング言語をベースに構築されており、最も有名な例は、フローグラフを指定するためにC++のiostreamライクな演算子を使用するRaftLibです。
FBPは、 GelernterとCarrieroの用語で言うところの「調整言語」[ 3 ]であるという点で、 Linda [ 2 ]言語と多くの共通点があります。つまり、本質的に言語に依存しない言語です。実際、十分に低レベルの言語で書かれたスケジューラがあれば、異なる言語で書かれたコンポーネントを単一のネットワークにリンクできます。したがって、FBPはドメイン固有言語または「ミニ言語」の概念に適しています。
FBPは「データ結合」を示しており、これは結合に関する記事でコンポーネント間の最も緩やかな結合タイプとして説明されています。緩やかな結合の概念はサービス指向アーキテクチャの概念と関連しており、FBPはそのようなアーキテクチャの多くの基準を満たしていますが、このアーキテクチャのほとんどの例よりもきめ細かいレベルでの適合性となっています。
FBPは、システム動作に関する推論を簡素化する、高レベルで機能的な仕様記述スタイルを推進します。その一例として、分散型マルチパーティプロトコルの意味論を構成的に記述・分析するための分散データフローモデルが挙げられます。
フローベースプログラミングは、1970年代初頭にJ.ポール・モリソンによって考案され、当初はカナダの銀行向けソフトウェアに実装されました。 [ 4 ] FBPは当初、当時のIBMのシミュレーション言語、特にGPSSの影響を強く受けていましたが、そのルーツはコンウェイがコルーチンと呼んだものに関する画期的な論文にまで遡ります。[ 5 ]
FBP は長年にわたり何度か名称変更されてきました。最初の実装は AMPS (Advanced Modular Processing System) と呼ばれていました。カナダの大規模アプリケーションは 1975 年に稼働を開始し、2013 年現在、ほぼ 40 年間毎日継続的に運用されています。IBM は FBP の背後にあるアイデアが「自然法則に似すぎている」ため特許を取得できないと考え、代わりに 1971年に技術開示速報「データ応答型モジュール式インターリーブ タスク プログラミング システム」[ 6 ]を通じて FBP の基本概念をパブリック ドメインに公開しました。 [ 4 ]その概念と使用経験を説明する記事は、1978 年にIBM Research IBM Systems Journal に DSLM という名前で掲載されました。[ 7 ] 2 番目の実装は、IBM Canada と IBM Japan の共同プロジェクトとして「データ フロー開発マネージャ」(DFDM) という名前で行われ、1980 年代後半に日本で「データ フロー プログラミングマネージャ」という名前で短期間販売されました。
IBM社内では一般的にこれらの概念を「データフロー」と呼んでいたが、この用語はあまりにも一般的すぎると感じられ、最終的に「フローベースプログラミング」という名称が採用された。
1980年代初頭から1993年にかけて、J.ポール・モリソンとIBMのアーキテクトであるウェイン・スティーブンスはFBPの背後にある概念を洗練させ、普及させた。スティーブンスはFBPの概念を説明し支持する記事をいくつか書き、彼の著書のいくつかにもFBPに関する資料を含めた。[ 8 ] [ 9 ] [ 10 ]。1994年、モリソンはFBPを説明し、FBPが開発時間の短縮につながるという実証的証拠を提供する本を出版した。[ 11 ]
以下の図は、FBP図の主要な構成要素(情報パケットを除く)を示しています。このような図は、接続リストに直接変換することができ、適切なエンジン(ソフトウェアまたはハードウェア)によって実行できます。

A、B、Cはコードコンポーネントを実行するプロセスです。O1、O2、および2つのINは、接続MとNをそれぞれのプロセスに接続するポートです。プロセスBとCが同じコードを実行することが許可されているため、各プロセスは独自の作業用ストレージ、制御ブロックなどを持つ必要があります。コードを共有するかどうかにかかわらず、BとCは同じポート名を使用できます。ポート名は、それらを参照するコンポーネント内(およびもちろんネットワークレベル)でのみ意味を持つためです。
MとNは、しばしば「境界付きバッファ」と呼ばれ、任意の時点で保持できるIPの数に関して固定容量を持っています。
ポートという概念によって、ネットワーク内の複数の場所で同じコンポーネントを使用できるようになります。初期情報パケット(IIP)と呼ばれるパラメータ設定機能と組み合わせることで、ポートはFBPにコンポーネントの再利用機能を提供し、FBPをコンポーネントベースのアーキテクチャにしています。このように、FBPはIBMリサーチのラウル・デ・カンポ氏とネイト・エドワーズ氏が「構成可能なモジュール性」と呼んだものを実現しています。
情報パケットまたはIPは、「IP空間」と呼ばれるものに割り当てられ(リンダのタプルが「タプル空間」に割り当てられるのと同様)、破棄されてその空間が解放されるまで明確に定義された寿命を持ちます。FBPでは、これは所有プロセスによる明示的なアクションでなければなりません。特定の接続を介して移動するIP(実際には移動するのはその「ハンドル」です)は「ストリーム」を構成し、これは非同期的に生成および消費されます。したがって、この概念は、フリードマンとワイズによる1976年の論文で説明されている遅延コンの概念と類似しています。 [ 12 ]
IPは通常、構造化されたデータの塊ですが、中には実際のデータを含まず、単なる信号として使用されるIPもあります。その一例として「ブラケットIP」があり、これを使用してデータIPを「サブストリーム」と呼ばれるストリーム内の連続したパターンにグループ化できます。サブストリームはさらにネストすることも可能です。また、IPを連結して「IPツリー」を形成することもでき、IPツリーは単一のオブジェクトとしてネットワーク内を伝送されます。
上述の接続とプロセスのシステムは、任意の規模に「分岐」させることができます。アプリケーションの開発中に、プロセス間に監視プロセスを追加したり、プロセスをサブネットに「展開」したり、プロセスのシミュレーションを実際のプロセスロジックに置き換えたりすることができます。したがって、FBPは迅速なプロトタイピングに適しています。
これはまさにデータ処理の組み立てラインをイメージしたものです。プロセスネットワークを流れるIPは、組み立てラインでステーションからステーションへと移動するウィジェットと考えることができます。「マシン」は簡単に再接続したり、修理のためにオフラインにしたり、交換したりできます。不思議なことに、このイメージは、コンピュータが登場する以前にデータ処理に使用されていたユニットレコード装置のイメージと非常によく似ています。ただし、当時はカードの束を手でマシンからマシンへと運ばなければなりませんでした。
FBPの実装は非プリエンプティブまたはプリエンプティブのいずれかになります。初期の実装は非プリエンプティブ(メインフレームおよびC言語)である傾向がありましたが、最新のJava実装(下記参照)はJavaスレッドクラスを使用しており、プリエンプティブです。
FBP コンポーネントはしばしば相補的なペアを形成します。この例では、そのようなペアを 2 つ使用します。説明されている問題は言葉で説明すると非常に単純に見えますが、実際には従来の手続き型ロジックを使用して達成するのは驚くほど困難です。ピーター・ナウアーによって最初に説明された「電報問題」と呼ばれるタスクは、テキスト行を受け取り、各行の文字数が一定の長さを超えない範囲で、できるだけ多くの単語を含む出力行を生成するプログラムを作成することです。単語は分割できず、どの単語も出力行のサイズより長くないと仮定します。これは、テキストエディタのワードラップ問題に類似しています。[ 13 ]
従来の論理では、プログラマは入力構造も出力構造も制御フローの呼び出し階層を駆動するために使用できないことにすぐに気づく。一方、FBPでは、問題記述自体が解決策を示唆している。
FBPにおける最も自然な解決策は以下のとおりです(FBPには唯一の「正しい」解決策はありませんが、これは自然な解決策のように思えます)。

ここで、DCとRCはそれぞれ「分解」と「再構成」を表します。
前述のとおり、初期情報パケット(IIP)は、出力レコードの希望長(右端の2つのコンポーネントで必要)やファイル名などのパラメータ情報を指定するために使用できます。IIPは、ネットワーク定義内のポートに関連付けられたデータチャンクであり、該当するポートに対して「受信」が発行されると「通常の」IPになります。
この種のプログラムでは、「詳細」(変更、追加、削除)のファイルを「マスターファイル」と照合し、(少なくとも)更新されたマスターファイルと1つ以上のレポートを生成します。更新プログラムは、同期的な手続き型コードを使用してコーディングするのが一般的に非常に困難です。これは、対応する詳細がないマスターファイルが存在する場合や、その逆の場合でも、2つ(場合によってはそれ以上)の入力ストリームを同期させる必要があるためです。

FBPでは、Collatorの単位レコードの概念に基づいた再利用可能なコンポーネント(Collate)により、この種のアプリケーションの作成がはるかに容易になります。Collateは2つのストリームをマージし、グループ化レベルを示すためにブラケットIPを挿入するため、下流のロジックが大幅に簡素化されます。たとえば、1つのストリーム(この場合は「masters」)がキー値が1、2、3のIPで構成され、2番目のストリームIP(「details」)のキー値が11、12、21、31、32、33、41で、最初の桁がマスターキー値に対応するとします。ブラケット文字を使用して「ブラケット」IPを表すと、照合された出力ストリームは次のようになります。
( m1 d11 d12 ) ( m2 d21 ) ( m3 d31 d32 d33 ) (d41)
値が4のマスターが存在しなかったため、最後のグループは単一の詳細(括弧付き)で構成されます。
上記のストリームの構造は、次のようなBNFライクな表記法を用いて簡潔に記述できます。
{ ( [m] d* ) }*Collateは再利用可能なブラックボックスであり、入力IP内の制御フィールドの位置を知るだけで済みます(ただし、制御フィールドを標準的な位置に配置するために、上流にトランスフォーマープロセスを挿入できるため、厳密にはこれも必須ではありません)。実際、任意の数の入力ストリームと任意の深さの括弧ネストに対応できます。Collateは入力に配列型ポートを使用するため、入力ストリームの数を可変にすることができます。
フローベースのプログラミングは、プロセス多重化を非常に自然な形でサポートします。コンポーネントは読み取り専用であるため、特定のコンポーネントのインスタンス(「プロセス」)をいくつでも非同期的に実行できます。

コンピュータが通常単一のプロセッサしか搭載していなかった時代には、大量の入出力処理が発生する場合にこの方式が役立ちました。現在では、コンピュータが通常複数のプロセッサを搭載しているため、CPU負荷の高い処理が発生する場合にもこの方式が役立つようになってきています。このセクションの図は、単一の「ロードバランサー」プロセスが、それぞれS1、S2、S3とラベル付けされた3つのプロセス間でデータを分散する様子を示しています。これらの3つのプロセスは、単一のコンポーネントのインスタンスであり、先着順で単一のプロセスにデータを供給します。

この概略図では、ユーザーからのリクエスト(トランザクション)は図の左上から入力され、レスポンスは左下から返されます。「バックエンド」(右側)は、CORBA、MQSeriesなどを使用して、他のサイトのシステムと通信します。相互接続は、バックエンドを経由する必要のないリクエスト、またはユーザーに返される前にネットワークを複数回通過する必要のあるリクエストを表します。
異なるリクエストは異なるバックエンドを使用する可能性があり、また、バックエンド(使用される場合)がリクエストを処理するのに必要な時間も異なる可能性があるため、返されたデータを適切なリクエストトランザクションに関連付けるための仕組み(ハッシュテーブルやキャッシュなど)を用意する必要があります。
上記の図は概略図であり、最終的なアプリケーションにはさらに多くのプロセスが含まれる可能性があります。キャッシュの管理、接続トラフィックの表示、スループットの監視などを行うために、他のプロセスの間にプロセスが挿入される場合があります。また、図中のブロックは「サブネット」、つまり1つ以上のオープン接続を持つ小規模なネットワークを表す場合もあります。
この手法では、プログラムは単一の手続き型サブルーチン階層として構成されなければならないと仮定します。その出発点は、入力および出力データ構造に基づいて、アプリケーションを「メインライン」の集合として記述することです。次に、これらの「メインライン」のうちの1つがプログラム全体を駆動するために選択され、他のメインラインはサブルーチンに変換するために「反転」する必要があります(そのため「ジャクソン反転」と呼ばれます)。この結果、「衝突」と呼ばれるものが発生する場合があり、プログラムを複数のプログラムまたはコルーチンに分割する必要が生じます。FBPを使用する場合、各FBPコンポーネントを個別の「メインライン」とみなすことができるため、この反転プロセスは不要です。
FBPとJSPは、プログラム(または一部のコンポーネント)を入力ストリームのパーサーとして扱うという概念を共有している。
ジャクソンの後期の著作であるジャクソン・システム開発(JSD)では、これらのアイデアがさらに発展した。[ 14 ] [ 15 ]
JSDでは、設計は最終実装段階までネットワーク設計として維持されます。その後、モデルは利用可能なプロセッサ数に応じた一連のシーケンシャルプロセスに変換されます。ジャクソンは、このステップより前に存在するネットワークモデルを直接実行する可能性について、著書の1.3節で論じています(強調は筆者による)。
FBPはMAジャクソンによって「コルーチンのようなメカニズムで通信する逐次プロセスへのプログラム分解」 [ 16 ]の方法に従うアプローチとして認識されました。
WB アッカーマンは、アプリカティブ言語を、値に適用される演算子によってすべての処理を行う言語と定義している。[ 17 ]最も初期のアプリカティブ言語は LISP である。
FBPコンポーネントは、入力ストリームを出力ストリームに変換する関数とみなすことができます。これらの関数は、以下に示すように、より複雑な変換を行うために組み合わせられます。

図に示すように、流れを小文字でラベル付けすると、上記の図は次のように簡潔に表すことができます。
c = G(F(a),F(b));
関数表記法では、Fは値のみを扱うため副作用がなく、2回使用できるのと同様に、FBPでは特定のコンポーネントの2つのインスタンスが同時に実行される可能性があり、したがってFBPコンポーネントも副作用があってはなりません。関数表記法は、FBPネットワークの少なくとも一部を表現するために明らかに使用できます。
そこで、FBP コンポーネント自体を関数表記で表現できるかどうかという疑問が生じる。WH Burge は、再帰的かつ適用的なプログラミングスタイルを使用してストリーム式を開発する方法を示したが、この研究は原子値 (ストリーム) の観点から行われた。[ 18 ] FBP では、構造化データ チャンク (FBP IP) を記述および処理できることが必要である。
さらに、ほとんどのアプリケーションシステムは、すべてのデータが同時にメモリに利用可能であることを前提としていますが、FBPアプリケーションは、限られたリソースを使用しながらも、長時間のデータストリームを処理できる必要があります。フリードマンとワイズは、バージの研究に「遅延コンス」の概念を追加することで、これを実現する方法を提案しました。これにより、「コンス」の2つの引数が同時に利用可能である必要性がなくなりました。「遅延コンス」は、両方の引数が実現されるまで実際にストリームを構築しません。それ以前は、これを行う「約束」を記録するだけです。これにより、ストリームを前面から動的に実現できますが、背面は未実現のままになります。ストリームの末尾はプロセスの最後まで未実現のままですが、開始は絶えず長くなる項目のシーケンスです。
FBPの概念の多くは、長年にわたって様々なシステムで独自に発見されてきたようです。前述のLindaもその一つです。両者の違いは、Lindaの「ピラニアの群れ」ロードバランシング技術によって示されます。FBPでは、処理待ちのIPアドレス数が最も少ないコンポーネントにリクエストをルーティングする、追加の「ロードバランサー」コンポーネントが必要となります。FBPとLindaは密接に関連しており、一方を使って他方を容易にシミュレートできることは明らかです。
OOPにおけるオブジェクトは、情報と振る舞いの両方を含む半自律的な単位として記述できます。オブジェクトは「メソッド呼び出し」によって通信します。これは基本的にサブルーチン呼び出しであり、受信側のオブジェクトが属するクラスを介して間接的に行われます。オブジェクトの内部データにはメソッド呼び出しによってのみアクセスできるため、これは情報隠蔽または「カプセル化」の一形態です。しかし、カプセル化はOOPよりも古く、David Parnasは70年代初頭にカプセル化に関する重要な論文の一つを執筆しており[ 19 ]、コンピューティングにおける基本的な概念です。カプセル化はFBPコンポーネントの本質であり、入力データを出力データに変換するブラックボックスと考えることができます。FBPでは、コンポーネントの仕様の一部は、コンポーネントが受け入れることができるデータ形式とストリーム構造、およびコンポーネントが生成するデータ形式とストリーム構造です。これは契約による設計の一形態を構成します。さらに、IP内のデータには、現在所有しているプロセスのみが直接アクセスできます。カプセル化は、外部プロセスが内部プロセスを保護することによって、ネットワークレベルでも実装できる。
C. EllisとS. Gibbsの論文では、アクティブオブジェクトとパッシブオブジェクトを区別しています。[ 20 ]パッシブオブジェクトは、前述のように情報と動作を含みますが、この動作のタイミングを決定することはできません。一方、アクティブオブジェクトはこれが可能です。EllisとGibbsは、論文の中で、アクティブオブジェクトはパッシブオブジェクトよりも保守可能なシステムの開発において遥かに大きな可能性を秘めていると述べています。FBPアプリケーションは、これら2種類のオブジェクトの組み合わせと見なすことができ、FBPプロセスはアクティブオブジェクトに対応し、IPはパッシブオブジェクトに対応します。
FBPは、カール・ヒューイットのアクターを、入力メッセージ用と制御信号用の2つのポートを持つ非同期プロセスとして扱います。制御信号は、アクター自身が各実行ラウンド後に発信します。この信号の目的は、アクター本体の並列実行を回避し、同期なしでアクターオブジェクトのフィールドにアクセスできるようにすることです。