2014-07-06

"Coders at Work" Peter Seibel 著

この手の書は、なにやら忘れかけているものを思い出させてくれるような気がする。それは、好奇心や探究心といったものだ。同時に、むか~しの愚痴も甦るけど...
人は皆、面倒臭がり屋である反面、純粋な好奇心に対しては真摯になれる面がある。そして、探究心の持続こそが才能を覚醒させるのであろう。
本書は、ピーター・サイベルが、いまや伝説となった15人のプログラマからコード哲学を聞き出すインタビュー集である。尚、サイベル自身がプログラマであり、教科書的な存在である「実践Common Lisp」の著者でもある。
その15人とは...
Netscape の実装者ジェイミー・ザウィンスキー。ソーシャルネットワークの概念を広めたブラッド・フィッツパトリック。JSON(JavaScript Object Notation) の生みの親ダグラス・クロックフォード。JavaScript の設計者ブレンダン・アイク。Java プログラマの尊敬を集めるジョシュア・ブロック。並行処理指向言語 Erlang の設計者ジョー・アームストロング。先進的言語 Haskell の設計と実装の中心人物サイモン・ペイトン・ジョーンズ。NASA と Google という対照的な開発グループを率いたピーター・ノーヴィグ。Scheme と Fortress を作り、数々の主要言語の標準化に携わった多言語話者ガイ・スティール。Smalltalk の実装者ダン・インガルス。実行時コンパイラ技術を生み、Ghostscript を作ったL・ピーター・ドイチュ。Unix の開発者ケン・トンプソン。最適化コンパイラ技術で女性初のチューリング賞受賞者となったフラン・アレン。ARPANET の実装者バーニー・コーセル。そして真打ち登場、コンピュータ科学者ドナルド・クヌースである。

ノイマン型アーキテクチャが提唱されて半世紀余り、インタネット世代を代表するフィッツパトリックを除いて、ネアンデルタール人に属す世代になろうか。共感できる点が多いということは、おいらも古代人ってか?ちとショック!しかしながら、いまだに情熱を持ち続け、趣味の境地でコードを書き続けているのには頭が下がる。
ちなみに、おいらはプログラマではない。むか~し組込システムのOSを書いていた時期もあるが、今では回路設計の経験の方が長い。これといった専門はなく、ずーっと雑用係と称してきた。最近はアルゴリズムの検証ばかりで、実装から遠ざかり気味。それでも思考のスケッチのためにプログラムを書く。いや、電子機器の開発設計に携われば、プログラミングを避けることの方が難しいだろう。回路設計においてもハードウェア記述言語を用いるし、その検証ではコンピュータ言語と協調させて効率を図る。画像処理アルゴリズムの検討では、ImageMagick やスクリプト言語と組み合わせるのも悪くないし、数学の落ちこぼれには、Octave のような数値演算言語の存在もありがたい。
おそらく万能なプログラミング言語は存在しないだろうし、ドメイン固有言語という思想はますます広がるだろう。ハードウェアの進化がムーアの法則に従い、ソフトウェアも大規模化していく中で、プログラミング言語の進化が比較的遅いのは救いである。言語システムには、多くの本質が内包されているように映るからだ。その傾向は、人間社会の変化に対する自然言語の変化にも顕れている。エドガー・ダイクストラは、こう言ったとか。
「母国語で満足に書けないようなら、プログラミングはあきらめることだ!」
プログラムとは、クヌースが言うように本質的に文芸作品なのかもしれん。尚、「The Art of Computer Programming」は数学的に濃い内容だけど、いつか挑戦してやると思いつつ、既に20年が過ぎた...

プログラミング言語がどうあるべきか、その意見が様々であることは驚くに値しない。設計の立場が違えば、設計哲学も思考法も変わる。本書でもその傾向が見られる。コードの取っ掛かり方だけを見ても...
ザウィンスキーやインガルスが、プロトタイプのようにすぐ動くようにすることの重要性を唱えるのに対して、ブロックは、実装前の段階で要求分析の重要性を強調しすぎることはないとし、クヌースに至っては、TEX プログラムをコンピュータに一言も入力せずに紙と鉛筆で書き上げた!と言っている。
デバッグの流儀では、デバッガ派、print 文派、あるいは、assertion 派に色分けされる。あるいは、C や C++ の普及の善悪や、言語システムがどこまで機能を具えるべきか、などでも意見が分かれる。
もちろん共通点も多い。誰もが読めるコードを書くことの重要性を唱え、無条件にシステムが巨大化する昨今、無謀なプログラムが増殖していることを懸念し、過剰なブラックボックス化についても議論される。確かに、Web アプリケーションに触れると、何年も放置された些細なバグが目立つ。情報が溢れればノイズが増殖し、プログラミングが庶民化すれば質の低い作品が氾濫する。高度な情報化社会では、鈍感さがより一層求められるようだ。
ソフトウェア業界は、全体的に良い方向に進んでいるのかもしれないが、回り道をしていることも否めない。ここに登場する偉人たちもまた、誰一人としてプログラミングが解決済みの問題だとは考えていない。ドイチュに至っては、今日のプログラミング言語で SIMULA-67 や Smalltalk より質的に優れたものはないと断言している。なるほど世間では、進歩や進化という言葉が迷信化しているところがある。インターネット世代のフィッツパトリックまでも、こう釘を刺す。
「新しいものが最低でないことを願っているのかもしれません。新しいプログラミング言語でやりたいことができるようになると期待するみたいに、でもユーザだって同じことです。ユーザはいつもバージョン番号の高いものを手に入れようとします。たとえそれがよりひどいものであっても。」
また、マルチコアというCPU構造の複雑化が、コードを書く方法を大きく変えていることも見逃せない。多くの人が最も厄介なバグに並行プログラミングにおけるものを挙げており、STM(Software Transactional Memory) の是非にまで議論が及ぶのは、なかなかの見モノ!

1. C と C++ の善悪論議
C++ の善悪については一般的に論じられているが、偉人たちの意見は、C の普及の段階から真っ二つに分かれる。アレンはコンピュータサイエンスの研究を大きく損なったと難じ、コーセルは最大のセキュリティ問題と批判する一方で、トンプソンはセキュリティはプログラマの問題であって言語システムの問題ではないと主張し、クヌースはポインタを「記法における最も目覚ましい進歩」と言っている。
プログラムで、大きな問題となるのは動的メモリの管理である。メモリリークや残骸の蓄積は、自身のプログラムだけでなく、他プログラムにも影響を与える。そこで、ポインタ機能は直にメモリにアクセスできるために忌み嫌われる。尤も昔は高級言語扱いされたが、今ではアセンブラのような低級扱いされる。しかし、参照で用いる分には便利な面がある。大量のデータ領域を関数の引数で渡すような場合だ。
そもそも、アプリケーション設計者が触れるべき領域なのか?という疑問もある。当たり前のことだが... バッファの境界を越えないことを明示的に確認せずにバッファを読んではいけないし、メモリブロックを不適切なタイミングで解放して他のポインタを不安定にしてはいけないし、サイズの合わないものを格納して他の値とかぶってはいけない。だが、そうした問題を見つけることが意外と難しい。
だからといって昔は、システムをアセンブラで書いて、アプリケーションを Pascal で書くというのも抵抗があった。C はシステムプログラムに大きな恩恵をもたらしたが、その利便性からアプリケーションの領域にも入り込んだ。アメリカ政府は、C の危険性を回避するために、Ada を強制しようとして、Ada 以外での契約を拒否した。だが、C の勢いは政府の思惑までも潰した。システム用言語とアプリケーション用言語を分けるべきだというのも、もっともな意見である。コーセルは、こう言っている。
「C が有用性を超えて長生きしすぎたと言いたくはありませんが、あまりに多くの良いプログラマに使われた結果として、今では十分よくないプログラマがアプリケーションを作るのに使うようになり、結論を言うと彼らは十分な能力がなく、ちゃんとやることができないのです。C は本当に優れたシステムプログラマには完璧な言語なのかもしれませんが、あいにくとあまり優れていないシステムプログラマやアプリケーションプログラマが、使うべきでないのに使っているのです。」
現在、高機能化したスクリプト言語が普及しているのは、よい傾向なのかもしれない。例えば、ガベージコレクションのような機能があるだけで、つまらないストレスから解放される。
一方で、C++ の普及はどうであろうか?多くの大学で C++ を採用したオブジェクト指向を教える講義がある。そもそも、こいつはオブジェクト指向言語なのか?C++ の実装の特異性や奇妙さを、いったいどうやって区別させるのか?クラスベースの言語は、ちと静的過ぎる感がある。大きなクラス階層があると、わざわざ分解してまで使う気はしない。だからといって、動的な言語を用いると、至る箇所でその場しのぎをやってしまうのだけど...
ザウィンスキーは、C++ テンプレートが大好きというような人には近づかないようにしていると言っている。フィッツパトリックは、C++ を少し擁護しているが、なるほど...
「個人的には、少なくとも C++ で scoped_ptr みたいなものを使っている限りでは、自分でメモリ管理することも特に煩わしいとは思いません。new も delete も書くことなく何日も C++ を書いていることができます。」
志の高いプログラマにしか手を出してはいけない領域というものがあるのだろう。思想に優れた者しが踏み込んではいけないシャングリ・ラのような聖地が...

2. デバッグの流儀
最近のスクリプト言語は、動的メモリまで言語システムが管理してくれるので、print 文で大方の現象は掴めるだろう。だが、システムに近い領域ほど、実際に何が起こっているかを知る必要がある。言語システムが十分優れたデバッグ機能を具えているとすれば、わざわざ余計なコードを埋め込む必要はあるまい。よって、用いる言語系と、システムとの距離によって、デバッガ派と print 文派に分かれることになりそうだ。実際は、いろんな手法を組み合わせるのであろうが...
テストにおいては、誰もが怠け者になりがちである。最も厄介なのは微妙に動いているように見える現象で、おまけに放置されがち。そこで、assertion を埋め込んで、不変条件を自動チェックするといった考え方も有効である。おいらはこの思想が好きだ。
print 文派のアームストロングは、こう言っている。
「プログラミングの偉い神様が言っています。汝プログラムの間違っていると思われる部分に printf 文を置いて再コンパイルし実行せよ...
"ジョーのデバッグの法則"というものがあります。それは、すべてのバグは最後にプログラムを修正した箇所からプラスマイナス3ステートメント以内にある、というものです。」
そもそも、デバッガの吐き出す情報が正しいのか?という問題もある。デバッガが関与する時点で、物理的なタイミングのズレが生じ、不安定な動きをすることもある。したがって、検証においては、検証環境をも含めたデバッグを心掛けるようにと、おいらは周りの連中に指示している。そのためには、必然的にシステムを理解する必要があり、それが真の意図だけど...

3. 純粋関数型と静的型付け
関数プログラミングとオブジェクト指向プログラミングでは、どちらが生産的か?という議論をよく見かけるが、宗教論争に映る。ここでは、ジョーンズがもう少し突っ込んだ観点から純粋関数型言語の魅力を語ってくれる...
関数型言語の始まりが、ギーク的で数学的であることは想像に易い。尚、ここで言う関数とは、多くの手続き型言語が採用している関数とはかなりイメージが違う。少なくとも副作用がない。アーサー・ノーマンは、副作用のまったくない二重連結リストを構築する方法を示したという。二重連結リストを作ろうとすれば、セルを割り当てて互いに指すような仕組みが必要で、どこかに副作用が生じそうなもの。だが、純粋関数型言語ならば、副作用なしにそれを実現できるという。デビット・ターナーという人の論文に、SK コンビネータについてのものがあるそうな。SKI なら聞いたことがあるが。ラムダ計算を変換して実行する一つの方法で、I は SKK と等価で取り除くことができるらしい。任意の複雑なラムダ項を、なんらかの変換ステップによって、S と K の項に置き換えられるのだとか。この得たいの知れない S や K のコンビネータが実装できれば、任意の演算モデルが実装できるってか。にわかに信じがたい、まるで魔法のような抽象化演算モデル。純粋関数型言語とは、純粋数学言語のようなものであろうか?数学も言語であることに違いはない。この発想は、まだノイマン型アーキテクチャの領域に留まっているのだろうか?純粋な関数にできることは、答えを返すことがすべて。根本的に呼び出すというプロセスは必要ないってか。だから、カッコだけでつなぐ Lisp のような構造も可能となる。だが、Haskell はそんな次元ではなさそうである。
とはいえ、評価するプロセスは必要だし、評価した結果を出力するのがコードのすべてだ。つまり、応答した遅延評価を扱うことが、入出力の問題となる。ここで言う「純粋」というのはどういう意味であろうか?極めて強い静的な型ということらしいが... ん~、難しい!
ところで、プログラミング言語には、データ型というものがある。これが言語の本質だと思うから、言語リファレンスを読む時は必ず型の章から始める。ちなみに、Perl のような言語に触れると、型なんかお構いなしって感じで、やはりクレイジーに映る。むかーしは型が厳密でない言語を扱う気がしなかったものだが、近年は適度に融通が利く言語を好む。ジョーンズは、ほとんどのプログラムは静的型で書けると主張する。保守の面で素晴らしい恩恵があると。
「依存型プログラミングをやっている人たちは言うでしょう。型システムは究極的にはすべてを表現可能にすべきだと。しかし型というのは奇妙なところがあって、コンパクトな仕様言語のようなものです。型は関数についてなにがしかのことを言いますが、頭の中に一度に入れられないほどたくさんのことは言いません。だから型について重要なのはそれが明快なことです。」
なるほど、型が関数の抽象化をなしているという見方はできそうか。データ型を適切に定義するだけで、そのプログラムが何をするものかについて、かなりの事を語ってくれる。全体像として型を書いて、型が済んだから次はコードを考える、という2段階のプロセスではない。整理する順番は二段階だとしても、型の検討中にスケッチ用のコードを同時に書いている。型設計そのものがプログラム設計であるという発想は、まったく同感である。

4. 並行プログラミングとソフトウェアトランザクショナルメモリ
ジョーンズは、STM が世界を救うほどのものではないが、ロックや条件変数を使う方法よりマシだと言っている。複数のプログラムカウンタ、マルチスレッド、マルチコア上で共有メモリを使うぐらいなら、STM の方が優れていると。
ロックベースのプログラムは、競合を最小化するためにロックを保持する期間を最小限にしようとするだろう。だが、細かい粒度のロックはうまくやる事が難しい。この点で STM が大きく優っているらしい。非常に細かいロック並みの粒度を、シンプルな原則で手に入れられるという。STM の推論原理では、トップの不変条件を設定すれば、後は逐次処理で推論できるらしい。例えば、銀行口座の残高を管理する場合、取引トランザクションの開始時と終了時で不変条件が成り立つようにすれば、推論では逐次的であっても、引き出そうが、預けようが、トランザクションは分離できるという考え方である。
となれば、トップレベルの不変条件の設定が鍵となりそうである。トランザクションの前後を矛盾なく設定する必要がある。また、トランザクションの途中で例外が生じても、それを破棄して不変条件は絶対に破壊されないようにする必要がある。並行処理にもかかわらず、命令型のコードに対してシーケンシャルに推論できると言っているようだが、ほんまかいな?やはり用途によりそうだ。
いずれにせよ、ロックマネージャのようなヤツが、データベースの中で最も物々しい存在となりそうだし、あるデータがロックされて、アクセス不能になるといった現象は、STM でも生じそうな気がするけど...

5. 文芸的プログラミング
文芸的プログラミングの提唱者といえばクヌースだが、当人は趣味みたいなものだと言っている。いずれにせよ、これが最高のものという証明はできまい。考え方のセンスだから、うまくやる人とそうでない人もいるだろう。
クヌースは、文章を書くためのルールを二つ挙げている。一つは、読者を理解すること。二つは、技術的な文書という条件付きで、すべてを二通りの仕方で補うように書くこと。だから、通常の技術文章は冗長性があるという。へー...
確かに、一つの事を違った視点から語るだけで、頭の中に入ってきやすい。文芸的プログラミングは、コードを書いた後にドキュメントを書くといったものではなく、両方を同時に書くようなもので、そこにはコードがあるだけでなく、ドキュメントが共存することになる。優れたコードを読む楽しさは、優れた小説を読む喜びに似ている。
スティールは、C の欠陥は文芸的プログラミングツールをもってしても克服するのは難しいことだと言っている。Common Lisp 用の文芸的プログラミングツールがあれば、きっと早く飛びつくだろうと。
しかし、文芸的プログラミングの魅力を認めつつも、現実にコードに反映することは難しいという意見もある。トンプソンは、二つの書き方があるなら、片方は間違っていると指摘している。正しいのはマシンが実行する方だけと。ノーヴィグは、こう言っている。
「クヌースのオリジナルの"文芸的プログラミング"の論文を読むと、彼が本当に言おうとしているのは、"本を書くための最良の順序は何か"ということで、本全体が読まれることを前提としており、それが論理的な順序になるようにしようと考えています。みんな今ではそのようにはしていません。本を読みたいとは思っていなくて、インデックスを求めているのです。"読まなければならない最小限の部分はどこだろう?必要な3段落だけを見つけたい。それを示してくれ!"これは大きな変化だと思います。」
圧倒的多数はそうだろうが、中には一冊を隅々まで目を通したいという貧乏性の読者もいる。ここに。やはり好みの問題であろう。逆に、上辺だけを拾って回る読者を締め出すには良い方法とも言えそうか。実際、技術文書ってやつは、読者の理解よりも数学的な厳密性が優先されるもの、という見方をする人が多い。だから、なるべくコンパクトに書きなさい!とよく叱られる。誤解されないように意識すると、どうしても補足的な記述を加えずにはいられない。おまけに、酔っ払いはお喋りときた。なによりも自分に分からせようと書いている。このブログにしても、対象読者は十年後の自分だ。ただ、数ヶ月後に読み返すと既にチンプンカンプン!文芸的プログラミングへの道は遠すぎる。はぁ~...

6. 過剰なブラックボックス化
ライブラリを自分で書けないなら、やることはライブラリを呼び出すだけになる。ライブラリの使い方を丸暗記することが仕事になるのでは、寂しい!数学書には証明がいっぱい詰まっているが、用途にピッタリとはまる定理がなかなか見つからない。ライブラリにも似たような事情がある。
おまけに、お偉いさんには、とんでもないライブラリを強制する性癖がある。黒幕の潜むブラックボックスは、いつも悪臭が漂う。根拠のないスケジュールの短縮という思想に憑かれると、マイルストーン上に何かが埋まっているだけで仕事をした気になれるらしい。再利用の効果を過剰に強調すれば、なんでもブラックボックスに頼ろうとする。それで責任転嫁できればOKってか?設計哲学の合わないライブラリやブラックボックスを組み合わせれば、奇妙な設計資産を量産させるだろうに...

7. 民主主義の在り方
スティールの言葉は興味深い。
「Lisp は容易に成長してきた言語の例だと思います。そのマクロ機能の柔軟性のためです。またある程度までは、それを作ったグループの社会的な姿勢のためでもあります。
それと対照的に、Scheme はもっと苦難の道をたどっています。そのある部分は、Scheme コミュニティが初期において全員、ないしはほとんどの人が同意するのでない限り何も言語に付け加えないという文化を発展させたためです。反対投票の文化なのです。
一方で、Common Lisp のほうは多数であればみんなを満足させるに十分という文化です。人はほかのものを手に入れるためなら、そう熱烈に好きでないものも受け入れるのです。」

0 コメント:

コメントを投稿