Pipes and Filters

パイプラインパターンと呼んできたIEnumerableを使ったアーキテクチャに別名発見。「Pipes and Filters」だそうで。

自分で読んでない本を紹介するのは心苦しいんだけど、「Pattern-Oriented Software Architecture」通称POSA本に載ってるらしい。邦訳は「ソフトウェアアーキテクチャ ソフトウェア開発のためのパターン体系」。POSAはシリーズ化しててVol5が近々出るみたい。
http://www.cs.wustl.edu/~schmidt/POSA/

オブジェクトクラブさんでPDFの図解を発見。
http://www.objectclub.jp/technicaldoc/object-orientation/pdf/chapter-3.pdf

Pipes and FiltersってIEnumerableのほうのLINQにぴったりな名前ですね。このLINQLINQ to Objects APIって名前なのかな?
パイプ&フィルタパターンなら、パイプラインパターンと呼ぶよりほかのモノときちんと区別ができそう。

ぐぐると、Struts1.3のChain of ResponsibilityはPipes and Filtersパターンなのでは?という指摘がありますね。Struts、全然知らないけど。

WikipediaではPipes and filtersはリダイレクトされてPipeline (software)へ。Pipeline (Unix)とは別項目です。日本のWikipediaUnixのほうだけ。McIlroyさんによるUnix shellが起源だそうな。またこの人か。diffもこの人だった…。あまり有名じゃないかもしれないけど、Unix初期の偉い人で珠玉のプログラミングによく出てくる。IEnumerableを標準入出力と見立てればUnixのパイプにとても似ています。
でも、実現方法は別。Unixでパイプを使った場合は各コマンドは別プロセスだけど、C#のIEnumerableはコルーチン(クヌース先生によると半コルーチンだそう)。

プログラムの中でPipes and Filtersしてる点では、Unixのパイプというよりも、前にも書いたようにSchemeのストリーム(遅延リスト)やHaskellのリストのほうが近いですね。これまでいろいろ試してきたように、その振る舞いや性質はそっくりです。Sequence.csを見ても、こっちが直接の由来と思います。
でも、言語の根っこの部分が違うので、これらの言語のつもりで書くと落とし穴があるのは最近見たとおり。

気づいた注意点は2つ。

1.各部品(フィルタ)の中ではIEnumerableからIEnumeratorを生成するのは一度だけにする。
2.id:siokoshou:20060402のRand()のように、IEnumerableからIEnumeratorを生成するたびに、異なるシーケンスを返すIEnumeratorを生成する場合は、1.に違反した部品を通すと結果が未定義になることに注意。(ややこしい説明しかできなくてスミマセン)

詳しくはid:siokoshou:20060401とそのコメント欄、id:siokoshou:20060402あたり。1.は単純な部品を書くときはごく自然に意識できるけど、長い部品を書くときは注意。
2.は守るも破るも書き手次第、と思います、私は。
SICPにもいろいろと利点、欠点の説明があります。よくわからないんですけどね…。

並列処理の分野ではパイプラインはあまり効果的じゃない並列化手法としてとして知られてますね。どーなるPLINQ。ヘジたんもインタビューでPLINQに懐疑的な顔をしてたのが印象的(^^;

こうやって見てみると、IEnumerableLINQアーキテクチャは長年研究&使用されてきた伝統あるパラダイムの上にSQL風の皮を被せたものってとこですかね。yieldがオートマトンあたりでいうところの状態マシンなのも含めて。DLINQと同じSQL風に見えるって点が、ものすごくうまい!と思います、ハイ。

ところで、パターンっていうとGoFの影響で小粒なイメージがあるから、このモデルをパターンと呼ぶのには実はちょっと抵抗があったり。パイプラインの考え方はもっと大きなパラダイムの違い?っぽいので。SICPでは「代入モデルに対して、代入や可変データを使わずに状態を持つモデル」みたいなことが書いてあるけど、よくわかりません…、消化不良です。
各部品の独立性の高さはいいところ。

しかし、diffに続いてまたしてもMcIlroyさんとは。珠玉のプログラムで賢い人って印象を持ってたけど、なんだかこの人の手のひらの上で踊ってる孫悟空な気分になったw