あどけない話

インターネットに関する技術的な話など

プログラマの壁

プログラマに向いている人と向いていない人がいるそうです。

Jeff Atwood さんの「どうしてプログラマに・・・プログラムが書けないのか?」:

プログラムを書ける者とプログラムを書けない者の間にある大きな溝についてはよく知られているが、プログラマの職に応募してくる人間は、すでにこの溝を飛び越えているものだとばかり思っていた。明らかにこれは妥当な仮定ではないらしい。プログラムを書けないプログラマの面接で時間を無駄にしないために、FizzBuzzスタイルのふるい分けが必要ということだ。

どんなことでも向き不向きはあるでしょうから、これには納得いきます。しかし、プログラマになれる人の中にも、溝があるようです。

Joel Spolsk さんの「Javaスクールの危険」:

私のささやかな経験から言わせてもらうと、伝統的に大学のコンピュータサイエンスのカリキュラムで教えられているもので、多くの人がうまく理解できないものが2つあった: ポインタと再帰だ。

溝はポインタと再帰だけではなく、他にもありそうです。

Paul Graham さんの「普通のやつらの上を行け」:

このプログラマ氏がパワーのスペクトルを見下ろしている時、彼にはそうしているという自覚がある。「ほげ」よりも力の弱い言語は、明らかに力が弱い。彼が慣れ親しんだ機能が無いからだ。しかし、このプログラマ氏が反対の方向に目を転じた時、彼は自分が見上げているのだということに気付かないのだ。彼が目にするのは、変てこりんな言語ばかり。多分、それらは「ほげ」と同じくらいパワフルなんだろうけど、どういうわけかふわふわしたおまけがいろいろついているんだ、と思うだろう。彼にとっては「ほげ」で十分なのだ。何故なら彼は「ほげ」で考えているから。

養老孟司さんの「バカの壁」を読んで、その考えが決定的になりました(この本自体はお勧めではありません。。。)。

数学くらい、わかる、わからないがはっきりする学問はありません。わかる人にはわかるし、分らない人にはわからない。わかる人でも、あるところまで進むと、わからなくなります。... それを考えれば、だれでも「バカの壁」という表現はわかるはずだと思っています。

「溝」より「壁」の方がしっくりくるので、「プログラマの壁」と言う表現を使うことにします。

まず、プログラマになれるかなれないかの壁があるのでしょう。なれたとしても、ある機能を理解できるかどうかの壁があります。その機能が理解できたとしても、次の機能が分るとは限りません。

ここでは、壁になりそうな機能を思いつくままに挙げてみることにします。

FizzBuzz

すなわち、簡単なプログラムが書けるかどうかという壁です。FizzBuzz が数分で書けないのなら、プログラマにはなれないでしょうね。

アルゴリズムとデータ構造

昔、授業で習ったユークリッドの互除法に感激し、この分野が好きになりました。新しいアルゴリズムを考えだすのには才能が必要です。僕にはその才能はありませんが、他の人が考えたことを学ぶことはできます。プログラミングをする際に、僕が一番頼りにするのは、この分野です。

最近は、この分野を軽視して、単にライブラリを呼べばいいとか、検索結果をコピー&ペーストすればいいという風潮があるように見受けられます。そう思っているのでしたら、ぜひ 「Joel on Software」を読んでみて下さい。いかに重要かが分るでしょう。アルゴリズムとデータ構造の勉強をしたければ、「珠玉のプログラミング」をどうぞ。(Pearl を珠玉と訳したところが、まさに珠玉です!)

Joel on Software

Joel on Software

珠玉のプログラミング―本質を見抜いたアルゴリズムとデータ構造

珠玉のプログラミング―本質を見抜いたアルゴリズムとデータ構造

正規表現

学生のときに苦労しました!その頃は、

  • 実用的な例題が載っている説明がなかったこと (a?b* みたいなものばかり!)
  • さまざまなツールの実装の差がまとまってなかったこと

などの理由により、学ぶのはとっても困難でした。

動かないのが、自分の正規表現のせいなのか、ツールがその正規表現に対応していないのか、はたまたツールのバグなのか判断できなかったのです。

「詳説 正規表現」(もちろん当時は初版)が出版されて、この混乱に終止符が打たれました。現在、正規表現を学ぶことは、そんなに難しくないのではないかと思います。

ただ、正規表現の中にも壁があるかもしれません。たとえば、ダブルクオートで囲まれた文字列の正規表現が /"([^"\\]|\\.)*"/ であると理解できる人は少ないかもしれませんね。

正規表現では、「または」で表現するので、「かつ」で考えるとつまずきます。そこで、「かつ」で考えたことも、ド・モルガンの法則で「または」に直せると知っておくのも重要かもしれません。

詳説 正規表現 第3版

詳説 正規表現 第3版

ポインタ

僕はマシン語の後に C を学んだので、C のポインタは逆に分りやすいという印象を持ちました。。。配列とポインタの違いは、少し難しいかもしれません。

char table[10];
char *p = table;
printf("%d, %d\n", sizeof(table), sizeof(p));
 → 10, 4

C のポインタを習得する際に役立ったのは、「Cプログラミングの落とし穴」です。(まだ、売っていてビックリ!)

Perl5 はポインタの抽象化に失敗しているので、Perl5 でポインタを学ぼうとした人は、不幸かもしれません。

JavaJavaScript などは、ポインタだらけの言語ですが、うまく抽象化されているので意識することはありませんね。

Lisp もポインタだらけですが、普段意識する必要はありません。ただ、セルの利用効率を上げようと思うと、ポインタを意識することになります。

Cプログラミングの落とし穴 (新紀元社情報工学シリーズ)

Cプログラミングの落とし穴 (新紀元社情報工学シリーズ)

再帰

再帰が分らない人は、「The Little Schemer」をどうぞ。日本語で読みたいなら、「Scheme 手習い」の古本を探してみましょう。それでもダメなら、「リスト遊び」をどうぞ。

The Little Schemer (The MIT Press)

The Little Schemer (The MIT Press)

リスト遊び―Emacsで学ぶLispの世界 (ASCII SOFTWARE SCIENCE Language)

リスト遊び―Emacsで学ぶLispの世界 (ASCII SOFTWARE SCIENCE Language)

オブジェクト指向

最近は Java から入る人が多いようなので、オブジェクト指向はあたりまえかもしれません。

僕の学生時代は、まだオブジェクト指向の黎明期で、間違った宣伝がたくさんされており、いろいろ誤解していました。間違った宣伝の例としては、継承による差分プログラミングが最たるものです。

オブジェクト指向では、

などの感覚を掴むのが重要だと思います。

また、「Rees Re: OO」を読んで、俯瞰した理解を得るとよいかもしれません。

高階関数

C で「関数へのポインタ」が分る人でも、高階関数でつまずくことがあるようです。関数の中で関数が定義され、それが返されるなんて想像できないかもしれません。

スコープがレキシカルのとき、返された関数はクロージャとなります。JavaScriptクロージャを使ってプログラムを書くのは楽しいですよ。

Haskell を勉強すると、カリー化も役に立つことが分ります。

非同期

ネットワークプログラミングは、非同期で書くのが自然だと思うのですが、どうしても同期で書いてしまうようです。制御の流れが複数になると、理解するのが困難なのでしょうか?

Ajax のお陰で非同期にまたスポットライトが当たるようになりました。でも、Ajax の非同期は中途半端なので、別の方法で非同期を学ぶ必要があるような気もします。

遅延評価

UNIX のパイプを使っているなら、コマンドのレベルで遅延評価を利用しています。Haskell のように、遅延評価が基本となっている言語では、関数レベルで遅延評価が使えます。遅延評価だと意識さえしない程です。でも、IO が絡んでくると、順番が決まらないため、モナドを使わないといけなくなり、意識させられます。。。

日頃使っている言語に遅延評価の機能がなくても、遅延評価という考え方自体が重要です。たとえば、ファイルの内容を色付けして表示することを考えて下さい。まず最初に表示している部分だけを色付けし、残りは後から裏で色付けすれば、ユーザにストレスを与えることがありません。

Lisp のマクロ

Lisp では、データもプログラムも S 式です。これは、プログラムをデータのように加工して、別のプログラムを生成できることを意味しています。この加工を請け負うのがマクロです。マクロを書くと、Lisp を解こうとしている問題に適した言語に成長させることができます。

Lisp のマクロを勉強したい人は、「On Lisp」をぞうぞ。

On Lisp

On Lisp

Scheme の継続

僕も勉強中です。

モナド

いやぁ、もう大変です。