- Published on
モダン Ruby & Rails 2026 — Ruby 3.4 / Rails 8 / Hotwire / Sorbet / Kamal 2 / Solid Queue 徹底ガイド
- Authors

- Name
- Youngju Kim
- @fjvbn20031
1章 · 2026年の Ruby/Rails — 「死んだ」と言った人へ
2026年の風景。友人が YC Demo Day で自分のスタートアップを自慢している。「3週間で MVP を作って公開し、最初の50万ドル売上を達成した」。スタックを聞かれた彼は少し恥ずかしそうに答える。「Rails」。隣のテーブルの Next.js フルスタックエンジニアが目を丸くする。「まだ?」
まだだ。そして2026年には、これまで以上に静かに、これまで以上に多くの場所で動いている。
2020年代初頭のインターネット言説は「Rails は死んだ」だった。2026年の現実はその逆 — Rails は死んでいないし、むしろ最も静かに、最も多く働いているスタックの一つになっている。GitHub、Shopify、Stripe、Airbnb、Basecamp、HEY、GitLab、Square、Coinbase、クックパッド、メルカリ、カカオペイの一部、トスの一部。挙げていくとキリがない。
なぜ死んでいないか。三つのことが同時に起きた。
- Ruby 3.4(2024年12月) — YJIT(Yet Another JIT)が本当に速くなり、
error_highlightがデフォルトになってデバッグがずっと親切になった。 - Rails 8(2024年11月) — 37signals が Redis 依存を切り離す「Solid 三兄弟」(Queue, Cache, Cable)を発表した。Postgres または SQLite 一つでジョブキュー、キャッシュ、WebSocket をすべて回せる。
- Kamal 2 —
kamal deploy一行で自前のサーバーに Docker でデプロイする。Heroku/Vercel/AWS Fargate に月数百〜数千ドルを払わなくてもいい時代になった。
その上に Hotwire(Turbo + Stimulus)がある — React のビルドパイプラインなしでもインタラクティブな UI を作れる。Sorbet(Stripe 製の漸進的型チェッカー)と Tapioca(RBI 自動生成器)が型を入れてくれる。Mission Control が Sidekiq なしでジョブを監視する。Propshaft が sprockets を置き換えた新しいアセットパイプラインで、Action Notifier が Rails 8 の新しい通知フレームワークだ。
この記事は2026年の Ruby/Rails フルスタックを一気に見る。1章から11章までは各パーツの解剖、12章から14章までは代替と生態系と「誰が選ぶべきか」を見る。最後まで読めば、次のサイドプロジェクトで Next.js+Vercel の代わりに Rails 8+Kamal を選んだときに後悔しないかへの答えが出るはずだ。
2章 · Ruby 3.4(2024.12) — YJIT 改善と error_highlight デフォルト化
Ruby 3.4 は2024年12月25日(毎年クリスマスが Ruby のメジャーリリース日だ)に出た。大きなヘッドラインは二つ。
YJIT — Ruby の JIT は本物だ
YJIT(Yet Another JIT)は Shopify が作ったメソッドベースの JIT コンパイラで、Ruby 3.1 で実験的に入り、3.2 で本番投入可能になり、3.3 で ARM64 対応とメモリ使用量を減らし、3.4 でウォームアップ時間をさらに短縮した。Shopify 自身のベンチマークによれば Rails ワークロードで平均 1.4x ~ 2x 速くなる。単純な算術ループのようなマイクロベンチではもっと極端な数字が出るが、本当の意味は Rails コントローラーアクションのような実ワークロードで測られる。
有効化は一行。
# config/boot.rb または環境変数
# config/boot.rb の先頭
require 'bootsnap/setup' if ENV['DISABLE_BOOTSNAP'].nil?
# 環境変数で
RUBY_YJIT_ENABLE=1 bundle exec rails server
またはコードで明示的に。
# config/application.rb
require_relative "boot"
require "rails/all"
if defined?(RubyVM::YJIT.enable)
RubyVM::YJIT.enable
end
# ...
Rails 8 は production 環境で YJIT をデフォルトで有効化する(config/environments/production.rb で明示的に切らない限り)。YJIT 統計を見るには。
# Rails console で
RubyVM::YJIT.runtime_stats
# => {compile_time_ns: ..., compiled_iseq_count: ..., ...}
error_highlight — デフォルトで親切になったエラーメッセージ
Ruby 3.1 で入った error_highlight gem が 3.4 でさらに洗練された。NoMethodError が起きたとき単に "undefined method foo'" ではなく、**ソースコードのどの部分で起きたかをキャレット(^`)で示してくれる**。
伝統的な Ruby 1.x ~ 2.x のエラーはこうだった。
NoMethodError: undefined method `name' for nil:NilClass
app/models/user.rb:42:in `display'
3.4 ではこう。
app/models/user.rb:42:in 'User#display':
puts "Hello, " + user.profile.name
^^^^^
NoMethodError: undefined method 'name' for nil
user.profile が nil だということが一目で分かる。Sentry / Honeybadger / Bugsnag のようなエラートラッキングサービスもこのキャレット情報をそのまま保存する。
その他の変更
itブロックパラメータが正式に入った —[1,2,3].map { it * 2 }のように単一パラメータブロックを短く書ける。Range#stepがRangeを返していたのがEnumeratorを返すように変わった。Prismパーサーがデフォルトになった — Ruby 標準パーサーを置き換える新パーサーで、IDE/LSP ツールがずっと速くなる。- ガベージコレクタのチューニング可能なオプションが増えた(MMTk 互換モード)。
3章 · Rails 8(2024.11) — Solid トリオで Redis 依存を切り離す
Rails 8 は2024年11月に出た。DHH のキーノートの一言がすべてを要約する。
「We're going Redis-free by default.」
数年間、Rails アプリの標準インフラはこうだった: Postgres + Redis + Sidekiq。Redis は Sidekiq ジョブキュー、Rails キャッシュ、Action Cable パブサブに同時に使われていた。Redis が死ねばジョブも死に、キャッシュも死に、WebSocket も死ぬ。小さなチームが Redis を運用するのは常にコストだった。
Rails 8 の答え: Solid Queue, Solid Cache, Solid Cable。三つともデータベース(Postgres/MySQL/SQLite)にデータを書き込む。Redis が消えると依存ツリーが大きく単純化する。
[従来の Rails 7] [Rails 8 デフォルト]
───────────────── ─────────────
Rails app Rails app
| |
├── Postgres (データ) └── Postgres
├── Redis (Sidekiq キュー) ├── solid_queue_* テーブル
├── Redis (キャッシュ) ├── solid_cache_entries テーブル
└── Redis (Action Cable) └── solid_cable_messages テーブル
Rails 8 の新規アプリはデフォルトで SQLite で Solid 三つを全部回すこともできる — 本当にシングルバイナリに近い単純さだ。小さなサイドプロジェクトなら EC2 t4g.small 一台に SQLite + Solid Queue + Solid Cache + Solid Cable + Kamal で十分。
Rails 8 新規アプリ作成。
gem install rails -v "~> 8.0"
rails new myapp
# デフォルトで SQLite + Solid Queue + Solid Cache + Solid Cable + Propshaft + Importmap + Hotwire
Postgres を使うなら。
rails new myapp --database=postgresql
既存の Rails 7 アプリを 8 に上げる方法は別途ガイドが必要なくらいなのでここでは触れない — Rails Edge Guides の Upgrade Guide を参考にしてほしい。
4章 · Solid Queue — Redis 依存除去の意味
Sidekiq は10年以上 Rails ジョブキューの事実上の標準だった。Redis をバックエンドに使い、BRPOP でジョブを取得し、fork+threads モデルでワーカーを動かす。速くて堅牢だ。だが欠点は? Redis が必要だ。
Solid Queue は37signals が HEY と Basecamp で実際に使っていたジョブキューをオープンソース化したもの。Postgres/MySQL/SQLite にジョブテーブルを作り、FOR UPDATE SKIP LOCKED(または SQLite のトランザクション)でジョブを掴む。
インストールは簡単。
bundle add solid_queue
bin/rails solid_queue:install
bin/rails db:migrate
config/queue.yml でワーカーを設定する。
default: &default
dispatchers:
- polling_interval: 1
batch_size: 500
workers:
- queues: "*"
threads: 5
processes: 1
polling_interval: 0.1
development:
<<: *default
production:
<<: *default
workers:
- queues: [ critical, default ]
threads: 10
processes: 2
polling_interval: 0.1
- queues: [ low_priority ]
threads: 3
processes: 1
polling_interval: 1
ジョブクラスは ActiveJob の標準インターフェースをそのまま使う。
class WelcomeEmailJob < ApplicationJob
queue_as :default
def perform(user_id)
user = User.find(user_id)
UserMailer.welcome(user).deliver_now
end
end
# どこからでも
WelcomeEmailJob.perform_later(user.id)
WelcomeEmailJob.set(wait: 1.hour).perform_later(user.id)
Sidekiq から Solid Queue に移行するときコード変更はほぼない(ActiveJob インターフェースを使っていれば)。ただし 性能特性が異なる — Redis インメモリキューより Postgres ディスクキューは100倍遅いが、小さなアプリには十分。分単位で数十万件処理するメガワークロードならまだ Sidekiq + Redis が良い。だが 分単位で数千件未満 なら Solid Queue が運用の単純さで勝つ。
5章 · Solid Cache + Solid Cable
Solid Cache
37signals の HEY は毎日テラバイト級のキャッシュを使う。Redis インメモリでは RAM コストが爆発した。答え? ディスクベースのキャッシュ。SSD が速くなった2020年代では、ディスクキャッシュも十分速い。
# config/cache.yml
production:
database: cache
store_options:
max_age: <%= 2.weeks.to_i %>
max_size: 256.megabytes
namespace: <%= Rails.env %>
使い方は通常の Rails.cache と同じ。
Rails.cache.fetch("expensive_query", expires_in: 1.hour) do
ExpensiveQuery.compute
end
HEY 基準ではキャッシュヒットレイテンシが平均 1-3ms 程度。Redis より遅いが、価格対容量がはるかに大きい。
Solid Cable
Action Cable が Redis パブサブに依存していた部分をデータベースに移したもの。メッセージを solid_cable_messages テーブルに書き、LISTEN/NOTIFY(Postgres)またはポーリング(SQLite/MySQL)で購読者に配信する。
# config/cable.yml
production:
adapter: solid_cable
connects_to:
database:
writing: cable
polling_interval: 0.1.seconds
message_retention: 1.day
チャットメッセージを送るコントローラー。
class ChatMessagesController < ApplicationController
def create
message = @room.messages.create!(body: params[:body], user: current_user)
# Solid Cable で他のユーザーにブロードキャスト
ChatChannel.broadcast_to(@room, render_to_string(partial: "messages/message", locals: { message: message }))
head :no_content
end
end
数百同時接続のチャットなら十分。数万人以上 なら Redis アダプタ(AnyCable のような)や専用ソリューションが必要だ。
6章 · Hotwire(Turbo + Stimulus) — React なしのインタラクティブ
Hotwire は「HTML Over the Wire」の略。哲学はシンプル: JSON でデータを送ってクライアントが React でレンダリングする代わりに、サーバーが HTML 断片を送ってクライアントが DOM に差し込む。
三つのパーツでできている。
- Turbo Drive — すべてのリンククリックとフォーム送信を fetch で奪い取り、応答 HTML の
<body>だけを差し替える。SPA のようなページ遷移を無料で提供。 - Turbo Frames —
<turbo-frame id="cart">のようなコンテナでページの一部だけを更新する。 - Turbo Streams — サーバーが「この要素を追加/置換/削除しろ」という命令を HTML 断片と一緒に送る。WebSocket や SSE でリアルタイム更新が可能。
Turbo Drive 例
<!-- app/views/posts/index.html.erb -->
<%= link_to "新しい投稿", new_post_path %>
このリンクをクリックすると Turbo が fetch で奪い取り、応答の <body> だけを差し替える。JavaScript を一行も書かずに SPA 感覚。
Turbo Frames 例
<!-- app/views/posts/show.html.erb -->
<h1><%= @post.title %></h1>
<turbo-frame id="comments">
<%= render @post.comments %>
<%= link_to "コメントを追加", new_post_comment_path(@post) %>
</turbo-frame>
<!-- app/views/comments/new.html.erb -->
<turbo-frame id="comments">
<%= form_with model: [@post, @comment] do |f| %>
<%= f.text_area :body %>
<%= f.submit "投稿" %>
<% end %>
</turbo-frame>
「コメントを追加」リンクをクリックすると id="comments" フレームの中だけでフォームがロードされる。ページ全体は変わらない。
Turbo Streams でリアルタイム更新
# app/models/comment.rb
class Comment < ApplicationRecord
belongs_to :post
belongs_to :user
broadcasts_to ->(comment) { [comment.post, "comments"] }
end
<!-- app/views/posts/show.html.erb -->
<%= turbo_stream_from @post, "comments" %>
<div id="comments">
<%= render @post.comments %>
</div>
これである誰かがコメントを追加すると、同じページを見ている全ユーザーに WebSocket(Solid Cable)で新しいコメントが即座に追加される。React/Vue 一行も書かずに。
Stimulus — 軽量な JS コントローラー
本当に複雑なクライアント相互作用が必要なときだけ Stimulus を使う。
<div data-controller="counter">
<button data-action="click->counter#increment">+</button>
<span data-counter-target="display">0</span>
</div>
// app/javascript/controllers/counter_controller.js
import { Controller } from "@hotwired/stimulus"
export default class extends Controller {
static targets = ["display"]
initialize() { this.count = 0 }
increment() {
this.count += 1
this.displayTarget.textContent = this.count
}
}
HTML が常に真実の源だ。React の「仮想 DOM が真実で実 DOM はそこから派生」とは正反対の哲学。
7章 · Sorbet(Stripe) + Tapioca — 漸進的型付け
Ruby は動的言語だ。変数に型がない。これは長所であり短所でもある。Stripe はコードベースが数百万行に成長して動的型付けの限界を痛感し、Sorbet を作った(2019年オープンソース化)。
Sorbet は Ruby に漸進的型付けを乗せる。すべてのファイルに一行追加する。
# typed: true
require "sorbet-runtime"
class User
extend T::Sig
sig { params(name: String, age: Integer).returns(User) }
def self.create(name:, age:)
new(name: name, age: age)
end
sig { params(name: String, age: Integer).void }
def initialize(name:, age:)
@name = name
@age = age
end
sig { returns(String) }
def display
"#{@name} (#{@age})"
end
end
# typed: true は strict 度合いを意味する(ignore / false / true / strict / strong)。sig { ... } でメソッドシグネチャを宣言する。実行時には sorbet-runtime が引数の型を検証してエラーを投げ、静的解析では srb tc で型チェックを回す。
bundle add sorbet
bundle add sorbet-runtime
bundle exec srb init
bundle exec srb tc
Tapioca — Sorbet の自動 RBI 生成器
Sorbet は .rbi ファイル(RBI = Ruby Interface)から型シグネチャを読む。外部 gem に対するシグネチャを直接書くのは地獄 — Tapioca が自動生成する。
bundle add tapioca --group=development
bundle exec tapioca init
bundle exec tapioca gems # 全 gem の RBI 生成
bundle exec tapioca dsl # Rails DSL(スコープ、アソシエーション、アトリビュート)の RBI 生成
Tapioca DSL が作った RBI の例。
# sorbet/rbi/dsl/user.rbi(自動生成)
class User
sig { returns(T.nilable(String)) }
def email; end
sig { params(value: T.nilable(String)).returns(T.nilable(String)) }
def email=(value); end
# ActiveRecord スコープ
sig { returns(ActiveRecord::Relation) }
def self.active; end
end
これで IDE で user.emil のようなタイポも捕まる。Stripe 社内ではコードの80%以上が # typed: true 以上だという。
8章 · Kamal 2(37signals) — kamal deploy で直接デプロイ
37signals の DHH は2023年に「We have left the cloud」という記事で有名になった。Basecamp/HEY を AWS から自前データセンターに移して年700万ドルを節約したという記事だ。その移行過程で作ったツールが Kamal(元の名前は MRSK)。
Kamal 2(2024年リリース)は Docker + SSH + 一行のコマンド で任意の Linux サーバーにアプリをデプロイする。Heroku/Vercel/AWS Fargate なしで。
gem install kamal
kamal init
config/deploy.yml でデプロイを定義する。
service: myapp
image: myteam/myapp
servers:
web:
hosts:
- 1.2.3.4
- 1.2.3.5
job:
hosts:
- 1.2.3.6
cmd: bin/jobs
registry:
server: ghcr.io
username: myteam
password:
- KAMAL_REGISTRY_PASSWORD
env:
clear:
RAILS_ENV: production
RAILS_LOG_TO_STDOUT: 1
secret:
- RAILS_MASTER_KEY
- DATABASE_URL
accessories:
postgres:
image: postgres:16
hosts:
- 1.2.3.4
env:
secret:
- POSTGRES_PASSWORD
volumes:
- /var/lib/postgresql/data:/var/lib/postgresql/data
proxy:
ssl: true
host: myapp.com
デプロイは一行。
kamal deploy
何をしているか。
- ローカルで Docker イメージビルド(または GitHub Actions でビルドしたものを pull)。
- レジストリに push。
- 全サーバーに SSH で入り、新しいイメージを pull。
- 新しいコンテナを起動し、Kamal Proxy(Traefik 後継)がトラフィックを差し替える無停止デプロイ。
- 古いコンテナをクリーンアップ。
初回デプロイ時は kamal setup を呼ぶと Docker インストールから全部やってくれる。
kamal setup # Docker インストール + 初期デプロイ
kamal deploy # 以降のデプロイ毎回
kamal rollback # ロールバック
kamal logs # ログ閲覧
kamal app exec --interactive --reuse "bin/rails console" # console 接続
EC2 t4g.medium 一台(月30ドル)に Postgres + Solid Queue + Rails アプリを全部立てれば、Heroku hobby tier(月25ドル)に近い価格ではるかに強力なインスタンス になる。トラフィックが増えればサーバーを増やして kamal deploy --hosts ... で水平スケール。
9章 · Mission Control — Rails ネイティブのジョブ監視
Sidekiq には常に良い Web UI(/sidekiq)があった。Solid Queue に移ったらこれを失うのか? いや — Rails 8 は Mission Control - Jobs という公式 Web UI を提供する。
bundle add mission_control-jobs
# config/routes.rb
Rails.application.routes.draw do
mount MissionControl::Jobs::Engine, at: "/jobs"
# ...
end
# config/application.rb
config.mission_control.jobs.base_controller_class = "AdminController" # 認証
/jobs に接続するとキュー状態、進行中ジョブ、失敗ジョブ、リトライ、ジョブ一時停止/再開がすべてできる。Sidekiq Web UI のほぼ全機能を提供しつつ、Solid Queue の全アダプタ(Postgres/MySQL/SQLite)で動作する。
加えてジョブ監視に良いツール。
- Skylight / Scout APM — ジョブのメモリ/CPU プロファイリング。
- Sentry / Honeybadger — ジョブ失敗時のエラー追跡とアラート。
- Datadog — Solid Queue テーブルメトリクスを直接収集。
10章 · Propshaft / Action Notifier — Rails 8 の新しい基本
Propshaft — sprockets の後継
Sprockets は Rails 2 からあったアセットパイプラインだ。CoffeeScript、Sass、ERB で JavaScript と CSS をコンパイルし、ダイジェストフィンガープリントを付けてキャッシュする。だが2020年代には esbuild、Vite、Bun、importmap-rails のようなツールがトランスパイルをもっとうまくやる。Propshaft はトランスパイルしない — ファイルにダイジェストフィンガープリントだけ付けて配信する。
# Gemfile
gem "propshaft"
# ダイジェストが付いたファイルを生成
bin/rails assets:precompile
新しいアセットパイプライン哲学。
- トランスパイルは esbuild/Vite/jsbundling-rails の仕事。
- バンドリングもそれらの仕事。
- Propshaft は単純にダイジェストフィンガープリントと配信だけ。
Rails 8 の新規アプリはデフォルトで Propshaft + Importmap-rails + Hotwire を使う。JavaScript は importmap でブラウザがネイティブに取得し、CSS は propshaft がフィンガープリントする。
Action Notifier(Rails 8 新規追加)
Rails 8 には通知(notification)システムが正式に入った。メール、SMS、プッシュ、Slack、データベースなど複数チャネルに同時に通知を送る標準抽象化だ。
class NewCommentNotifier < ApplicationNotifier
deliver_by :email, mailer: "CommentMailer", method: "new_comment"
deliver_by :slack, channel: "#engineering"
deliver_by :database
param :comment, :user
def message
"#{params[:user].name}が新しいコメントを投稿しました。"
end
end
# 呼び出し
NewCommentNotifier.with(comment: @comment, user: current_user).deliver(@post.author)
複数チャネルに同じメッセージを送る一般的なパターンを一箇所にまとめる。Noticed gem が着想元で、Rails 8 で公式化された。
11章 · RuboCop / Standard / Brakeman — 静的解析
RuboCop — 最も使われているリンター
RuboCop は Ruby の ESLint 的な存在。スタイル違反から潜在バグまで捕まえる。
bundle add rubocop --group=development
bundle exec rubocop
bundle exec rubocop -a # 自動修正
rubocop-rails、rubocop-rspec、rubocop-performance のような拡張 gem で範囲を広げる。
# .rubocop.yml
require:
- rubocop-rails
- rubocop-rspec
- rubocop-performance
AllCops:
TargetRubyVersion: 3.4
TargetRailsVersion: 8.0
NewCops: enable
Style/StringLiterals:
EnforcedStyle: double_quotes
Layout/LineLength:
Max: 120
Standard — 意見のない RuboCop ラッパー
毎回 .rubocop.yml を決めるのが疲れるなら Standard を使おう。RuboCop をラップしつつ「もう全部決めたから黙ってろ」という哲学。
bundle add standard --group=development
bundle exec standardrb
bundle exec standardrb --fix
Tenderlove(Aaron Patterson)や多くの OSS メンテナが使っている。Prettier が JS でやったことを Ruby でやる。
Brakeman — 静的セキュリティ解析
Brakeman は Rails 専用の静的セキュリティ解析ツール。SQL インジェクション、mass assignment、XSS、コマンドインジェクションのような一般的な脆弱性を捕まえる。
bundle add brakeman --group=development
bundle exec brakeman
CI パイプラインに入れて PR ごとに回すと良い。GitHub Actions の例。
name: Brakeman
on: [pull_request]
jobs:
brakeman:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: ruby/setup-ruby@v1
with:
ruby-version: 3.4
bundler-cache: true
- run: bundle exec brakeman --no-pager
Rails 8 の新規アプリはデフォルトで RuboCop、Brakeman、そして GitHub Actions ワークフローを一緒に作ってくれる。
12章 · 代替 — Hanami 2 / Roda / Sinatra / dry-rb
Rails が全ての答えではない。Ruby 生態系には他に良い選択肢がある。
Hanami 2
Hanami は「Rails よりも明示的でモジュール化されたフレームワーク」を目指す。2022年に Hanami 2 が出てから本格的にプロダクション利用できるレベルになった。特徴。
- 依存性注入(DI) コンテナが第一級市民。dry-system の上に作られている。
- ルーター / コントローラー(アクション) / ビュー / ビューモデルが明示的に分離。
- 「慣習より明示的」哲学。マジックが少ない。
# slices/main/actions/books/index.rb
module Main
module Actions
module Books
class Index < Main::Action
include Deps[
"repositories.book_repo"
]
def handle(_request, response)
response[:books] = book_repo.all
end
end
end
end
end
小〜中規模の API/SaaS に適している。Rails より学習曲線は急だが、大きなコードベースで明示的な構造が価値を持つときに輝く。
Roda
Jeremy Evans(Sequel 作者)が作ったマイクロルーティングツリーベースのフレームワーク。非常に高速で、ツリールーティングでルートが自然にネストする。
require "roda"
class App < Roda
plugin :json
plugin :halt
route do |r|
r.root { { hello: "world" } }
r.on "users" do
r.get Integer do |id|
{ user_id: id }
end
r.post do
# 新規ユーザー
end
end
end
end
Sinatra より速く、Hanami より軽量。Shrine、Sequel のようなライブラリと相性が良い。
Sinatra
最も古いマイクロフレームワーク。シンプルな API や小さなツールには今でも良い。
require "sinatra"
get "/hello/:name" do
"Hello, #{params[:name]}"
end
dry-rb / Rom-rb
dry-rb は Hanami が基盤としているライブラリコレクション。dry-validation(スキーマ検証)、dry-monads(Result/Maybe モナド)、dry-types(型)、dry-system(DI コンテナ)、dry-effects(エフェクト)。Rails と一緒にも使える。
Rom-rb はデータマッパーパターンの ORM。ActiveRecord と違ってドメインオブジェクトと永続性を分離する。DDD を真面目にやるチームに魅力的。
13章 · 韓国 / 日本の Ruby 生態系 — クックパッド、メルカリ、カカオペイ
日本 — Ruby の本場
Ruby は Matz(まつもとゆきひろ)が1995年に作った。日本は Ruby の本場で、日本企業の Ruby/Rails 利用が最も深く長い。
- クックパッド — 日本最大のレシピサイト。ほぼ全てのバックエンドが Rails。RubyKaigi のメインスポンサー。Ruby/Rails カンファレンスの発表で社内モノリスをどう運用しているかをよく共有している。
- メルカリ — 日本最大のフリマアプリ。バックエンドの大部分が Ruby/Rails で、他は Go/Python に移行中。Go に移す部分も Ruby で始まったビジネスロジックを少しずつマイグレーションする。
- GMO ペパボ — ライブコマース/EC。
- マネーフォワード — 家計簿/会計 SaaS。Rails で始まり成長したケース。
- Sansan — 名刺管理。Rails ベース。
- freee — 会計 SaaS。Rails で IPO まで到達した。
日本では毎年 RubyKaigi(2-3日のカンファレンス)が開かれ、Matz が直接キーノートをする。Rails より Ruby 自体に関する発表が多く、MRI/YJIT/言語デザインの深い議論が日常だ。
韓国 — Rails 利用は増えている
韓国の Rails 利用は日本ほど大きくはないが、着実に増えている。
- カカオペイ — 一部のバックエンドが Rails。決済/メンバーシップ関連の一部ドメイン。
- トス — 一部の社内ツールと社内システムが Rails。
- Bridge Plus / D.CAMP — スタートアップアクセラレータがよく Rails で開始するスタートアップを見る。
- よく知られた韓国の Rails 事例 — Class101、Mirinae、Zigbang の一部バックオフィスなど。
韓国は2010年代中盤に RubyKR カンファレンスが活発で、最近は RubyKR Slack/Discord コミュニティが小さいながら活発。韓国での Rails 開発者採用は日本ほどではないが着実にある(特にシニア/スタートアップテックリードポジションで)。
グローバル — よく知られた事例
- Shopify — 世界最大の Rails アプリ。YJIT の主要スポンサー。Rails コアへの多数のコントリビューション。
- GitHub — Rails で始まり今も大部分が Rails。モノリス運用の模範例。
- Stripe — Sorbet の発祥地。決済処理バックエンドの大部分が Ruby。
- Airbnb — 初期から Rails。一部は Java/Kotlin に移行、一部はまだ Ruby。
- Basecamp / HEY — 37signals 自社プロダクト。DHH のビジョンがそのまま具現化された場所。
- GitLab — Rails。セルフホストと SaaS 両方。
- Twitch — 初期 Rails、一部は Go/Erlang に移行。
- Coinbase — Rails で開始、一部は Go に移行。
14章 · 誰が Ruby/Rails を選ぶべきか — 1-2人 / スタートアップ / B2B SaaS
1-2人 / サイドプロジェクト
圧倒的に Rails を推奨する。 理由。
- 速度 —
rails new一行で認証、ジョブキュー、キャッシュ、WebSocket、マイグレーション、テスト、管理画面までセットアップされる。 - インフラの単純さ — Rails 8 + Solid トリオ + SQLite で EC2 t4g.small 一台に全部立てられる。
- Kamal でデプロイコストがほぼ0 — Heroku/Vercel なしで月5ドルから始められる。
- Hotwire でフロントエンドビルドパイプラインなし — Node 依存ゼロ。
Next.js + Vercel + Postgres + Upstash Redis + Resend + Stripe で組むより、Rails + Kamal + Postgres 一つで組む方が速くて安い。
初期スタートアップ(1-15人)
Rails はまだ最良の選択。 37signals、GitHub、Stripe、Shopify が全部 Rails で始まり IPO/ユニコーンまで到達した。PMF を探す段階ではフルスタックフレームワークの凝集力が絶対的だ。Next.js のモノレポ + RPC + 認証ライブラリ + ジョブキュー依存ツリーは PMF 段階では荷物。
良い組み合わせ。
- Rails 8 + Postgres + Solid トリオ + Hotwire + Kamal 2。
- Sentry でエラー追跡、Skylight または Scout APM で APM。
- RSpec または Minitest、FactoryBot、Capybara/Cuprite でテスト。
- 漸進的に Sorbet 導入(最初から全部 strict にせず、コアドメインから)。
B2B SaaS(15-100人)
依然 Rails が良い。ただし 型とドメイン分離 にもっと気を配ろう。
- Sorbet でコアドメインの型を整える。
- Service Object / Command パターンで fat controller を避ける。
- Trailblazer、dry-rb、Hanami のパターンを部分的に導入。
- モノリスを維持しつつ Engine でドメインを分離(Shopify の「Modular Monolith」パターン)。
100人以上 / マイクロサービス段階
Rails もよく動くが、この時点では言語選択より 組織設計 がもっと重要になる。Rails モノリスが自然に分解されるなら、一部のサービスを Go/Java/Kotlin に移すことを検討する価値がある(Shopify がコアは Rails、一部のインフラ系サービスを Go/Rust に移行したように)。
Rails を避けるべき場合
- 超低レイテンシ(
<10ms)がビジネスの中核 な場合 — ゲームサーバー、高頻度取引、組み込み。Go、Rust、Elixir、C++ が良い。 - 機械学習推論/学習パイプラインが本業 の場合 — Python が答え。
- 型が絶対的に必須 なドメイン — Sorbet である程度解決するが、最初から TypeScript/Kotlin/Rust の方が直線的な経路。
- 既に Node/Python 単一言語ポリシー の会社 — わざわざ Ruby を追加する理由がない。
15章 · 参考 / References
- Ruby 3.4 Release Notes: https://www.ruby-lang.org/en/news/2024/12/25/ruby-3-4-0-released/
- Rails 8 Release Notes: https://rubyonrails.org/2024/11/8/rails-8-no-paas-required
- Rails Edge Guides: https://edgeguides.rubyonrails.org/
- YJIT Documentation: https://github.com/ruby/ruby/blob/master/doc/yjit/yjit.md
- Solid Queue: https://github.com/rails/solid_queue
- Solid Cache: https://github.com/rails/solid_cache
- Solid Cable: https://github.com/rails/solid_cable
- Hotwire: https://hotwired.dev/
- Turbo Handbook: https://turbo.hotwired.dev/handbook/introduction
- Stimulus Handbook: https://stimulus.hotwired.dev/handbook/introduction
- Sorbet: https://sorbet.org/
- Tapioca: https://github.com/Shopify/tapioca
- Kamal: https://kamal-deploy.org/
- Mission Control Jobs: https://github.com/rails/mission_control-jobs
- Propshaft: https://github.com/rails/propshaft
- RuboCop: https://docs.rubocop.org/rubocop/
- Standard Ruby: https://github.com/standardrb/standard
- Brakeman: https://brakemanscanner.org/
- Hanami: https://hanamirb.org/
- Roda: https://roda.jeremyevans.net/
- Sinatra: https://sinatrarb.com/
- dry-rb: https://dry-rb.org/
- Rom-rb: https://rom-rb.org/
- 37signals "Leaving the Cloud": https://world.hey.com/dhh/we-have-left-the-cloud-251760fb
- Cookpad Tech Blog: https://techlife.cookpad.com/
- Mercari Engineering Blog: https://engineering.mercari.com/en/
- RubyKaigi: https://rubykaigi.org/
- Shopify Engineering on YJIT: https://shopify.engineering/yjit-just-in-time-compiler-for-ruby
- GitHub on Modular Monoliths: https://github.blog/2022-08-03-monoliths-and-microservices/