Edited at

「Railsは終わった」と言われる理由


はじめに

Rubyは死んだ、Railsは時代遅れという人が最近増えてきたように思えます。

私自身RubyやRailsを書いて3年位経ちますが、「終わりつつあるな」と実感することが多いです。

そう思った経緯を記事に書いていきます。


Railsの特徴

Railsの特徴というか、流行した要因としては以下の5つが大きいと私は思っています。


  1. テンプレート、パーシャル、レイアウトをERBを使ってすばやく構築できる

  2. Active Recordによってデータベースを簡単に定義、操作ができる

  3. アセットパイプラインによってcss、jsを管理することができる


  4. チュートリアルが充実している

  5. Rubyという柔軟性の高い言語によって開発することができる

私はRailsはこの5本の柱によって支えられていると思っています。

これらの5本の柱のメリットにより、Railsは大流行しました。

すばやく簡単にプロダクトを作ることができ、チュートリアルが充実しているため、新人教育も簡単でした。

しかし時代の流れとともにこのメリットは以下のようにほぼ失われてしまいました。



  1. テンプレート、パーシャル、レイアウトをERBを使ってすばやく構築できる ReactやVue.jsによる保守性の高いフロントエンドが構築できるようになり使われなくなった


  2. Active Recordによってデータベースを簡単に定義、操作ができる これは今でも現役で使える!


  3. アセットパイプラインによってcss、jsを管理することができる webpackerなどによって置き換えられた


  4. チュートリアルが充実している 扱っている内容が段々と古くなってきており、時代に合わなくなりつつある


  5. Rubyという柔軟性の高い言語によって開発することができる 柔軟性が高いゆえに保守が大変。

今現在5本の柱のうち4本はすでに形骸化しつつあります。Railsを使うメリットはほぼActiveRecordの利便性のみです。

過去に比べてRailsの利便性が失われてしまった、だから「Railsは死んだ」と言われているのだと私は思ってます。

これらに要素について順番に解説していきます。


1. テンプレート、パーシャル、レイアウトをERBを使ってすばやく構築できる

RailsではErbをつかって以下のように書くことができます。

<% provide(:title, "ログイン") %>

<h1>Log in</h1>

<div class="row">
<div class="col-md-6 col-md-offset-3">
<%= form_for(:session, url: login_path) do |f| %>

<%= f.label :email %>
<%= f.email_field :email, class: 'form-control' %>

<%= f.label :password %>
<%= f.password_field :password, class: 'form-control' %>

<%= f.submit "ログイン", class: "btn btn-primary" %>
<% end %>

<p>New user? <%= link_to "Sign up now!", signup_path %></p>
</div>
</div>

しかし大規模になればなるほど、以下のような辛いことが待っています。


  1. jQueryなどでViewの状態を管理するので見通しが悪くなる

  2. cssの管理が大変になる。BEMなどのアプローチで頑張ってもいずれ辛くなる。

  3. パーシャルはレンダリングのみで状態を保持したり、隠蔽することができないため、使いづらい。

  4. form_for、form_withなどのRails独自の記法の挙動が意外と難しい

  5. View側にモデルを持つことができないため、helperやdecoratorなどの関数に依存してしまい、さらに保守が難しくなる。

上記のような課題点によってRails単体ではフロントエンドで負債が積み重なることが多いので、最近ではReactやVue.jsをつかうのが一般的です。

下記はReact一例ですが、コンポーネント化により、状態やcssの影響範囲をクラス範囲内だけに留めることができます。


login.html.erb

<% provide(:title, "ログイン") %>

<%= javascript_pack_tag 'login', 'data-turbolinks-track': 'reload' %>
<%= stylesheet_pack_tag 'login', 'data-turbolinks-track': 'reload' %>

<div id="login"></div>



login.tsx

document.addEventListener('DOMContentLoaded', () => {

const node = document.getElementById('login');
ReactDOM.render(<LoginPage />, node);
});


index.tsx

export default class LoginPage extends React.Component<Props, State> {

constructor(props) {
super(props);
}

private onSubmit = event => {
event.preventDefault();
const formData = new FormData(event.target);
// ログイン処理
};

render() {
return (
<div className={styles.container}>
<form method="POST" className={styles.content} onSubmit={this.onSubmit}>
<div className={styles.title}>
ログイン
</div>
<InputTextField label="メールアドレス" name="email" inputType="email" />
<InputTextField label="パスワード" name="password" inputType="password" />
<button className={styles.button} type="submit">
ログイン
</button>
</form>
</div>
);
}
}


Reactなどのフロントエンドのフレームワークを導入することにより以下のようなメリットが得られました。


  1. コンポーネント化によって定数や状態を隠蔽することができ、保守性の高いフロントエンドが構築できる

  2. cssの影響範囲を任意のクラス内に留めることができる。

  3. (TypeScriptを使った場合)型によって安全にプログラミングすることができる。

  4. フロントエンドでネイティブアプリのようにモデル層、通信層などレイヤーを決めて開発できるようになった。

Railsのerbやhelperを殆ど使わずに書くことが一般的な今、ViewにおけるRailsの優位性はなくなりつつあります。

Railsあるあるですが、インスタンス変数地獄、ERBでモデルやクエリを呼び出したりなど、行儀の悪いコーディングも防ぐことができるというだけでもメリットです。


2. Active Recordによってデータベースを簡単に定義、操作ができる

RailsのDB周りは未だに優秀だと感じています。


  • データベースをORMにより簡単に操作が行える

  • マイグレーションによってデータベース定義をバージョン管理できる

  • バリデーションを簡単に定義できる

  • リレーションが簡単に定義できる

欠点を上げるとするならば


  • 難しい処理の場合実際に発行されるクエリがわかりにくい

  • ActiveRecordから逸脱したことをやろうとすると面倒

というぐらいで、普通に使うのであれば、非常に使いやすいです。

他言語のマイグレーションツールとしてはFlywayなどがありますが、

Railsのほうが圧倒的に使いやすいです。

しかし、Railsのようにマイグレーション周りだけ記述できるridgepoleというものがあり、それだけを使うという選択肢もあります。


3.アセットパイプラインによってcss、jsを管理することができる

cssやjsを連結したり圧縮してくれる仕組みです。

これによって複数ファイルでcss、jsを管理したり、出し分けたりするなどのことが簡単に行えました。

ですがこちらもReactやVueを使う場合殆ど使わない機能になります。

それに加えて、Rails向けのフロントエンド用のライブラリの保守が行われなくなってきているのもあり、

フロントエンドのコードをRailsで管理すること自体が難しくなってきています。


4.チュートリアルが充実している

Railsを一通り学ぶことができる良い教材だと思います。

しかし、ReactやVueによるフロントエンド構築が一般的になりつつある今に、

form_withやimage_tagなどのRails独自のマークアップを覚えることはメリットではなくなりつつあります。

とくにform_for、form_tag、form_withは挙動を完全に把握するにはかなりの学習コストが必要です。しかし学んだところでRails以外のフレームワークでは全く必要のない知識ですし、erbによるHtml記述は斜陽なのでこの部分はReactなどjsxを使った方法で学ぶほうが良いのかなと思います。

TDDやデータベースの設計手法などは未だに参考になると思います。

数年前はRailsチュートリアルをやれば誰でも一線級のエンジニアになれる!という感じでしたが、

今では一部の知識は役に立つが、その他の知識はあまり役に立たなくなってきています。


5. Rubyという柔軟性の高い言語によって開発することができる

Railsの記事なのにRubyに言及するのは許してください。

Rubyは確かに良い言語でした。純粋なオブジェクト指向言語で、書きやすい言語だと思っています。

Ruby2系はチームの幸福度を最大化できなかった - Qiita

過去にこのような記事を書きましたが、Rubyは以下のような弱点があり、コードに問題のあるRailsプロダクトが多く生まれてしまいました。


  1. 読みにくい

  2. Rubyしか触っていないエンジニアはある一定レベルで成長が止まる

  3. 美しく書くという文化でしか質を担保する仕組みが無い

  4. Rubyの将来性


1. 読みにくい

Rubyのコードは引数や返り値の定義がないため、実際に読んでみないと何が帰ってくるのかわからないです。

なのでコードリーディングに時間がかかりますし、バグの混入確率も高いです。

そのためにRailsは「設定より規約」を取り入れて、このようにしたら、このように返ってくるというルールみたいなものを決めています。

このような規約は非常にありがたい半面、Railsはこう書いたら動くみたいな覚えゲーとなってしまった感がします。(その覚えたこともRailsでしか役に立たない)


2. Rubyしか触っていないエンジニアはある一定レベルで成長が止まる

これは社内外のエンジニアでRubyしか触ったことがないエンジニアを見て思った感想に近く、具体的に検証していませんが、述べさせていただきます。

Rubyは型やクラスを意識することなく記述することができてしまいます。

そのため、なんとなくな設計指針やなんとなくなクラス設計というのができてしまいますし、業務でも多く見てきました。

(よくあるケースとしてなんとなく、クラスメソッドにしたり、なんとなくインスタンス生成したりなど)

逆にJava、KotlinやGoなどの型定義を行うプログラミング言語の経験があるエンジニアが書くこRubyのコードは比較的美しいです。

Rubyという言語は型を全く定義しなくても動きますが、型を意識して書かなければ簡単に崩壊してしまいます

しかし、型を意識する書き方というのはRubyでは学ぶことはできません。(一応学べるかもしれませんが、Rubyの型は他言語に比べて挙動の把握が難しいです)

このパラドックスにより、質の悪いRailsプロジェクトが生まれやすくなっています。

そのためRubyしか触っていないエンジニアは一定のレベルで成長が止まると考えています。

その他、クラスの継承、インターフェース、ビルダーパターン、リアクティブプログラミング、ジェネリクス、ラムダなどのパラダイムはRubyでは学ぶことはできません。

私自身Rubyを触ったあとにJava,Kotlinを触ったことによりRubyに対する見方が変わったという経験があります。


3.美しく書くという文化でしか質を担保する仕組みが無い

Rubyは他人が書いたコードを読むのにエネルギーが要る言語だと思います。

型定義がある言語では入力と出力の形式がある程度定まっているので、比較的読みやすいです。

Rubyは返り値がどのような型になるかわからないので、メソッド名が妥当であるか?であったり、美しくわかりやすく書かれているかもしくは、テストを書いているか?が重要になってきます。

熟練者のコードは非常に読みやすいかもしれませんが、そうでない場合、コードリーディングが大変です。

こうしたコールドリーディングを簡単にするために、美しく書く文化やテストを書くという文化があるのですが、

どこまで美しく書くか、どの程度テストを書くかは属人的であるので、質が担保しにくいです。

追い打ちをかけるようにRubyは様々な書き方ができてしまうので、よりコードリーディングが難しくなります。

ダメなプログラミング言語の代名詞としてPHPが挙げられますが、それがRubyに置き換わる時が来るかもしれません

TypeScript、KotlinやGoなどのように、型宣言があり、最低限の書き方が担保されている方が読みやすいのではないかと私は思います。

上記のようにRubyは簡単にかけるが、チーム開発をするには上級者向けの言語なので、Rubyによる開発が辛くなってくるのは必然だと思います。


4. Rubyの将来性

これは個人的な愚痴に近いのですが、Rubyの開発の方向性と現場で必要なものがだんだんと違ってきているのではないかと最近は感じています。

Ruby3では速く動作することが頻繁に取り上げられますが、実際にそれでいまエンジニアが抱えている問題が解決するのか・・・?と思ってしまいます。

Rubyでチーム開発しやすいように、型宣言などの開発者を支援するような機能もほしいなという声もあるのではないでしょうか。

そういった背景もあり、型推論言語であったり、並列処理が速い言語などにフォーカスがあたってきているのだと思います。


今後のRailsとRuby界隈

終わったといっているだけでは生産性がないので、自分なりのアイデアや予想も記述しておきます。


Railsの将来性について

全盛期に比べて価値はかなり落ちてしまったように感じますが、


  • 優秀なマイグレーションツール

  • 扱いやすいORM

によって、APIサーバーとしてはまだまだ活用されるのではないかと思います。

バックエンドはRailsで書いて、フロントエンドはReactもしくはVueなどのフレームワークを用いて設計というのがRailsの今後の道かもしれません。

Railsを使うのであれば、以下のような構成が主流になるのではないかと思います。


  • Rails

  • Fast JSON API

  • Webpack

  • React

  • TypeScript

  • 一部の処理をGoなどでマイクロサービス化

とはいえ、Railsが管理しているのはAPIサーバーとデータベースのみなので、このためだけにRailsが選択されるかというとちょっと微妙な気もします。


Rails代替のフレームワーク、言語について


Go

Goへの乗り換えが最近HOTですが、個人的にはGoはきついのではないかなと思います。

Goroutineなど並列処理は優秀ですが、それ以外のことは苦手だと思っています。

理由としては


  • オブジェクト指向的な設計がやりにくい

  • C言語チックなのでポインタなど意識しなければならないことが多い

  • Rubyなどの他言語に比べて不親切

マイグレーション、データベース、APIをすべてGoで実装しようとする人をたまに見かけますが、それって本当にGoでやるべきなのか?と思います。

なので、私の予想としてはRailsプロジェクトが数年後100%Goのプロジェクトに置き換わることはないかなと思います。

バッチ処理などの重い処理がGoに置き換わっていくというのが現実的かなと思います。


Kotlin

筆者としてはKotlinはかなりありなのかなと思っています


  • Null安全、型推論のモダンな言語

  • Ktor(けいとーる)がKotlin/Nativeに対応した

  • Kotlin/JSによってフロントエンドも書くことができる

Kotlinの世界観として、すべてのプラットフォームをKotlinで書けるという物を目指しているので、

実現した暁には、フロントエンド、バックエンド、アプリをすべてKotlinで書くことができます。

しかし、期待値は高いですが、Railsに代替するほどの決め手はまだなくこれからって感じだと思います。


Node.js

私はあまり触ったことがないのでわからないですが、フロントエンドでTypeScript、JavaScriptを書くので、

サーバーサイドもJSのほうが学習コストが少なくて済むかもしれないので流行るかもしれません。

また、フロントエンドとバックエンドの一部モデルの共通化などNode.jsでできるかもしれません。


その他

Elixirなどありますが、私は触ったことがないのでよくわからないです。


Rubyの型システム予想

ここは完全に妄想なので、興味ない人は飛ばしてください。


メソッド

Ruby3系以降では以下のような感じになってほしいなと思います。

  def add(x : Integer, y : Integer) : Integer

x + y
end

Integer以外が入ったときには静的解析などで通知してくれると嬉しいです。

Typescriptのように複数の型を返すときは以下のようにかけるといいと思いました。

ただ、Trueクラス、Falseクラスが存在する中でBooleanクラスをすんなり導入できるかどうかで意見が分かれそうです。

  def method(x : Integer, y : Integer) : Integer | nil

if x > y
x
else
nil
end
end

Ruby3の開発状況は全然知らないのですが、

Rubyに型の秩序を取り入れるという選択肢をユーザーに与えてみてもいいのではないかと思います。


クラス

抽象クラスやメソッドのスコープがわかりやすく定義できると良いなと思いました。

Rubyの場合オブジェクト指向的なプログラミングへのサポートが弱いです。

継承を行うだけで見通しの悪いコードになってしまいがちなので、言語的にサポートがほしいです。

abstract class ApplicationRecord < ActiveRecord::Base

open def method(x : Integer) : Boolean
x > 10
end

private def save
#.....
end
end

class User < ApplicationRecord

override def method(x : Integer) : Boolean
x > 20
end

end


おわりに

数年前はRails学べばなんでもできると言われていましたが、今ではちょっとつらいかなと言う印象です。

主にフロントエンドでは、ネイティブアプリのようにAPIだけ問い合わせてレンダリング、状態管理、キャッシュするというプロダクトが主流になりつつあります。

さらにRubyはチーム開発にはあまり向いていない言語だと思うので、コードレビューや設計方針にあまりエネルギーを割くことがないプログラミング言語が人気になると思います。

という感じでRailsは終わっていないかもしれないが、積極的に学んでも、Railsの特徴の殆どはこれから活躍する見込みが無いので、あまり得られるものはない。と思ってます。

ぶっちゃけRailsがすごいのはActiveRecordなので、それさえ現役である限り終わっていないとも言えます。

次の言語何が来るかってのはいろいろあると思いますが、どんな環境になってもHTTPやデータベースの仕組みはしばらく変わることはないので、それさえ知ってればなんとかなるんじゃないのかなー。


追記 2019/08/22

いろいろ説明不足だったので、動画を出しました

解説の動画