Locked History Actions

scala/ruby

Ruby対Scala

Javaの欠陥、Rubyの欠陥を埋めるものとしてScalaが選択されつつある。 ここでは特に、なぜRubyではだめなのか、他の方の言を紹介する。

一刻も早くJava から Ruby へ移行したいと思っていた。しかし、実際に Ruby で開発を行ってみると、そこには譲れないトレードオフがあった。Eclipse 上の Java コードは、死んだ文字列ではなく、呼びかければ応えてくれるオブジェクトだったが、Aptana RadRails 上の Ruby コードは、それとは程遠い代物だった。補完はまともに働かず、依存先へのナビゲーションや依存元の検索はインテリジェントでなく、リファクタリング支援は貧弱。これは、特定ツールの未成熟の問題というよりも、動的型付け言語のアイデンティティに関わる問題だろう。そして、Rails アプリケーションの実行速度は一般的に遅い。

私は気が付いてしまいました。Ruby の動的型付けは多くのエラーを引きおこすことに。そして、安心してデプロイ(リリース)するためには 95% ものテストカバレッジを達成しなければいけないことに。95% のテストカバレッジを得ることの代償として、私の書いたコードは(テストコードも含めて) Java で書いたものと同等のサイズにまでふくれあがってしまいました。その上、Rails(Ruby On Rails) では動的なコードの変更が可能なため、開発・テスト・デプロイ中にトラブルが続出するようになりました。高いテストカバレッジを確保しているにも関わらずです。これらの問題にくわえて、MRI(Matz Ruby Implementation: まつもとゆきひろ氏による Rubyの実装)は速度が遅く、言語仕様も安定していません。それなのに開発コミュニティはそのことに見向きもしません。私は他の言語も見てみようと思うようになりました。そんな時に Scala と出会いました。Scala を使ってみて、これこそが私が求めていた言語だと思いました。

「Scalaプログラミング入門」を読みはじめて、いきなり大きく頷いてしまった。

  • * "コーディング時間の半分をテスト作成に費やさなければならなかった"(p.3)
  • * "Rails(Ruby On Rails)によって得られた生産性の向上は、テスト作成の作業に失われてしまいました"(p.3)

まさにここ数年私が抱いてた漠然としたストレスの正体が、的確に文章となっていたからだ。そしてほどなく、「あ、この機能がRubyに欲しかった!」という驚きと共に Scala が本物であることに気付いた。さらに読み続けていくと、その驚きの回数は減るどころか、最後にはため息へと変わっていった。

動的型付の言語は、多めの人数で開発することに向かない面があります。

言語が「動的」なので、実行するまでコードに問題がないか分かりません。多めの人数で開発するときは、優秀ではない人も混じっていると思いますが、その人が他の人のコードに影響を与えるおかしなコードを書いたとしても、あくまで「実行時」にしか見つけることができないことになります。これはたくさん人数で開発するときに問題となってきます。

この点が、JavaやC#といった「静的型付け」の言語が持っている「メリット」です。

(Twitter開発者のインタビュー)

It began its life as a Ruby on Rails application, and still uses Ruby on Rails to deliver most user-facing web pages. But about a year ago they started replacing some of the back-end Ruby services with applications running on the JVM and written in Scala.

twitterはRuby on Railsアプリとして開始され、現在も(少なくとも2009年時点)ウェブページの生成に使われているが、一年前に彼らはいくつかのrubyによるバックエンドサービスのScalaへの置き換えを開始した。

Alex Payne(Twitter技術者):

Over time we found that although Rails works great for doing front-end web development, for doing heavy weight back-end processing, Rails had some performance limitations at runtime. And I think that—and this is more my personal opinion—the Ruby language lacks some things that contribute to reliable, high performance code, which is something we’re very interested in as we’re growing as a business. We want the code we write to be correct and maintainable. We want to keep our costs down—all the things most businesses want out of their stack. So that’s why we started looking at Scala.

Rails(Ruby On Rails)はウェブのフロントエンド開発や重いバックエンド処理に適切であったが、Railsはパフォーマンス制限のあることが徐々に分かってきた。僕は(僕だけの意見じゃないけど)Ruby言語は信頼性に欠けるし、高パフォーマンスコードの記述ができないと思う。それらはビジネスを成長させるのに必要なものだった。正しくてメンテナンス可能なコードが必要だったのだ。僕らはコストを下げる必要があった。Scalaを始めたのはそういう理由だ。

Martin Odersky(Scalaの作者)へのインタビュー

You still need unit tests to test your program logic, but compared to a dynamically typed language, you don't need a lot of the more trivial unit tests that may be just about the types. In the experience of many people, you need a lot fewer unit tests than you would in a dynamic language. Your mileage might vary, but that's been our experience in several cases.

もちろん、プログラムロジックをテストする必要はあります。が、動的型付け言語に比較すると、「型」についての些細なテストは不要になるのです。これは多くの人々の経験によりますが、動的言語に比較すれば、ユニットテストは少なくなるのです。あなたにとって有用な話かどうかわかりませんが、我々は様々なケースでこれを経験しています。

railsの作者の言

Ruby is about a culture, too. One of these cultures is testing. I found it pretty special when I arrived to Ruby in 2003 that there is such a focus on testing.

Rubyっていうのは文化でもあるんだ。そしてその文化の中の重要な要素としてテストがある。僕が初めて2003年にRubyにたどり着いたとき、Rubyコミュニティのテストを重視する姿勢がとても特別なものに思えたんだ。

It's not like Ruby invented testing, but there is a culture that really took it in, and made it part of the community core of this is what we do. We test software.

別にRubyがテストを発明した訳じゃないってことは分かってるけれど、Rubyにはテストがコミュニティの中心部まで根ざしているんだ。「ソフトウェアをテストするのが俺たちのやり方だ」ってね。

There is also another way not to do it. No, no, no. If you are going to be this crowd you have to test your software, otherwise you are not really in it yet.

テストをしないってやり方もある?チッチッチ、君が僕たちの仲間になりたいのなら君のソフトウェアにテストを書かなきゃ、でないと君はまだここまできてないってことさ。

私の意見~動的型付言語は使い物にならない

少なくとも巨大なソフトウェア作成では、動的型付言語は使い物にならない。 railsが流行ったのは、単に「簡単に、短い行数で、開発者が一人であっても」所望のプログラム作成ができたからであって、 おそらくは、たかだか一万行程度が限界である。 これらのスクリプト言語は、この程度の「さっと書いて、使った後は捨ててしまう」といった用途にのみ向いている。 これを超える、複数の人間で作成するような複雑なシステムでは動的言語は明らかに不適当である。これは以下の事実から導かれる。

  • 動的言語では「名前」の同一性が字面からは判断できない。
  • ソフトウェアは機能拡張されるものである。
  • 人間の記憶には限界がある。
  • プログラマは忙しい。
  • 完全なユニットテストを記述することは難しい。

一般にプログラムでは、メソッド名や変数が同じであるからといって、同じものを指しているとは限らない。 複数の人間が関わるのであればなおさらだが、一人の人間が記述したものであっても、同じ名前を使ってしまうことがよくある。 getXXXというメソッドを作成したとすると、他でも同じ名前のメソッドを定義してしまうことは十分にありうるのだ。

ところが、こんな簡単な事実が動的言語ではとてつもない問題を引き起こす。プログラムを眺めても(仮にコンピュータにそれをやらせたとしても)、このgetXXXメソッドを呼び出しているところがどこなのか判断がつかないのである。getXXXと記述してあっても、先のgetXXXというメソッドのことであるか、字面上での判断はできない。

ところがその一方で、ソフトウェアの機能拡張によって、getXXXの名称を変更したり、引数を変更したり、あるいはごっそり別の仕組みに入れ替えたりすることが起こりうる。これを字面だけの解析で行うことは全くできず、必ずすべてのgetXXXの呼び出し元をテストしなければならない。

もちろん、このソフトを一人の人間が作成したものとして、そのすべてのコードを覚えていれば問題は無いが、しかし一人の人間が、例えば数十万行ものコードを記述し、そのすべてを記憶していることなどありえない。

また、「プログラマはとても忙しい」のである。テストカバレッジ(ユニットテスト用プログラムによる、対象コードのカバー率)を100%にすることも非現実的である。おそらくは対象コードより大きい(おそらくは数倍)ものテストコードになるだろう。

つまり、巨大な「動的言語によるプログラム」は、それよりもさらに大きいユニットテストが必須なのであり、これはrubyの宣伝文句である「短く、簡単に書ける」というアピールとは裏腹のものである。もちろん、小さなプログラム~一人がすべてを記憶することのできる範囲ではおそらくこの宣伝文句は有効であるものと思われるが、複数の人間の関わるものあるいは巨大なプロジェクトでは全く成立しない。

このようなプロジェクトでは静的型付の言語を選択するほかはないのである。それも、その制限が厳格であればあるほどよい。 制限が厳格であればあるほど機械的な解析可能性が高まる。プログラマが「この名前とあの名前が同じものであるか」を悩む必要は無くなり、それらをコンピュータに肩代わりさせることができるのである。