Web2.0の盛り上がりとともに軽量言語が存在感を増している。軽量言語(Lightweigt Language)とは、重量級と呼ばれる言語と比べて簡易に開発できるPerl、Ruby、Python、PHPなどのスクリプト言語を指す。軽量言語の特性としては、インタープリタ言語であること、動的型をサポートしていることなどが挙げられる。
一方、“重量級言語”の代表格は C/C++、Javaである。Web2.0以前は、普通の企業システムはこれらの「重い」「堅い」言語で作るのものというのが日本のIT業界の常識だった。理由としては、軽量言語には、実行速度が遅い、スケールアップが難しい、システムが大きくなるとメンテナンスがしにくい、エンジニアが少ない、大人数での同時開発に不向き、などの欠点があったからである。一人のエンジニアが短期間でとりあえずのシステムを構築するようなケースでは重宝しても、顧客向けのサービスや、受託開発するシステムの言語として選択するにはリスクがあり、はじめから選択肢に入らない、という傾向が強かった。しかし、この流れが覆りつつある。
中でも目を引くのは、Ruby on Rails (以下、RoRと略す)の成功である。RoR はRubyによるWebアプリケーション開発フレームワークで、David Heinemeir Hansson氏 によって 2004年7月に発表されて以来、人気を集めている。海外での成功を受け、日本でも2006年には非常に注目され、活用事例が増えてきた。有名なところでは、2007年3月に楽天が採用を発表している。
RoRの登場、盛り上がり、軽量言語の台頭の背景には、2つの重要な時代の変化がある。ひとつには、ハードウェアが進化し、安く、速く、大容量になった点だ。処理速度の遅い軽量言語でWebアプリケーションを構築しても、それなりに軽快に動作させることができるようになった。
もうひとつは情報システムに求められるニーズの変化である。結論からいえば、短納期化・低コスト化の圧力が強まり、さらに、Web2.0的な意味での高品質化が求められることが多くなっている。システムの短期構築は変化の速い世界で競争に勝つために必要であり、低コスト化はビジネスの変化が速くなりシステム寿命が短くなったことに呼応する。Web2.0的な意味での高品質化とは、例えば、ユーザーが参加できるように設計されている、効果的・魅力的なUIを備えている、他サービスとの間で機能・データを利用・提供できる、Webアプリケーションとしてのセキュリティが安全である、といった特徴を指す。このようなニーズの変化が、軽量言語の価値を相対的に上げているもうひとつの要因であると思われる。なぜなら、軽量言語はそもそもプログラマが楽に手早く開発できることを重視しているのが特徴なので、基本的に短納期、低コストに向いているからだ。Web2.0的な意味での高品質化と軽量言語は一概には結びつかないものの、プレゼンテーションレイヤーで凝った処理をする場合の開発効率が概して良い、ちょっとした変更や新機能の追加が素早く行えるといったメリットが役に立つ傾向があるように思われる。
こういった軽量言語への追い風はあるが、単に軽量言語を使ったからといって、短納期・低コストでのWebアプリケーション開発、あるいはWeb2.0的技術の活用、システムの小刻みな改良、などが達成できるわけではない。Webアプリケーションは様々なレイヤーから成る複雑な構造物であり、昔ながらのCGIをスクリプト言語で書くといった原始的なやり方では、ソースコードがすぐ煩雑になり、ある程度以上の規模のアプリケーションを構築し維持していくことは難しい。
前述のRoRは、こういった従来の軽量言語だけによる開発とは一線を画しており、むしろ、重量級言語による企業Webシステム開発のノウハウを詰め込んだ開発フレームワークを、軽量言語、具体的にはRubyという技術要素を使って実現したという言い方ができるだろう。
RoRはしっかりしたMVCモデルでWebアプリケーションを開発できる本格的なフレームワークである。RoRの登場以降、Java、Perl、PHP、Python、.Netなど多くの言語で、RoR の影響を受けたとされるフレームワークが登場していることからも、フレームワークとしての RoR が画期的かつ効果的であることがわかる。
RoRのコンセプトのひとつに「Convention over Configuration(規約は設定に勝る)」というのがある。これは、設定ファイルを各種揃えないと動作しないという以前の状況(RoR以前のJavaでの開発に顕著だった)への反発から生まれた着想だと思う。RoRでは、ユーザーは必要最小限の設定だけをすれば良いようにデザインされている。それ以外の部分については規約がデフォルト設定と結びついているために、規約どおりに開発する場合には設定は不要だ。
一例をあげれば、O/RマッピングのRubyクラス名が Order(注文)でDBテーブル名がOrders(注文の複数形)というように、名詞の単数形と複数形の形になっていれば、両者の関連性の記述をユーザーはどこにも書く必要がない。定義がなければテーブル名はクラス名を複数形にしたものだと仮定されて処理が行われるからである。同様に、DBテーブルのプライマリキーがidという名前なら、ユーザーはプライマリキーについてどこにも記述する必要がない(さらにいえば、どこにも明示的にidと書かなくてもDBテーブルに自動発番のIDカラムが用意される)。
モデル層以外にも規約が効果を挙げている例は色々ある。例えば、デフォルトではコントローラクラス名とメソッド名が自動的にURLとマッピングされるので、デフォルトどおりでよければ自分でURLのマッピングを定義する必要はない。
なお、こういった規約と異なる設計を採用したい場合は、自分で設定を書けばかなり自由に設計することができる。ただし、規約に従うほうが明らかに生産性が高いので、大部分は規約に従っておいて、既存DBの再利用などやむを得ないケースや、プロダクトとしての完成度のためにデフォルト設定以上の質を求めるケースにおいて独自の設定を加える、というやり方がお薦めだ。
規約は開発環境に関しても設定されている。例えばrails ではソースファイルをどのようなディレクトリ構成で格納すべきかが決まっており、プロジェクト作成時に自動的にディレクトリも用意されるので、構成について悩まないで済む上に、自然とMVCモデルに沿った開発ができる。
RoRの別のコンセプトとして「DRY(Don't Repeat Yourself、重複したコードを書かない)」がある。RoRにはDRYな開発をさせるための工夫が色々ある。例えば、まず前提として、ライブラリの充実(例えば、細やかな Validation ヘルプメソッド)によって、Webアプリケーションでよく必要になるコードは極力自分で書かなくていいように用意されている。また、MVCフレームワークが良くできていて、ある種のコードをどこに書くべきかが判断しやすいので、気づかずに複数箇所に書いてしまっていた、ということも起こりにくい。また、RoRのベースであるRubyは、コードの集約に関して非常に強力な言語である。(例えばModuleのMix-inを使った多重継承的な設計もできる。)そのため、従来のフレームワークにありがちだった、同じ処理やデータを2回以上記述しなければならないような(そうしたほうがマシと思えるような)技術的制約はなく、エンジニアは安心してDRYを推進できる。
今まで述べた2点はいずれも、コード量を減らすことに直結する特色である。コード量が少ないということは開発が早い、生産性が高いということであり、RoRのもっとも特徴的な一面であると思う。
技術的な要素で特筆すべきはO/Rマッピングを行うActiveRecord(AR)である。ActiveRecordという概念はRoRのオリジナルではなく、エンタープライズアーキテクチャパターンとして知られていたもので、ドメインモデルのクラスとテーブルが基本的に一対一に対応し、DBアクセスとドメインロジックの両方をモデルクラスが受け持つデザインを指す。RoRのARはこのパターンを独自に発展させた実装となっており、徹底した自動化と高い柔軟性に大きな特徴がある。
自動化の例としては、ARでは、DBスキーマを設定ファイルから読むのではなく、DBそのものからスキーマを取得する。また、カラムへのオペレーションメソッドはスキーマをもとに動的に自動で作られる。これは非常に強力な仕組みで、新しく作るときはもちろん、変更時に大きな威力を発揮する。例えば、システムをバージョンアップするときにDBにカラムを追加するというケースがよくあるが、ARでは、実際に変更が生じたDBと画面だけを変更すれば、連動して変更が必要な中間レイヤのARは自動的に変更に追随してくれる。エンジニアはそれだけ機械的な作業をしなくて済むのである。
柔軟性に関する特色としてはコールバックが挙げられる。オブジェクトの取得、検証、保存などの重要なイベントの前後に呼ばれるコールバックメソッドに独自の処理を記述することで、ドメインモデルとDBデザインのギャップを埋めることができ、複雑なビジネスロジックにも耐える設計となっている。
コールバックについて、Order(注文)モデルをつかった具体的な例で説明してみよう。ある種の顧客についてだけ、発注が保存される時点で自動的に対応するBill(請求書)モデルを作って保存しておきたい、という要件があったとする。これをコールバックを使わないで実装することもできるが、別のプログラマが別の画面から注文を保存するコードを書いたとき、うっかりこの制約のことを忘れる危険性がある。コールバックを使うと、インスタンスのsaveメソッドの実行に伴って確実に制約を処理できる。また、コードが適切に隠蔽され、将来、同じような記述が重複することを防ぐという点で優れている。
このほか、開発に必要なライブラリがツールも含めすべて含まれている(フルスタックである)点も重要だ。RoRには、O/Rマッピング、HTML出力のためのテンプレート機構、Ajax関連ライブラリ、アプリケーションサーバ、単体テスト、DBメンテナンス機能の自動生成機能などが同梱されている。高度な知識・経験がなくても間違いなく開発環境を構築できるため、すぐ開発に着手できるし、後になってライブラリの選択ミスに悩まされるといったリスクもない。また、環境が均一になるため、一度覚えてしまえば、あらゆるRoRプロジェクトをすぐ理解できるというメリットもある。
また、開発・テスト・本番の3種類の環境が用意されていて、それぞれの目的にあったデフォルト設定がされていることも非常に行き届いている。
このように、RoRはWebアプリケーション開発の生産性・開発の各工程を総合的にケアするカバー力というフレームワークの基本的な部分で優れており、短納期・低コストでの企業システム構築という時代のニーズにマッチする。次節では、Web2.0との相性という点で、さらに特徴を紹介する。
Web2.0の重要な技術要素としてAjaxがあるが、RoRで典型的なAjaxアプリケーションを開発することはとても簡単だ。RoRにはPrototype.js をはじめいくつかのJavaScriptライブラリが含まれており、これらをRoRのライブラリを介して利用できる。典型的な処理の例としては、あるボタンが押されたらページの一部を書き換えるとか、observer処理(特定のフィールドを監視しておいて、値が変更されたらある種の処理をするもの。例えば入力欄に打ち込まれた一部の文字をみて補完した候補を表示するなど)などが挙げられる。
一般に、複数の言語を混ぜて開発するとソースが見にくい、メンテナンスしにくい、技術者が限られるといった問題があるので、Ajax関連のJavaScriptソース生成の多くをライブラリがカバーしてくれることはとても有用だ。ただし、筆者の感触としては、うまく動作しない場合の原因追求や、アプリケーション個別の事情への対応、あるいは単純な話だがAPIドキュメントをきちんと理解するために、JavaScriptやJavaScriptライブラリのAPIについてある程度の知識は必要と感じる。
また、Ajaxには、サーバサイドからみると、ユーザーのアクションと直接関係のある処理だけを切り出すという特徴がある(旧来のWebアプリケーションでは、再表示するページ全体のための処理をサーバサイドが行う必要があったことと対比してほしい)。DRYな実装のしやすいRoRでは、Ajax用の処理と一般リクエスト用の処理でソースコードを徹底的に集約でき、かえって設計がシンプルになる効果もあるように思われる。
Webサービスに関しては方式によって開発のしやすさが異なる。まず、RESTであれば、提供側は通常の機能と同じ形で開発するだけであり、呼び出し側も単なるHTTP接続として簡単に記述できる。SOAPまたはXML-RPCの場合は、RoRにActionWebServiceというライブラリが用意されており、最低限の手間でサービスを記述することができる。クライアントとしてSOAPのサービスを呼ぶ場合はRubyの添付ライブラリ、XML-RPCのサービスを呼ぶ場合は標準ライブラリでそれぞれできる(ただし、SOAPの場合はある程度複雑になる)。
このほか、SQLインジェクション、CSFRなど、一般に知られているWebアプリケーションのセキュリティ問題が考慮されていて、対策の手段が用意されているのもRoRがWeb2.0に向いている点に挙げられよう。(注:CSFR対策はRoR本体ではなく Security Extensions Plugin によって実現できる。)
また、Web2.0では、システムを頻繁に更新するが、この点についてRoRの利点として挙げられるのが、DB変更がしやすいという点である。従来、DB変更はコストが高いため、スキーマを最初に慎重に決めて、以後はなるべく変えたくないというエンジニアが多かった。しかし、ニーズに応じて積極的にシステムを改良するには、当然DBスキーマも変更の必要が出てくる。RoRでは、前述のようにARが強力なため、うまく設計・実装していれば最少限のコードでDBスキーマ変更にシステムを追随できる。また、migrationという仕組みがあり、DBスキーマの変更の差分を共通の方法で管理できる。そのためDBスキーマに変更があったときに開発環境に取り込むのが非常に簡単で、差分の理解、最新版のシェアに何の苦労も発生しない。この点は、アジャイル開発や頻繁な機能改良をするケースにおいて、大きなアドバンテージと言える。
このように、RoRではWeb2.0の主要技術を比較的簡単に使うことができ、例えばマッシュアップアプリケーションを作るのにも向いている。一方で、RoRは基本的に開発の生産性が高いので、Web2.0的なアプリケーションをスクラッチで開発する際に特に有力な選択肢となることだろう。
最後に、企業情報システムへの採用判断のポイントについて述べておこう。
RoRを企業情報システムへ採用する場合の利点としては、これまで述べてきたように、生産性が高いこと、Web2.0の主要技術を使いやすいこと、変化への対応に強いことなどが挙げられる。それらの相互作用により、アジャイル開発でユーザーニーズを素早くシステムに反映できるという効果を特筆しておきたい。開発時の待ち時間が少なく変更の容易なRoRでは、ユーザーが開発者の隣にいて、目の前で画面や機能を変更して感想を聞くといったことが本当に実現できるし、そういう時の開発速度と品質には驚くべきものがある。(注:別の観点では、要求開発のためのツールとして活用することもできるということになる。)ただし、実現のためには、当然のことながらまず、ユーザーか、少なくとも仕様決定者が開発現場に常にいる必要がある。
仕様決定者が現場にいることは、純粋に開発者の生産性を高めるという観点からも重要だ。RoRでは、無駄なコードを書かずに済む。言い換えれば、より本質的なコードだけを書くことになり、“何を作るか”を頭に浮かべながら同時並行的に設計・実装していくことが可能である。(ちょうど、ワープロと高速なタイピング能力が、“考えを即座に記録する”ことを可能にしたように。)一般的に、実装するために要件を細かく具体的に考えたり、作ったものを実際に動かしてみたタイミングで、これまでに考えられていなかった問題や新しい選択肢に気づくことが多いが、このときに仕様を決める人間がはるか遠くにいていちいち確認をして返事を待たなければいけない状況では、その場しのぎの実装をして後からなおすというサイクルを繰り返すしかなく、重量級言語で機械的なコードを書きながら進んだのと同程度の生産性しか達成できないということになりかねない。RoRの素晴らしい生産性を活かすためにも、仕様決定のできる人間が開発現場にいて即座に対応できる体制を用意すべきである。
一方、採用にあたっての課題もある。まず挙がってくるのは、パフォーマンスや大規模化への対応である。RoRは、比較的規模の小さい、時々はシステムを停止することのできるようなWebアプリケーションでの採用には最適だが、厳格な安定稼動、極端に大量のリクエストの処理などは比較的苦手と言える。企業がRoRを採用する際には、システムの要件にあわせて判断、工夫する必要がある。なお、RoRの運用環境として現時点で代表的なのは FastCGI + Lighttpd と Apache + Mongrel だが、新しいものが次々と出てくる流動的な状況にある。一部には、JRubyを使い、Javaのステージング技術によってエンタープライズ対応をする試みもある。このように活発な動きがあるということは、RoRの企業利用が認知されてきたことの表れであり、この分野の状況が、今後改良されていく流れにあることはまず間違いがないだろう。
次に、技術者の確保のしやすさという観点がある。現時点では、日本でRubyの経験豊富なエンジニアを確保することはJavaや.Netに比べて格段に難しい。筆者は複数のRoRプロジェクトに関わっているが、チームメンバー全員がRuby初心者だった。それではRuby技術者が少ないからRoRを採用できないかというと、そんなことはない。例えばJavaを経験していれば、Rubyは比較的入りやすい言語で、数日でとりあえず書くことはできる。ただ、うまく書けるようになるには1ヶ月~3ヶ月くらいはかかるように思う。RoRを使うにあたっては、Rubyだけでなく、WebアプリケーションやMVCフレームワークの基本的な理解も必要で、逆にいうとそれがわかっているエンジニアであれば、RoR未経験者であっても習得は早いだろう。
RoRで作った場合のソフトウェアの品質をどう確保するのかということを心配する向きもある。特に、Rubyがインタープリタであり、コンパイル時にコードを事前チェックするようなタイミングがなく、ビジネスロジックの不備から変数名のタイプミスに至るまで、すべての間違いが実行時のエラーになる点が心配の種であるようだ。また、変数に宣言が不要であったり、動的型であることから、IDE(統合開発環境)によるプログラミング支援に限界があり、変数名やメソッド名の自動補完が利用できない、タイプミスが検出されないという不利な側面もある。(注:筆者は、将来より賢いIDEが出現する可能性に期待している。)
これについての対策は、自動テストケースを十分に用意することが基本となる。自動テストが主要な処理をカバーしており、日々実行されてエラーがない状態に保たれているならば、変数名のタイプミスなどコンパイル時にチェックされるような低次元の問題が主要な箇所にはないということの確認になる(もちろんビジネスロジックが正しいことも保証される)。RoRではあらかじめ Unit、Functional、Integrationという三種類の自動テストツールが用意されている。さらに、DBに入れるべきテストデータをわかりやすく記述できる fixture という仕組みもあり、手軽に自動テストを開発できる。
自動テストに加えて、コードの書き方を工夫する余地もある。例えば、Rubyではメソッドの引数について言語による型のチェックはなく、実際に何かのメソッドが呼ばれ、それが見つからなかった時点ではじめて実行時の例外が発生するので、型チェックに慣れた開発者は不安を感じる場合もあるかもしれない。経験的には、間違った引数が渡されることを防ぐために一番重要なのは、引数名やメソッド名を適切につけることだ(前提として、開発者の間で概念とクラスの対応が合意されている必要があるが)。それだけでほぼ引数の型のミスマッチは発生しない。ただ、時には引数の特性について宣言的に記述しておきたいこともある。例えば、引数が具体的なクラスやModuleのインターフェースを備えていることを前提としている一方で、対象外のオブジェクトをメソッドに渡される危険が高いような場合だ。そんな場合は、メソッドの冒頭で自分で引数を検証し、問題があればわかりやすい原因を記した例外を発生させると良い。
なお、IDEでメソッド名や変数名の自動補完やチェックをしてくれないという点についても、実は、コードの書き方で影響を少なくすることができる。とにかく全てにわかりやすく簡潔で統一感のある名前をつけることが重要だ。そうすればメソッド名を覚えたり推定したりして手早く書けるし、間違っていてもすぐ気づくことができる。
別の懸念として、RoRは大人数での開発に不向きなのではないかとの声も時々聞く。その根拠は、品質確保に関する不安や、コンパイル時のチェックを通じて他者の設計・実装範囲を限定できない点にあると思われる。品質については、前述のとおり、単体テストを十分に作れば大きな問題はない。言語による制約が少ないことに関しては、全般に良い名前をつけ、必要なら自前で制約をかけるようなコードを書き、さらに設計方針をうまくコメントに残す、といった作法を守ることで、制約の多い言語並の共同作業効率を保つことができる。筆者の場合、10人くらいまでの規模のプロジェクトをRoRで開発しているが(うち数名がオフショア開発というプロジェクトもある)、特に並行開発がしにくいという印象はない。
開発人数については、おそらく20人でも30人でも100人でも、RoRで並行開発すること自体は可能であると思う。しかし、繰り返し述べていることだが、RoRを使って複数の開発者で効率よく開発するためには、以下の前提が必要である。
この前提の達成と人数はトレードオフの関係にあるように思われる。人数が増えるほどと、上記の条件を満たすことは難しくなっていく。私見では、自然に上記を達成できる開発人数は5人程度である(自然といっても、各自が黙々とコーディングする環境ではだめで、コミュニケーションによってスキルを補完しあいながらコードをよい状態に保ちながら進むという良い雰囲気が醸成されている必要がある)。それ以上の人数で開発する場合には、開発ユニットを分割する、スキルが高い技術者を多く投入する、開発者間のコミュニケーションを意識して増やす、コードをきれいに保つための工数を計画に多く入れる、などの対策が必要になるだろう。
まとめると、RoRは現時点ではパフォーマンスや大規模化が比較的苦手という側面はあるものの、その特性を理解して適切な開発体制を組めば、非常に素晴らしい生産性を実現できる強力なフレームワークだ。目的に応じて上手に活用していきたいものである。
本頁の著作権: Copyright (c) XML コンソーシアム 2007 All rights reserved. Copyright (c) メタデータ株式会社 2007 All rights reserved.