プログラミング言語は、完全な柔軟性をもって開発者が好きなようにいじり回せて、開発者が自分でやったことには責任をもつと信じるべきなのか?それとも悪いコードやメンテナンス性や可読性をさげてしまうような失敗を避けるために、設計時に言語の中に明確な制約を設けるべきなのか?
Bruce Eckel氏は、ある種の機能は複雑すぎて、結局のところ、ほとんど使われないと考えている。
実行時のモデルが存在しないC++(コンパイルすると全てネイティブのコードに変換されて、Cとの互換性をもたなければならない)では、テンプレートによるメタプログラミングが現れました。そんな制約があったので、テンプレート・メタプログラミングはとても複雑で、ほとんど誰も、どう扱ってよいかわからなかったのです。
Javaは実行時のモデルを持ち、動的にコードの変更を行う方法すらあります。しかし言語の静的な型チェックが面倒なので、メタプログラミングは、C++の場合と同様にとても難しいのです。
はじめてアスペクト指向プログラミング(AOP)を見たとき、大半のプログラマには、ちょっと複雑すぎるなと感じたことからも、足りない点があることは明らかです。
Smailtalkと同様に、Rubyにおいては、全てのものが置き換え可能です(これは静的言語になれている人たちにとっては、おっかないものです)。
Michael Feathers氏は、Eckel氏が言語に対する制約を示唆していると考えている。
言語の設計者は、こういった論法によって、ある種のものは許可されるべきではないという考えを主張します。もし、あなたがこの種の主張の例をみたければ、このBeuce Eclel氏のBlogのメタプログラミングのセクションを見ればよいでしょう。
Feathers氏は、セーフティネットを用意するよりは、責任という倫理を推し進めている開発者たちを信用するように主張している。こういったことが、Rubyコミュニティに存在すると彼は信じている。
いくつかの言語では、ある種のことはとても危険なのでそれらを禁止して、機能の乱用を防ぐためのツールを持つべきだというように言語の設計者が考えているように感じられるでしょう。結果として、コミュニティ全体は、多くの時間を規範的なアドバイスやワークアラウンドに費やすこととなります。もし言語が、人々が慣れしたしんでいる方法で行えるような全ての方法を提供しないなら、彼らは激怒することでしょう。
私は、このことを単にRubyの文化だといっているわけではありません。
Rubyでは、想像可能なほぼ全てのことができます。ライブラリの中のいかなるクラスも変更できますし、アスペクト的な振る舞いを織り込むこともできますし、メタプログラミングを使って正気とは思えないようなこともできてしまいます。言い換えると、全てはあなた次第なのです。もし、なにか悪いことが起こったとしたら、自分自身を責めればよいのです。機能を追加しなかったからといって言語設計者を責めることはできません。なぜなら自分自身で機能の追加ができるのですから。言語設計者があなたの足を引っ張ると責めることもできません。なぜなら、そんなことはしていないのですから。
ではなぜ、もっと多くの人が、ひどい失敗で崩壊したり、まる焦げになったりしないんでしょうか? 私が考えるに、もっともな理由があります。なんでもできるときには、より責任をもたなくてはならなくなるのです。自分の運命を自分で握る。そして、それこそが責任を促進する状況だと考えます。
Coda Hale氏は、Rubyコミュニティが責任に関して、よりよい意識をもっているのではなく、ある種の寛大さをもっているのだと考えている。
私もRubyが責任の文化をもっていると信じたいです。しかし、私はそれは正確でないと考えています。いままで、サード・パーティのライブラリが、他の人が実行中の
NilClass
をブラックホールにしてしまったり、alias_method_chain
をメソッドシグネチャを完全に複製することなしに使うことで、問題を起こしたRubyアプリケーションを数多くデバッグしてきました。毎度、問題を起こしているライブラリの作者に問題を直すよう説得するのに骨を折ります。また毎度、ライブラリが修正されるまで、自分自身でホットパッチを書いてコードを修正しなければなりません。これは前向きな意味での責任ではありません。「あなたが直さなければ他の誰も直さない」という意味での責任です。私は、Rubyが責任というよりも、寛容の文化をもっていると考えています。全てのものを受け入れることができるという意味では、他のライブラリが悪さをすることに文句を言うよりも、独自の悪さをするあなた独自のバージョンを書くべきです。
Niclas Nilsson氏は、開発者に自由を与え、責任を感じさせるべきだという点でFeathers氏に同意している。
これは何らかの理由で、様々な文脈で、常に行き着く議論です。「それは危険ではないですか?」と聞かれ、私がよく答えるのは、「そうですね。しかし車やナイフ、薬も一緒です。」便利なものは、ほとん全て誤用される可能性があり、実際に誤用されることもあるでしょう。しかし、私たちはめったにそんなことをしないし、そんなことをしてもすぐに正しいやり方を覚えるのです。しかも、ソフトウェアにおいては、他と違い、やり直しが可能なのです。
私は、代償としてプログラム言語の力が削がれるのであれば、(誤った)防御に対して代償を払いたくないのです。その防御は、何らかの方法で回避できるのですし。Javaでは、実行時にクラスを変更することが想定されていません。これを回避するために、バイトコードの変更を行う必要があります。しかしそれは、コストが高く、複雑なのです。それよりも、私は責任や論理的なミスから自分自身をまもるために私が用意する習慣やセーフティネットを信じたいのです。
自由と責任は関連しています。
Keith Braithwaite氏は、ユーザーを甘やかさず、ユーザは落とし穴をさける方法を学んでいたLispコミュニティの例をあげた。
Lispコミュニティの歴史からどのような教訓が得られるのでしょうか?Lispは(Smalltalkやアセンブラと同様に)、ユーザを甘やかすことは決してありませんでした。LISPプログラマが、いかに自主検閲するようになり、ある種のテンプレートによる利口さを不適切なものだと考え、そういった利口さを他の人に押しつけないように気をつかっているかをDick Gabriel氏がある雑誌で語ったことを思い出します。彼らはほとんどどんなことでもできた(そのようなコードを書くことができた)のですが、ある種のことは選択しませんでした。
Glenn Vanderburg氏は、言語が制約を設けても、開発者がミスを犯すことを止められないと考えている。
能力の無い開発者は、どんなことをしても、まずいことをやってしまうんです。鋭利なツールを取り上げたところで被害をくい止めることはできない。かれらは、鈍器をより激しく振り回すだけです。
もし、チームに優れた仕事をなしとげ、決断に責任をもってもらいたいのであれば、パワフルなツールを与えましょう。
新参者は防御機構が必要だと感じるが、経験を積むにつれて、それらを取り除くたいと思うようになるものだとAslam Khan氏は考えている。
多くの人(言語設計者)は、人々はコントロールされる必要があると想定しています。実際、新参者は、あらゆる種類のセーフティネットを危険のあるところに張り巡らしている、ルール/レシピ/定型句にもとづいた学習方式と言語を好むのです。しかし新参者は、いつまでも新参者ではなく、それらの制約はやがて押しつけがましいものになるのです。
Ward Bell氏は、人々はそれほど責任感を持っていないという見解をもっている。
魅力的な論拠です。責任と学習というものに対して誰が反対できるでしょうか。しかし、長年にわたり既存のコードを読んできた経験からいうと、責任感をもっていない人々もいるし、しばしば、私たち自身は、だらしなくなります。Rubyは私たちの気質をかえたのでしょうか?
私は、70年代から80年代にかけてAPLを使って商業用のアプリケーションを書いていました。とてもダイナミックでした。他人の書いたコードを書き換えるのはたやすかったんです。新しいAPLを文字列として書いて、それをソーン演算子によって実行することができました。エラーの補足や警告を行うインタプリタのサポートは貧弱でした(コンパイラは存在しませんでした)。
何とも見事な混乱を私たちは作り上げました。ほぼコードを書いたとたんに、修正が行われたのは素晴らしいものでした。しかし、誰かが書いたコード(自分が書いたものも含めて)読むのは、忌々しかったのです。
どんな言語をつかっていようとも、開発者は最低になりえるので、真に重要なのは、言語ではなく姿勢だとT. Powell氏は考えている。
どんな言語をつかっていようと、大馬鹿ものにも素晴らしい存在にもなりえます。そう、言語は物事に影響をあたえて、設計者やコミュニティの存在を感じることでしょう。しかし、どんな言語を使っていても大馬鹿ものになりえるのです。Javaを使っていようと、Rubyを使っていようと、Fortranを使っていようと。
制約のない言語で開発者を信用するのがよいのか、それともセーフティネットを設けた方がよいのか、あなたの見解はどちらでしょうか?