Edited at

Railsが時代に合わなくなってきた

More than 5 years have passed since last update.

追記

RailsでJS辛い問題に関しての結論:http://qiita.com/kaiinui@github/items/dad6180f1910c6a4bfd5

--

近年、(1) Web/App両対応が増えてきたこと、(2) WebでもJSを多用するようになったこと、の二つがあり、以下の点でRailsが微妙になっている。


  1. ViewのJavascriptがRailsから独立している

  2. API層のサポートが微妙

最初に書いておきますが、特に決定的な解決策もなく、辛いから今後解消されてほしいよね、な話です。


ViewのJavascriptがRailsから独立している

Railsはとても堅牢。

モデル、コントローラ、ルーティングと、変にいじらない限りはほとんどテストが要らない。

必要なのは、モデルに新たにpublicメソッドを付けたときくらいだろう。

実際、バックエンドはそうそうバグが出ない。

テストも最低限に抑えられていると感じている。

しかし、最近はViewをJavascriptが支配するようになってきた。

JSが無ければViewが適切に動作しないほどに。

ここで残念なことに、Railsは全くJSの世話を見てくれない。

だからか、おおよそ殆どの問題がModel層とJSの不協和で起こる。

計測したことがないから正確には分からないが、少なくとも、Viewが開発/Fixの大部分を占める。

JSがRailsから独立してしまっているからフレームワークの恩恵が受けられず辛い。

モデルを扱うViewModelかControllerに相当するようなコードがViewの中にも入ってしまっていて、DRY/SRP等クソ食らえ状態。

もちろん、テストもしにくい。

Capybaraでpoltergeistなんぞ回してテストしている気分になるのが精一杯だ。

つくづく、Railsは、Railsで閉じていない開発をするのが苦手なのだと感じる。

根本的に、フレームワーク側でViewのJSとModelをグルーしてくれないと、そろそろ辛い。

何が辛いかというと、別にグルーを書くのが辛いのではなく、ちゃんと動いていることを確認するのが辛い。

せっかく結合部分をフレームワークに全任せしているのに、ここだけ原始時代に戻ったかのようだ。

View開発の比重が増してきたから、裏側だけが良い感じに書けても嬉しくなくなってきた。


API層のサポートが微妙

Appにも対応するためAPIを公開したいが、RailsのAPI対応はとても微妙。

Grapeもいいけど微妙。

なんだか、同じことを何度も書かされているような気分になる。

というか、Webを受けるControllerと、APIを受けるController/Grapeを書くのがあからさまに被っている。

確かにちょっと違うことを書いているのだけど、実質は同じ事を書いているはずだ。

まず、ここで同じModelを扱うコードが2つになってしまう。

次に、Railsに限った話ではないけど、サーバもクライアントもAPIを扱うコードを書かなければならない。

クライアント側のAPIを扱うコードというのは、つまりAPIクライアントのことだ。

生URLを毎回叩くなんて正気の沙汰ではないから、ラップするなにかしらが必要で、APIを書く毎に毎回実装する必要がある。

もちろん、扱う言語毎に必要だから、iOSとAndroidをネイティブで書いていれば、APIクライアントは2つになる。

これで、同じModelを扱うコードが4つ。

4つ…DRYとはなんだったのか

(あっ、そういえばJSでも同じようなコードを書いているから、これで5つ!)

どうせRESTかそれに近い形でサーブするのだから、モデルから自動生成とか出来るはずなのだ。

しかし、それだけだと柔軟性がないからか、いまいち辛いし、実用もされてこなかった。

なにかしらAPIを拡張すれば、それだけで破綻してしまいそうになる。

GoogleのProtocol Bufferのような仕組みが必要だと感じている。

Protocol Bufferは、データ構造を定義する言語。

Googleはこれを使って、RPCなどインスタンス間でデータを受け渡しするコードを自動で生成しているらしい。

Protocol Bufferを使えばデータの受け渡しに齟齬がなくなるから、むしろこれを使わないデータ受け渡しを禁止している(らしい)

このような仕組みが有れば、RailsでAPIを書いて端末でそれに沿うようにAPIクライアント書いて…みたいなつらみが軽減されるだろう。

しかし、Protocol Bufferではまだ足りず、API Clientを生成するための諸情報が欠けている。

以上を鑑みて、いまのところ、RailsとかNode.jsらへんで扱うにはJSON Schemaがいいかなと感じている。

これに関しては、良いブログ記事があるのでこちらを参照。

http://r7kamura.hatenablog.com/entry/2014/06/10/023433

JSON Schemaの記法があまり洗練されていないように感じる。が、Modelから自動生成したり、足りないものはyard的な埋め込み型記法でフォローとか出来そうだから、問題ではない。

正直、APIを扱うことがかなり一般的になってきているから、このあたりのことはFW側で面倒を見てほしい。

APIのエンドポイントしかり、API Documentしかり。

あとは、Web上で簡単にAPIを試したり。

テスト用のリクエストを発行して、レスポンスを確認出来る、みたいな。

近い将来、これらの機能はFWに標準装備されてほしい。

これらの機能は、APIにおけるscaffoldみたいなものだから。

APIをフレームワークで扱う機能が薄いために、RailsはAPIを扱うところで様々なつらみがある。

Railsで閉じる開発が快適すぎるだけに、本当に辛い。


ViewでJSを書くのが全体的につらい

(あまりに辛いために、もう一度同じようなことを書く)

先述の通り、JSがRailsから信じられないほど独立している。

「設定より規約」がJSにおいて、全く機能しない。

せっかくMVCが綺麗かつ簡単に書けているのに、JSだけ昔のまま。

Viewの何かしらのclassを付け外しするだけでバグが出るのはざらである。

これを受けて、jsで扱うclassは特別なprefixを付けている開発者も多い。

しかし、これは各人のローカルルールであり、Rails的な「規約」というわけでもない。

独立しているばっかりに、DRYを守りにくいのもある。

Railsからデータを貰う部分だったり、渡す部分だったり。

Rails+JSで書いたコードは、少なくともどこかがDRYでないはずだ。

テンプレートが2重になることなど、日常茶飯事だ。

また、JSがControllerあるいはViewModelのような役目を担ってきているため、Viewコードが全然Pure Viewでない。

SRPなど無いがごとくだ。

フレームワーク/Model層とイイ感じに調和するJS記法が必要であると感じている。(イメージが全然湧いていないけれど)

せっかくHTMLをRailsでイイ感じに書いているのに、JSでそれを汚すのは辛い。

FW側でイイ感じにそれらを統合するような、透明なJS記法が必要だ。

二重MVCを避け、テンプレートを統合し、js routingもイイ感じに面倒を見てくれるような。

イイ感じと書きまくっているけど、それだけイメージが湧かない。

漠然と、プリプロセッサのようになるのではないかと思っている。

あるいは、既存MVCと高レベルに結びついたView記法とか。

とにかく、Railsから独立しちゃってるJSの見通しが悪い。


ならSPA?

SPAは全体的につらぽよすぎるので書きたくないし、クローリングとかi18nとか考えていくだけで破綻が間近なので、やりたくない。

いくらRailsでJS辛いといっても、快適なRailsに乗りたい。

また、各ページにURLを提供することはWebの基本であり、これを逸脱することは避けたい。

クロールの問題もある。

SPAをやると、URLをどうにかして提供せねばならず、結局RailsのViewを使って二重テンプレート…みたいなことになり辛い。

結局RailsとJSつらぽよ問題に悩まされることになる。


結論

Ruby on Railsは、URL => HTML => Resourceの単純なモデルに深く結びついている。

だからこそ、各要素のハイレベルでの統合を果たしており、Railsの実現する記法は美しいほどだ。

この記法がWeb開発に与えた影響は計り知れない。

実際、自分もRailsのファンであり、足を向けては寝られない。

しかし、デザインの基となったモデルが単純だからこそ、今となっては時代遅れの部分が出てきてしまっている。

原因は、冒頭の通り (1) Web/Appの両対応が普通になってきたこと (2) WebでもJSを多用するようになったこと

この二つが、


  1. RailsはJSをフレームワークレベルで統合していないために、JSが独立してしまう。従って、Railsの恩恵を受けられず、しばしばバグの原因になる。

  2. RailsはAPIをイイ感じに扱う術がないために、API開発でつらみがある

  3. そもそもRailsのViewのJSをテストする術が貧相であり、E2Eテストがしばしばすっぽかされる

以上の問題を引き起こしている。

とはいうものの、これは現時点では解決策が弱く、今後解決されていくであろう(かつ、していきたい)問題である。

これらを解消するような、JS/APIを深く統合したようなフレームワークが今後台頭するだろう。(してほしい)

どれほど掛かるかは分からないが…

Railsのコード資産を考えると、とても時間がかかりそうだ。

問題提起として、というか、うらみつらみが書きたかったため書いたので、結論は特にない。

ちなみにRailsは大好きです。

JSON schema周りのツールセットにcontributeしたい人は是非contributeしましょう。

自分も何かしら書くつもりです。


代替案?

決定的なものは一切ありません。

今、想像/妄想したものを書きます。

まずは、そもそも自前のバックエンドを持たないことが、APIの面倒さへの解決案に成り得るし、実際流れとして存在する。

インフラの面倒も解決され一石二鳥。

というわけで、


Parse

https://parse.com/

APIのつらみを解消するためにうってつけ。

Mobileのバックエンドとして要求しうる殆ど全てを備えている。

標準のAPIクライアントも文句が付けにくい。適切にラッピングすれば、流れるようにコードが書ける。

また、問題になりそうなWeb対応だが、実は、RailsでもParseは利用出来る。

https://github.com/adelevie/parse_resource

これは、文字通りActiveModelのバックエンドとしてParseを用いるというもので、Mongoidに近いインターフェースを持っている。

まあ実際は、まだ開発途上で、開発者もメンテナンスする時間が取れないと言っているため、難しいところはある。

ActiveRecord, Mongoidと比べればまだまだ残念であることは否定出来ない。

しかし、コンセプトとしては、検討出来る構成ではないだろうか。

(JSのつらみは全然全く解消されないので、実際のところあまり辛さは解消されないし、WebのバックエンドとしてParseを使うのは先進的すぎるから、まだコンセプトレベル)


Firebase

https://www.firebase.com/

JSだけでイイ感じにアプリケーションをつくりたいとき、リアルタイムとデータベース格納の問題を同時に扱え、かつバックエンドも持たなくて良く素晴らしい。

Web用のParse.comという感じ。

特に、Rails + JS MVC + Socket.io という苦行におさらばしたい人は要チェック。

上二つは自分のデータベースでないし、自分の実装でないためプラットフォームに強依存することを覚悟して使わなければならないのは少し辛い。


Meteor

https://www.meteor.com/

ただただよくわかってない。

今回のうらみつらみはかなりの精度で解決されている、ように見える。

が、独特過ぎて良く分からないのも確か。

もう少し触ってみて書くかも。

どうでもいいけど他のフレームワークとか触ると結局Rails神なことを思い知らされる。


Rails + JSON Schema

Rails使っててもAPIのつらみだけでも解消したい。

だから、JSON Schema.

ただし、今の時点では、APIの自動生成等が出来ない。

iOSやAndroidのAPIクライアント自動生成なども、まだない。

要するに、発展途上であり、まだProduction useではない。

絶賛contribute募集中な感じである。

しかし、流れは有るので要チェックだし、JSON SchemaがAPI開発に与えるであろう影響は無視出来ない。

今まで個別に書いていたコードが統合され、しかもそれはコードですらなく、ただのJSONである。

これに魅力を感じないエンジニアがいるだろうか?

API周りが全然DRYじゃなくてフラストレーションを貯めているエンジニアは、要チェック。


Synth

これまで散々書いてきたが、実はほぼ理想的にこの問題を取り扱っているフレームワークがある。

Synth: https://github.com/JonAbrams/synth

Synthに関するinfoQの記事: http://www.infoq.com/jp/news/2014/06/synth

これは


  1. Node.jsベースであり

  2. クライアントサイドMVCにAngularを据え

  3. APIファースト(というかAPIしかない)であり

  4. Angularとフレームワークが統合されており、テンプレートが一つであり

  5. URLを適切なモデルにルーティングし、Angularに直接モデルを渡す

フレームワークであり、ほぼ理想的にこの問題に取り組んでいる。

が、まだあまり深く理解していないため、詳しく書くことは控える。

注目すべきFWだ、としか言えない。

一つだけ言えることは、今回のうらみつらみがほぼ理想的に解決されるアプローチを採っていること。


結局

誰かいい解決策があったら教えてください。

ところで

クライアントMVC大体重すぎて100KB以上してモバイルつらぽよなので、GmailみたいなAppCache使う重度のSPAじゃないと割に合わない感ある

あとテストしにくい

ところで日本語を直す編集リクエストを送ってくれる奇特な人は大歓迎です。

こぴー:http://kaiinui.com/drafts/2014-06-26-problem-of-rails.html

--

追記

JS問題に関しての結論: http://qiita.com/kaiinui@github/items/dad6180f1910c6a4bfd5