From compound-engineering
このスキルは、DHHの独特な37signalsスタイルでRubyおよびRailsコードを書く際に使用されるべきです。Rubyコード、Railsアプリケーションの作成、モデル、コントローラー、または任意のRubyファイルの作成時に適用されます。Ruby/Railsコード生成、リファクタリングリクエスト、コードレビュー、またはユーザーがDHH、37signals、Basecamp、HEY、Campfireスタイルに言及した場合にトリガーされます。RESTの純粋性、ファットモデル、薄いコントローラー、Current属性、Hotwireパターン、そして「賢さより明確さ」の哲学を体現します。
How this skill is triggered — by the user, by Claude, or both
Slash command
/compound-engineering:dhh-ruby-styleThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
DHHの哲学に従ってRubyとRailsコードを書く:**賢さより明確さ**、**設定より規約**、何よりも**開発者の幸福**。
DHHの哲学に従ってRubyとRailsコードを書く:賢さより明確さ、設定より規約、何よりも開発者の幸福。
index、show、new、create、edit、update、destroyclass MessagesController < ApplicationController
before_action :set_message, only: %i[ show edit update destroy ]
def index
@messages = @room.messages.with_creator.last_page
fresh_when @messages
end
def show
end
def create
@message = @room.messages.create_with_attachment!(message_params)
@message.broadcast_create
end
private
def set_message
@message = @room.messages.find(params[:id])
end
def message_params
params.require(:message).permit(:body, :attachment)
end
end
プライベートメソッドはprivateキーワードの下に1レベルインデント:
private
def set_message
@message = Message.find(params[:id])
end
def message_params
params.require(:message).permit(:body)
end
モデルはビジネスロジック、認可、ブロードキャストを所有:
class Message < ApplicationRecord
belongs_to :room
belongs_to :creator, class_name: "User"
has_many :mentions
scope :with_creator, -> { includes(:creator) }
scope :page_before, ->(cursor) { where("id < ?", cursor.id).order(id: :desc).limit(50) }
def broadcast_create
broadcast_append_to room, :messages, target: "messages"
end
def mentionees
mentions.includes(:user).map(&:user)
end
end
class User < ApplicationRecord
def can_administer?(message)
message.creator == self || admin?
end
end
リクエストコンテキストにはCurrentを使用、どこでもcurrent_userを渡さない:
class Current < ActiveSupport::CurrentAttributes
attribute :user, :session
end
# アプリ内のどこでも使用可能
Current.user.can_administer?(@message)
# 括弧内にスペースを入れたシンボル配列
before_action :set_message, only: %i[ show edit update destroy ]
# モダンハッシュ構文のみ
params.require(:message).permit(:body, :attachment)
# 1行ブロックには波括弧
users.each { |user| user.notify }
# シンプルな条件には三項演算子
@room.direct? ? @room.users : @message.mentionees
# フェイルファストにはバングメソッド
@message = Message.create!(params)
@message.update!(message_params)
# 述語メソッドには疑問符
@room.direct?
user.can_administer?(@message)
@messages.any?
# 式なしcaseでクリーンな条件分岐
case
when params[:before].present?
@room.messages.page_before(params[:before])
when params[:after].present?
@room.messages.page_after(params[:after])
else
@room.messages.last_page
end
| 要素 | 規約 | 例 |
|---|---|---|
| セッターメソッド | set_プレフィックス | set_message、set_room |
| パラメータメソッド | {model}_params | message_params |
| 関連付け名 | 汎用ではなく意味的 | userではなくcreator |
| スコープ | チェイン可能、説明的 | with_creator、page_before |
| 述語 | ?で終わる | direct?、can_administer? |
ブロードキャストはモデルの責任:
# モデル内
def broadcast_create
broadcast_append_to room, :messages, target: "messages"
end
# コントローラー内
@message.broadcast_replace_to @room, :messages,
target: [ @message, :presentation ],
partial: "messages/presentation",
attributes: { maintain_scroll: true }
特定の例外をレスキュー、バングメソッドでフェイルファスト:
def create
@message = @room.messages.create_with_attachment!(message_params)
@message.broadcast_create
rescue ActiveRecord::RecordNotFound
render action: :room_not_found
end
| 従来型 | DHH流 |
|---|---|
| PostgreSQL | SQLite(シングルテナント向け) |
| Redis + Sidekiq | Solid Queue |
| Redisキャッシュ | Solid Cache |
| Kubernetes | 単一Dockerコンテナ |
| サービスオブジェクト | ファットモデル |
| ポリシーオブジェクト(Pundit) | Userモデルでの認可 |
| FactoryBot | フィクスチャ |
包括的なパターンと例については以下を参照:
npx claudepluginhub rakutek/cc-compound-engineering --plugin compound-engineeringCreates structured, bite-sized implementation plans from specs or requirements before writing code. Useful for breaking down multi-step tasks into testable steps with file structure and task boundaries.