2008年05月 | プログラマ2.0日報 | あすなろBLOG
2008.05.29
今まで何回も取り上げてきた「マイクロフォーマット」ネタですが、Allsopp本の翻訳が
マイクロフォーマット Webページをより便利にする最新マークアップテクニック
というタイトル(仮題)で毎日コミュニケーションズから出版されるようです。情報元は「Web標準Blog」で、監修の木達一仁氏が関わっている会社です。
ちなみにセミナーも Allsopp 氏来日に合わせてあるようですが、これは満員御礼だそうです....
やはり関心ある人多いでしょうね...本は「買うべし」です(ただしエントリ時点で毎日コミュニケーションズの近刊予告には入っていないようです)
投稿者 : 杉浦 こずえ | 投稿日時 : 2008.05.29 12:33
2008.05.28
前回のエントリ...に限らず、私って平気で「コーラー側」という言い方をしてたのですが、"コーラー側" でググると、あまりコレ引っかからないのですね....
要するに
コーラー(caller) =(関数・メソッドの)呼び出し側
コーリー(callee) =(関数・メソッドの)呼ばれた側
のことを言います。あれぇ、私はプログラマの日常口語だと思ってたのですが、知らない人が多いみたいなのですね(まあ、「コーラー側」と使うと、「馬から落馬」みたいな冗語っぽいニュアンスがないではないですが)。
とはいえ、caller/callee は(明確な)技術用語で使われている箇所っていうのはあります。皆さんおなじみの JavaScript ですけども(まあ、他のスクリプト言語でも同様な実装があるのでは?)、関数の中で「隠し持っている(実際には関数呼び出し時にセットされる)」arguments というオブジェクトがあります。これは「その関数の呼び出し環境(スタックフレームみたいに考えて良さそうです)」を示し、名前の通り「その関数に渡された引数」を配列として持つのが本来の役割です。しかし、この arguments オブジェクトには、caller と callee という2つの重要なプロパティがあります。
JavaScript の arguments オブジェクトの
callee プロパティ: 現在実行中の関数オブジェクトを示します。
caller プロパティ: この関数を今呼んでいる「呼び元の関数の arguments オブジェクト」を示します。
というように、このargumentsはうまく使うとかなり面白いことができます。arguments オブジェクトはJavaScript 関数の汎用カリー化関数とかで「任意数の引数を再適用する」ところで使ってたおぼえもあります...たとえばですね、JavaScript では「無名の関数」を function() {} などで作ることができますが、この「無名の関数」内で、再帰呼び出しをしたい場合
.....あれ、名前がないから再帰で呼べない...
となりますけども、実はこれ、callee プロパティを呼べばいいのです。
function show(n,m) {
alert( function(x) {
if( x > m ) return x * arguments.callee(x-1);
return 1;
}(n) );
}
n!/m!
を再帰的に計算するルーチンならば、こんなところでしょうか。show() の内部で再帰計算をする無名関数を作って、それを引数 n で起動した結果を alert() しています。m の束縛はいわゆるクロージャです。あるいは、caller を使うと、スタックトレースが取れます.....しかし、この caller は JavaScript 1.5 では deprecated の扱いのようですが(がまだIE/FireFox共に動きますね!よかった...)
まあ、この caller/callee というプロパティは「スタックフレームへの参照」ですから、どんなスクリプト言語でも、「言語設計者が実装しようと思えば装備できる」プロパティです(逆に言うとかなり初期からこれを持つ発想のあった JavaScript の設計は評価すべきでしょう。参照方法はともかく、アイデアいいです)。同じようなプロパティが他の言語にもある可能性は高いですね....
そう考えてみたら、プログラマ用語として「コーラー・コーリー」を使う...というのはけして珍しいこと、とまでは言えないのでは?と思います。個人的には時代遅れになってなくって良かった(苦笑)....
投稿者 : 杉浦 こずえ | 投稿日時 : 2008.05.28 12:12
2008.05.27
書き出した時点で、お昼休憩中です。皆さんお昼ご飯はいかがでしたか?お昼ご飯代はおいくらでしたか....という話では、残念ながらないです(ちなみに私は大概会社の近くの自宅に帰ってお昼ご飯です。今日は昨日の残りモノで、鳥ごぼうご飯と、アスパラのおひたし、大福豆、大根おろし+金山寺味噌というメニューでした)。
お昼ごはんはタダではいけません! というのは、有名なSFネタのジョークです。「ノーフリーランチ定理」と呼ばれる面白い定理があります。それは、
数学的にありうべき全ての問題の集合について、どの探索アルゴリズムも同じ平均性能を示す
と主張します。結構意外じゃないですか?
プログラマ、というと「このアルゴリズムは性能がいい/悪い」というのを肌で知ってる...というのが望ましいですけども、しかし、それは「日常に現れる一般的な問題」の場合に「性能がいい・悪い」という議論をしているだけなのです。プログラマだったら、「いいアルゴリズム」がデータによって「ウラをかかれ」た経験があるんでは..と思います。たとえば、速いアルゴリズムの代表であるクィックソートは、すでに整列したデータを与えた時に、O(n2 ) にまで性能が劣化します。勿論「ホントにいいアルゴリズム」の場合は「最頻のケース」と同様に、「最悪のケース」に対する備えを心がけるべきなのですが....
このノーフリーランチ定理を言い換えると、
あらゆる問題で性能の良い汎用最適化戦略は理論上不可能であり、ある戦略が他の戦略より性能がよいのは、現に解こうとしている特定の問題に対して特殊化(専門化)されている場合のみである
ということになります。「よくある場合に性能がいい」と「ウラをかかれると性能が悪い」とは同じことの両面に過ぎないことをこの定理は示すのです。汎用的であればあるだけ、「最良の場合の性能」は悪化してしまいます....汎用性と特殊性のせめぎあい、というプログラマがいつも頭を悩ます問題というのは、回避不可能な本質的な問題なのです。
これはもっと広く考えて、問題とその解決法、という視点で考えるのも面白いでしょう。問題を「汎用的に解決する」のは非常に難しいわけです。
人生、宇宙、すべての答え
という極めつけの「汎用的な問い」への答えを要求された銀河最高のコンピュータ「ディープ・ソート」は、
42
という極めて「汎用的な答え」を返します(詳しくは「銀河ヒッチハイクガイド」を...)。「42」は答えに違いないのでしょうが、それは人間にとって「利用可能な答え」ではありえないのです....「汎用的」なのがいつもいつも正しいわけではないのです。
投稿者 : 杉浦 こずえ | 投稿日時 : 2008.05.27 13:48
responseencodingされているもの
2008.05.23
オブジェクト指向言語が紹介され始めた頃(80年代初期)に、「Object Oriented て具体的にどういうこと?」というコトバの問題で、ある学者が「唯物型(プログラミング)」という訳はどうか...などと提案していた覚えがあります。手続型言語のアドオンとして実装された言語でないならば、オブジェクト指向言語は、
すべてモノ(オブジェクト)だ!
ということになるわけで、「唯物型」というのもそれなりに根拠がないわけではないですね!→昔話
しかし、その後、オブジェクト指向プログラミングが成熟を重ねていくにつれ、「オブジェクト指向のプログラミング・ノウハウ」が蓄積されてきて、それが「デザインパターン」(狭く GoF でまとめたモノを指すと今回はしておきます)として結実したわけです。このデザインパターンの「思想」を非常におおまかに(哲学として)捉えなおすと、それは、
モノはモノなんだけども、モノとモノとの間の関係に着目して、「役割を担ったモノ」として捉えよう!
というのが、一番の重要なポイントなのでは...と思うのです。ここまでOK?
さて、よくコーディング規約では、
変数名は、それが「何であるか」をちゃんと記述するような名前をつけましょう!
と言われるのがフツーです。まあ、これが「正しくない!」と言うわけではありません。とはいえ、この「何であるか」ということにこだわりすぎると、こういうコードになります。
for( int indexOfSomeList = 0; indexOfSomeList <= sizeOfSomeList; indexOfSomeList++ ) {
SomeObject someObjectInTheListAtPresent = someList.get(indexOfSomeList);
someObjectInTheListAtPresent.executeSomeFunction( argumentForSomeFunction );
}
あ、勿論パロディですってば! 念のためシンプルな書き方と比較しましょうか?
for( int i = 0; i < someList.size(); i++ ) {
SomeObject at = someList.get(i);
at.execute( argument );
}
さて、どちらが判りやすいでしょうか.....少なくとも私は、「それが何なのか」を丁寧に記述したコードは、きわめて冗長に感じます。情報が多くなりすぎて、構造を覆い隠してしまっているという印象ですね。その情報は繰り返しに過ぎません。逆に for 文の中のループカウンタが「ホントに同じカウンタを示しているか?」ということさえも、一見して読み取りにくいわけです。
またこのルーチンを別なところで呼ぶことになりました。そしたら、実際にこのメソッドに渡されるのは、SomeObject の派生クラスのリストが渡されることになり、その派生クラスでは、executeSomeFunction() の「派生オブジェクトに対して、someFunctionをせよ!」というのが、直感的に意味が通らない表現になってしまいました....
たとえ話: 「鳥」というクラスに「飛べ」というメソッドは意味があるけども、「ダチョウ」という「鳥」派生クラスだと「飛べ」というメソッドは何をするんでしょう? だったら、「飛べ」というメソッドは過剰に意味を限定しすぎているのであり、「移動せよ」の方が適切では?
....要するにこれ、過剰に詳細に「何であるか」を説明的に記述してしまったために、機能的な柔軟性を失ってしまうケースがある、ということです。残念ながら、プログラムの構造よりも、「変数が何を示すか?」の方のがずっと変化しやすいのです。
勿論私は、インスタンス変数の命名に、「それが何を示すか記述的な名前をつける」ことに反対するわけではなく、それを薦めます。
しかし、引数名や自動変数には、「それが何であるか」を示す名前を付けるよりも、「それがどう振る舞うか?」に注目して名前を付けるべきだ、と思います。i, j, k という変数ならば、プログラマはフツーにそれらを「ループカウンタ」だと理解しますし、len や size と付いていれば、注目しているコレクションや文字列のサイズであろう、と了解します。あるいは、sum ならばループの中で蓄積される値であることを期待しますし、ret という名前ならば、それが戻り値を強く関連付けられている変数だと理解します....こういう名前は「そのメソッドの中でどう振る舞うか」の役割を示す変数名なのです。このような「振る舞いの名前」を見れば、その動きについて、予測が付きます: 予測がつく分、プログラムを意味の通った構造としてすんなりと把握できるというメリットは大きいのです。
逆なメリットもあります。
インスタンス変数は 「それが何か示す説明的な(長い)名前」
自動変数は 「役割を示すかなり固定した(短い)名前」
だったら一見して簡単に区別が付きます。しかしそれよりも重要なのは、こういう風に「何に対してするのか」よりも、「どう動くものなのか」をメソッドが明示するようになると、「メソッドAとメソッドBは実は同じ構造を持っているから、これらは一緒にまとめてやった方がいい」というリファクタリング発想を強く促す、という点です。
2つのリストをインスタンス変数で持っているクラスだとしましょう。最初は個別にそのリストについて探索をするメソッドを書いていました。
MyObject findListA( int a ) {
for( int i = 0; i < this.listA.size(); i++ ) {
MyObject object = this.listA.get(i);
if( object.getA() == a ) {
return object;
}
}
return null;
}
しかし、「これら構造はまったく一緒じゃん!」と気がついたとき、それは
MyObject find( Listlist, int a ) {
というインターフェイスに変わり、コーラー側で「何からfind するか」を、インスタンス変数を引数渡しすることで、選択することになります。シンプルに書いていればいるほど、構造が全面に出て、「構造の共通性」に気づきやすくなります。これは「何であるか」ではなくて、「どう振る舞うか」を重視したことによるメリットなのです。
「何なのか」を記述する「唯物論」ではなくて、「どう振る舞うか」を大きなパターンとして捉える視点を今回強調したわけですが、ホントは情報の量と人間にとっての理解しやすさ、というのは反比例したりするわけです(情報理論を勉強するといいですが)。「情報が多いこと」が必ずしも理解を助けるのではなく、「情報を最低限に絞ること」が本当はデザインの極意なのではないのでしょうか。
投稿者 : 杉浦 こずえ | 投稿日時 : 2008.05.23 13:35
2008.05.22
って英単語知ってます? 辞書で引くと、
Intrinsic=本質的な、内在する Extrinsic=外来的な、非本質的な
というくらいな意味なんですけども、要するに
- Intrinsic=あるモノの中にある、それがそれであるような、本質的なモノ
- Extrinsic=あるモノの中にあっても、それが本来備えるモノではないこと
というくらいに理解すればいいんじゃないかな。まあ、ちょっと気取った英単語ななので、知らなくってもどうということはないんですけどね。で、この単語、実は GoF で非常に印象的に使われているんです。その部分はというと、「FlyWeight」パターンのところで、ネット上の文章でも、この語をそのまま使って FlyWeight を解説しているケースを見かけます。
....とはいえ、この Intrinsic/Extrinsic の区別は、別に FlyWeight 専用のもののわけではないです。どんなクラス・オブジェクトでも、Intrinsic な情報、Extrinsic な情報という風な見方で見ることができる...というのが今回のネタです。
たとえば、コンストラクタ引数として渡してオブジェクトを生成するような情報は、そのオブジェクトの「Intrinsicな情報」だと言えます。それに対して、そのオブジェクトが「何かする」メソッドの引数として渡すような情報は、「Extrinsicだ」と言えるわけです。こういうケースでは典型的なので、はっきりと区別ができますが、そうじゃない微妙な情報もいろいろあります。
どのようにコンパイラが動作し
- 1. インスタンスによって設定されていたり、いなかったりするインスタンス変数。
- 2. 何かさせる直前で引数代わりにセットされる情報。
- 3. Intrinsic な内部情報を二重化してもっているタイプの情報(キャッシュとか)
まあ、特に「白黒ハッキリつけよう」と思うわけではないですから、曖昧なものはとりあえず曖昧としておきましょう。しかし、「そのクラスにとって、この情報は Intrinsic か、それとも Extrinsic か?」というのは、クラスを作るときに結構重要な視点になります。ですから、それをキレイに言い表すコトバとして、Intrinsic/Extrinsic を有効に使えれば....なんていう提案です。どうです? FlyWeight 専用じゃちょっともったいないでしょう!
余談:Intrinsic っていうと私がまず連想するのは、XIntrinsics だったりします。これは、X-Window の上で、低レベルな Xlib ライブラリと、高レベルなツールキットの間に立って、「いろいろなウィジットを作るための道具」であるライブラリのことを言います。この XIntrinsics は純然たるCで書かれた非オブジェクト指向言語でのライブラリなのですが、ウィジット自体はちょっとしたオブジェクト指向味の「オブジェクト」だったりします。親ウィジットの属性を継承できたりしちゃうのです。まあ、Cなのでここらへん、構造体の入れ子でうまく書けるようになっているのですが、このXIntrinsics では、「ウィジット(全体の枠組みを示す)クラス」を表すデータと、「(個々の)ウィジットのインスタンス」を表すデータをうまく分離しています。さまざまなコールバック情報などを大量に抱え込んだ「ウィジットクラス」がその「ウィジットにとって Intrinsic」で、シンプルに自分が使うプロパティだけを持った「ウィジットのインスタンス」が「そのウィジットにとっての Extrinsic」というあたりなのでは...と名前の由来をようやく今になって気がついた...みたいです。
参考:Xプログラミング入門~応用編:変形ウィンドウの実現
投稿者 : 杉浦 こずえ | 投稿日時 : 2008.05.22 21:25
2008.05.19
こういう記事です。
世界の貧しい子供たちは、もうLinuxで苦労しなくてよくなる
結構皮肉な書き方です....
Microsoftが何としても避けたいのは、コンピューターをわかる人がたとえ1人でも、Microsoft Windowsのない世界が可能であると思ってしまうことだ。
まあ、私は90年中盤に「中古でイイからSparkでも買って...」と思っていたところに Linux が登場したのでそっちに方針変更したクチですから、「Windowsのない世界」の可能性、というのを充分イメージすることが出来てしまいます。OSを一社が独占することのよしあしについて、ここで論じる気はありませんけどもね。とはいえ、日本でも私の友人の某氏は、「余計な金を、独占企業に払うのはイヤだ!(この友人、サヨクです...)」と言って、プログラマじゃないのに、Linux をインストールしちゃってました(苦笑)。
ですから、逆に「途上国出身のスゴいUNIX系プログラマ」が続々登場する可能性、というのは実はかなり高いのかもしれません。Linux は便利で強力で安定しているだけではなくて、「(不合理な)情報格差を自然と埋めるコンヴィヴィアルな道具」なのですね(オープンソースとイリイチの思想...って結構背景としては重要だと思います)。やはり、「コンピュータは新しい世界を拓く道具である」というささやかな理想主義を、プログラマとしては持ち続けていたいものです....
私が思うにこのPCのオペレーティングシステムはLinuxで何の問題もない。
投稿者 : 杉浦 こずえ | 投稿日時 : 2008.05.19 09:25
2008.05.15
とおねだりする話では全然ないです。
集計みたいなタイプのプログラムを書いていると、
要素の重複をOKにするコレクションが欲しいけども、List で線形探査するのはアクセススピードを考えると勘弁して!
という状況が生まれます。java.util のインターフェイスの中では、
- List だと、要素の重複はOKだけども、contains() は線形探査。
- Set だと、要素の重複は不可だけども、contains() はハッシュコードなり二進木なり速い手段を使って探査する。
というように、帯に短したすきに長し...という状況です。これを解決するのは、jakarta-commons(あれ、今はApache-commons の方が良さそうですが)のcollections 中にある、Bag というインターフェイスです。実際この org.apache.commons.collections.Bag は、
要素の重複がOKの List みたいな Set
なのです....ですから、この実装クラスとして、o.a.c.collections.bag.HashBag(HashSet相当)とか、o.a.c.collections.bag.TreeBag(TreeSet相当)があるので、たとえば「データが追加された時点で、ソートされている List」みたいな使い方を、TreeBag はすることができてしまいます。これ結構強力でしょ!
実際のところ、Collections フレームワークと、Java5 の新 for 構造のおかげで、
今ループで順にアクセスしようとしてる対象が、配列なのか List なのか Set なのか全然クライアント側では気にしなくてイイ!
という状況になっています。とすれば、
コーラー側は整列したモノを期待しているのだけども、手元にあるのは非整列状態しかない。ゲッタで呼ばれるたびにソートするのか(効率が悪い)? それともソートしたものを内部で保持する格好にして、一度ソートしたらソレを返すようにするのか(同期しなくなる可能性がある)?
という悩ましい状況を、「そもそも整列された状態で保持すればいいじゃん!」とキレイに解決することができるようになるわけです。Set だと重複値の問題で List と同一視できない、という落とし穴を、この Bag は回避できるのです。
あと、commons-collections の使い勝手のいいオブジェクトとしては、MultiMap(重複した値を一つのキーに与えられるMap)があったりしますから、こっちも Bag とノリは似てますね! 今一つ地味(でも、さまざまな大オープンソース・プロジェクトでフツーに使われている...) な commons-collections ですけども、使うと結構イイ使い心地です。ぜひぜひお使いください。
あと設計が Decorator ベースで、かなりイロイロできるようになっているのも特徴ですね。均質化Bag とか、変更不可とか、あるいは 3.0 からは Predicate によるちょっとした Map 関数風処理とか、結構地味ながらも着実な進化を遂げているみたいですね!
投稿者 : 杉浦 こずえ | 投稿日時 : 2008.05.15 15:24
2008.05.13
どのように行番号を見つけるには、cgiスクリプト行
アーサーは小部屋に通じるドアに体重をかけて、開かないように押さえていた。しかし、ドアはちゃんと合っていない。か細くて毛むくじゃらの小さい手がいくつも、ドアのすきまから突っ込まれてくる。その手の指はインクで汚れていた。小さい声が熱に浮かされたようにぺちゃくちゃ言いつづけている。
アーサーは顔をあげた。
「フォード、ドアの外に無限の数のサルがいて、『ハムレット』の台本を仕上げたからぼくらとその話がしたいと言ってるんだけど」
(ダグラス・アダムズ「銀河ヒッチハイクガイド」安原和見訳)
まあ、これは大好きなSF(原作・映画共お気に入りです!)なのですが、今回の話は、「無限の数の猿がタイプライターを叩き続けば、いつかはフランス国立図書館に収蔵されている書物の全てを書きあげることができる」と言い表される「無限の猿定理」と呼ばれるものについての考察です。
....要するにこれ、非決定性アルゴリズムなんです。以前も「空にカードを放り投げて..」書きましたが、平行プログラミングにちょっと考え方を慣らそう、というイメージトレーニングみたいなことを考えているのですが、そこでのパラドックスみたいなこと、かな?
勿論「無限の猿定理」自体は真実です。しかし、「無限の猿」による無限個の「ハムレット候補」があるために、これをチェックして「本当のハムレット」を見つけ出すための計算量が爆発してしまう....(停止するのは確実でも、異常に時間がかかる可能性も高い)ということになのですね。本当のハムレットを見つけ出すには、猿が抱えるタイプ用紙を1枚づつチェックしていかないとダメなのです。
しかも、「本当のハムレット」を識別するためには、「本当のハムレット」のテキストを「持って」いる必要が出ます。「本当のハムレット」のテキストと猿が打ったテキストとを比較して、正しく打てているかどうかを見るわけです。...しかしこれ、考えてみれば、手元にすでにまぎれもない「本当のハムレット」があるわけです。無限の猿に仕事をさせる必要が....あるのでしょうか?
同じようなことは、量子コンピュータが使う量子アルゴリズムでもあります。量子ビットは複数の状態を重ね合わせることができ、それらの状態を全体として他の量子ビットと演算させることができるわけです。ですから、結果もやはり量子ビットのかたちで表現される...わけですが、例の「観測問題」のために、いざ結果を得ようとする時に、「量子ビットが重なり合った状態」から「確率的にその量子ビットのどれかを表現する1つの状態」に変化してしまう(重ねあわせが壊れる)ことになります....ですから、「量子アルゴリズム」とされるアルゴリズムは、観測に拠らず値が決まる、という特別な性質を持ったアルゴリズムであるわけです。
量子コンピュータは非決定性チューリング機械の「特別な場合」ということになりそうです。まだまだ全然実験状態で、期待される「素因数分解を超高速で行う!(実際これをするためのアルゴリズムが見つかっているので期待されているわけです)」でも、15=5×3に成功してから、どうなっているんだろう....と心配なあたりです(最近あまり記事がないですね)。まあ、そんなところですから、私が実際に量子コンピュータをプログラムする...というのはムリっぽそうなのですが、それでも知的興味は強くあります。
量子コンピュータについてのオススメ本は、やはりブルーバックスの「量子コンピュータ」(竹内繁樹著)です。想像がいろいろと広がりますし、しかもこっちは実用化まであともうちょいの「量子暗号」についてもちゃんとした説明が載っていたりします。エンジニアならば面白く読めると思います。
しかし、どうやら量子力学の多世界解釈によると、観測によって「Aと観測した世界と、Bと観測した世界とに、世界が分岐してしまう」ということにもなるのかもしれません。としてみると、実は「無限の猿」というのは「観測によって分岐した無限の世界」の猿たち...だったのかもしれないです(空想)。
投稿者 : 杉浦 こずえ | 投稿日時 : 2008.05.13 20:48
2008.05.10
ずいぶん前(80年代くらい?)に読んだ話なので、登場人物が間違ってたらごめんなさい!
芥川也寸志は著名な作曲家・指揮者なのだけども、レコードプレーヤーというものを買ったことがありませんでした。どうしてもレコードを聴かなければならない時には、亡父遺愛の竹針蓄音機で聴いていましたが、とある業界関係者に最新のステレオセットをプレゼントされて.....
まあ勿論、作曲家ですから「音楽は演奏会で聴くものだ」というのが最初からアタマに入っていて、それで「記録・再現手段に過ぎないレコード」というものを異常に軽視した...という事情がこのエピソードにはあるわけで、感想としては、
なんて貴族的な.....
というところでしょうか(ちなみに「亡父」というのは芥川龍之介ですね!)。音楽はライブに行かないと、ホントのところはわからない....というのはポピュラー音楽でも実はあまり差はないようには感じないでもないですが、しかし「音楽メディア」という面で考えて見たときに、もう一つ「音楽を伝達するための重要なメディア」があるわけです。もちろんそれは、
楽譜
です。芥川也寸志は作曲家・指揮者ですから、当然自由自在に楽譜を読みこなし、楽譜から「演奏された音楽」をイメージをできてしまうわけです。この「アタマの中で鳴りひびく音楽」の美とリアリティが、「他人の音楽」をおおまかにカリカチュアしただけの「レコード音楽」よりも、完璧に勝っていればこそ、レコードプレーヤーを長らくまったく必要としなかった....というような事情があるのでしょう。
私がこの話を憶えていた...というのも、やはりこのようなメディアとのかかわり方、というのに非常に憧れる面があったからだと思います.....
翻って、昔はコンピュータ・プログラムのことを「算譜」と言ってました。古いコンピュータ科学の教科書では大マジメにプログラムを「算譜」と呼んでて時代を感じますが....ようするにコレも楽譜の一種なのかもしれません。とするのならば、
自由自在にプログラムを読みこなし、プログラムから「実行される処理」をイメージできてしまい、この「アタマの中で実行される処理」のスピード・実行効率が、実際のコンピュータでの実行に完璧に勝る....
なんてことが、プログラマのちょっとした理想なのかもしれません。実際こっちも結構憧れますね! 「音楽の出版」がレコードと楽譜の2つの形式を持つように、プログラムの配布もバイナリとソースがある...のかもしれませんよ!
ちなみにあと、楽譜・算譜の仲間としては、楽譜に触発されて作られた「舞踊記譜法」であるラバノーテーションなんていう面白いものがあります。これは「特にダンスジャンルを問わず、人間の体のどんな動きでも譜面として記録できる」という結構スゴイものです。
投稿者 : 杉浦 こずえ | 投稿日時 : 2008.05.10 21:45
2008.05.08
少し前回の補足...というか、前回書いていて見かけた内容についての、ちょっとした意見...というあたりでしょうか?
要するに「テストファーストに対する反対意見」について、ということです。あ、私はテストファースト好きですよ!! ですから、「反対意見に感じる違和感みたいなもの...」が今回のテーマです。
すごく有名な「デキの悪い反対意見パロディ」として有名なものとして、「テスト・ファーストなんて嫌いだ」がありますが、これは「反対意見をパロろうとして、結果として全然面白くない...」といういささか不憫なエントリだったりします。まあここで書かれている反対意見(の根拠)に説得力がないのはパロディセンスの欠如というものでしょうから、ここで検討する意味はないですね。
「テストファーストの弊害」はまともなので、こっちはマジメに検討する価値があります。このページが論拠として挙げるのは次のものです。
- 1. 計画性のないテストによって、テストの品質が下がる
- 2. 単体テストが行われず、バグが見逃される
- 3. 効果的でないテストが工数を浪費する
- 4. 読みづらいドキュメントが、修正を妨げる
このうち 4. の「テストケースが仕様を正確に明示するものだ、とは言っても、それが読みやすくまとまっているというわけではない」というあたりは私も全面的に賛成です。これはいいツールを作る...とか考えて、javadoc に統合できないかしら....テストケースに記述されたテスト内容が、いつもの javadoc に反映したらすごくイイでしょ。とはいえ、そのテスト内容をうまく抽出して記述できないと意味がないので、そこは考えどころですが....
しかし、その他の3点にはかなり違和感があります。それは、
テストファースト=開発と単体テストを一緒にやってしまう開発手法
とどうやら捉えているらしい...というところでしょう。あれ、テストファーストのテストって、どっちかいうと、
よりよい仕様を探っていくための、設計手段としてのテスト
というものじゃなかったっけ。ですから、作ったコードが(外部的な)仕様を満たしているかどうかテストするテスト、とは全然独立なもの、とさえ思います...まあ、外部的な仕様が完全に決まっているプログラムだったら、テストファーストを採用する必要性なんて全然ない...とは感じませんか?(まあダブって単体テストしても害は何もないと思いますよ、苦笑) 「テストファースト=今風の契約主導設計」というところでしょうか?
ですから、私が感じるところの、最大のテストファーストのメリットは実はですね、
インターフェイスが洗練される
ということなのです....
普通に書いていると、「直接呼び出すところでうまく出来ればいいや...」という感じで場当たり的なインターフェイスを作っちゃうこともないわけではないですが、テストファーストだと「テストが明快にできるインターフェイス」をどうしても優先することになります。でしかも、ほとんどの場合、
テストしやすいインターフェイスは良いインターフェイス
だったりするわけです.....テストケースとは、プライオリティのかなり高いクライアントコードなのです。
テストファーストで書けば「呼び出し順に依存するインターフェイス」のような悪い(明示的でないルールを持った)利用規約をあえて採用するのはかなり恥ずかしい、と感じるようになります。
Target target = new Target();
target.setMap( secretMap );
int ret = target.getTreasure();
上の例のような、あるメソッドが動くのに必要な情報を、テスト前にセッタでセットする必要がある(←明示的でないルール)のを止めて、引数でその情報を渡すように変更したらどうでしょう?
Target target = new Target();
int ret = target.getTreasure( secretMap );
あるいは、渡す情報がその Target クラスにとって本質的なものであるのならば、コンストラクタで渡すのも良いでしょう。
Target target = new Target( secretMap );
int ret = target.getTreasure();
あるいは、これがまったく内部的な情報を使わないのであれば、思い切って static メソッドにすべきなのかもしれません....
int ret = Target.getTreasure( secretMap );
というように、テストファーストは、インターフェイスについて考える「もう一つのクライアントコード」としての働きを持ちます。これは特に「再利用を考えたライブラリ的なプログラム」では、「より使いやすいインターフェイス」であって欲しいですから、それをあらかじめテストケースとして考えておくようなものなのです!
ですから、逆に言えば、こういう場合にはテストファーストはあまり意味がないですね!
- 1. 明快に記述された外部仕様を持つ場合 → 今までの理想ケースですから、あえて変える必要はないでしょう...
- 2. 使い捨てで再利用する可能性が低いコードの場合 → 一度書いたコードを「多面的に使う」可能性がないのならば、あえて手間のかかる工程を取る必要はないでしょう。
- 3. インターフェイスを変更するのが政治的にやりにくい場合 → 「精度はともかくとしてとりあえず動いているコード」を要求され、それを使う人が今まさにいる状態で、よりよく改善している場合は、簡単に「前のインターフェイスは良くないですから、新しいインターフェイスを使いなさい」とは言えません....この場合インターフェイスの互換性を守る必要が出てしまいます。
まあ、「銀の弾丸はない」のがアタリマエです。テストファーストも適材適所、です。
投稿者 : 杉浦 こずえ | 投稿日時 : 2008.05.08 21:28
2008.05.06
シリーズ第3回なんですけども、ここでちょっとコーヒーブレークで歴史を振り返りましょう。
結局、「コードの読みすさ」というものは、
プログラムの実行とは直接関わらないが、プログラムの全体的な把握を容易にする説明記述を、いかに合理的に追加するか?
ということになります。こういう視点は実は結構前からありまして、その創始者は例によって、ドン・クヌースです。クヌースは「文芸的プログラミング」という名前でアイデアを表現しています。
我々はプログラム作成における伝統的な態度を変更すべきである。すなわち、計算機に何をすべきかを命じることが我々の主要関心事であるという妄想を捨て去り、人間に我々が計算機に何をさせたがっているかを説明することにむしろ傾注すべきである。(クヌース「文芸的プログラミング」より、有澤誠訳)
言いますねえ! 「どう動くか」を「コンピュータに指示」することは、本当は全然重要ではなくて、「人間に理解させる」ことの方がずっと重要だ、とクヌースは過激に主張しているわけです。あ、クヌースがこのやり方を実践したのは TeX の開発の中でですから、実際には 1980年代に公にしているわけです(例の TeX Book の出版...ということになりますか)。ですから、随分と昔から、「プログラムとコメントとを合体させて、人間に判りやすいように記述する」というアイデアはあるものです。
ですから、クヌースは自分のことを「コンピュータに指示を出すプログラマ」ではなくて、「人間を相手にした随筆家」だとしています。
文芸的プログラミングの実践者は随筆家とも見なされよう。その関心は主として解説と文体の卓越にある。著作者は手に辞典を持ち、注意深く変数に名前を付け、各変数の意味を説明する。彼は理解可能なプログラムを作ろうと努力し、諸概念を人間に一番わかりやすい順番で導入し、形式的、非形式的方法をないまぜて、お互いが効果を強めあうようにするであろう。
....ここらへん、昔すごく憧れたものです。TeX Book なんて、「読み物兼プログラム」で出版されていたわけですから...
とはいえ、この発想はかなり時代に先んじていたわけです。しかし、「ドキュメントがソースとシンクロしないのは、それを別々にメンテしているからだ!」というもっともな理由から、Java では最初から javadoc が付いていた...こともあって、最初から「ソースがドキュメントを含み、ソースからドキュメントを抽出して Web ページとして構築できる」という格好になったわけです。クヌースでは「ドキュメントの中にソースがある」でしたが、これが「ソースの中にドキュメントがある」という、今一般的なかたちに逆転しているわけですね。
で、この javadoc のアイデアの元って何だろう?というと、やはりメイヤーにありそうです。実際には「ドキュメントとソースをシンクロさせるのには、それが1つのファイルに合体している必要がどうしてもある」というだけでは足りず、それを「ドキュメントの view」「ソースの view」という感じで、自動的に view を切り替えて出力し、しかもそれが「情報隠蔽」を実現した格好になっている、という発想がポイントのように感じます。メイヤーだと、
その代わりに、モジュールの中にドキュメントを含めるべきなのである。この方法では、ソフトウェアは1つの製品でありながら、複数の見え方(view)をサポートするようになる。1つの見え方はコンパイルと実行に適した見え方で、ソースコード全体である。また別の見え方は個々のモジュールの抽象的なインターフェイスドキュメントで、ソフトウェアを開発する人がモジュールそのものの内部を知らずに顧客モジュールを書けるようにするためのもので、情報隠蔽の原則に従っている。(「オブジェクト指向入門第2版」邦訳p70)
と、この自己文書化をOOPの中にきっちりと位置づけて考えています。でしかも、実際にはメイヤーの場合、事前条件・事後条件といった表明で記述される制約は、現実的に「インターフェイスの記述」になるものですから、これも自己文書化の対象とならなければなりません。ですから、メイヤーが Eiffel に対する javadoc として作った short では、この表明記述を抽出してドキュメントとする機能を備えているわけです。
残念なことに、Java の表明機能(assert)は機能を限定された実装です。ですから、javadoc と assert が連携して、自動でインターフェイスの制約を javadoc に盛り込む...なんてことはできません。これが出来たら、少しは Java の assert も普及するのでは...とも思いますね!
とはいえ、以前にも書いたことですが、メイヤーの「契約によるプログラミング」とXPの「テストファースト」とは、かなり相通ずる側面があります。これを考えてみると、JUnit のテストクラスを、うまくテスト対象クラスと結びつけて、JUnit の書き方を工夫して、「JUnit の javadoc コメント」をうまく「テスト対象クラスのインターフェイス制約」として取り込むような仕組み、というのを考えてみるのも有益かもしれません....意外にテストクラスの javadoc というのはサボりがちですが、実はこれは
javadoc で管理し、テスト計画書が javadoc で出力できるようにする
のが当然ベストです。そう考えてみると、テストクラスの javadoc というのは実は意外な潜在的な活用の可能性を多く秘めている存在かもしれません。
投稿者 : 杉浦 こずえ | 投稿日時 : 2008.05.06 12:36
0 コメント:
コメントを投稿