layered-rails について
layered-railsは、Rails開発にレイヤードアーキテクチャの原則を適用するスキルです。コードベースの監査、レビュー、段階的な導入計画、パターン選定のワークフローを備えています。
主な機能
- 01アーキテクチャとレイヤー境界の監査
- 02変更内容のレイヤー違反レビュー
- 03コードが適切なレイヤーに属するか検証
- 04段階的なアーキテクチャ導入の計画
- 05CI向けArchSpecチェックの生成
活用シーン
- 01Railsコードベースの監査
- 02差分のレイヤー違反レビュー
- 03段階的なリファクタリング計画
- 04CIでの境界ルール適用
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ palkan/ layered-rails-skills --skill layered-railsインストール後、Claude Code で/layered-railsを入力して読み込まれたか確認します。
同梱ファイル
SKILL.md と一緒にインストールされる参考資料やスクリプト。
examples/authorization-to-policy.mdcallbacks-to-service.mdcomplex-input-to-form-object.mdcurrent-from-model.mdgod-object-decomposition.mdimplicit-to-explicit-state-machine.mdquery-to-query-object.mdview-logic-to-presenter.mdreferences/anti-patterns/callbacks.mdconcerns.mdhelpers.mdjobs.mdlayer-violations.mdservice-objects.mdtesting.mdreferences/core/architecture-layers.mdextraction-signals.mdspecification-test.mdreferences/gems/action-policy.mdactive-agent.mdactive-delivery.mdactive-job-performs.mdalba.mdanyway-config.mdarchspec.mdrubanok.mdview-component.mdworkflow.mdreferences/patterns/collaborator-objects.mdconcerns.md詳細
レイヤー化されたRails
レイヤーアーキテクチャの原則を用いて、Railsアプリケーションを設計・レビューします。
クイックスタート
Railsアプリケーションは、一方向のデータフローを持つ4つのアーキテクチャレイヤーで構成されます。
┌─────────────────────────────────────────┐
│ PRESENTATION LAYER │
│ Controllers, Views, Channels, Jobs* │
│ Forms, Filters, Presenters, Serializers │
└─────────────────────────────────────────┘
↓
┌─────────────────────────────────────────┐
│ APPLICATION LAYER │
│ Services, Policies, Mailers, Deliveries │
└─────────────────────────────────────────┘
↓
┌─────────────────────────────────────────┐
│ DOMAIN LAYER │
│ Models, Value Objects, Query Objects │
└─────────────────────────────────────────┘
↓
┌─────────────────────────────────────────┐
│ INFRASTRUCTURE LAYER │
│ Active Record, API Clients, Storage │
└─────────────────────────────────────────┘
* ジョブは内部のインバウンドエントリポイントです。設計上は、認証とユーザー入力の処理を除き、コントローラーと同じルールに従います。
**コアルール:**下位レイヤーは上位レイヤーに依存してはなりません。
各レイヤーの責務の詳細と「4つのルール」の解説については、アーキテクチャレイヤーのリファレンスを参照してください。
このスキルの用途
次の場合にこのスキルを使用します。
- コードベースの分析 — 全体を監査するにはアーキテクチャ分析を適用し、対象を絞るにはサービスレイヤー監査、コールバック分析、またはゴッドオブジェクト分析を使用します。
- コード変更のレビュー — 差分、ファイル、またはブランチに対してコードレビューワークフローを実行します。
- 仕様テストの実施 — 単一のファイルまたはディレクトリに対して仕様テストワークフローを使用し、コードが現在のレイヤーに属するかどうかを評価します。
- 段階的な導入の計画 — 「認可の導入」や「ゴッドオブジェクトの分解」などの目標に焦点を当て、レイヤー化計画ワークフローで段階的なロードマップを作成します。
- 機能の計画 — これから作成するコードに、以下のレイヤー化の原則を適用します。
- 特定のパターンの実装 — 認可、通知、ビューコンポーネント、AI 統合などについては、以下のパターンカタログとトピック別リファレンスを参照してください。
このスキルをプラグインとしてインストールした Claude Code(/plugin install layered-rails@layered-rails-skills)では、上記の各ワークフローをスラッシュコマンドからも実行できます。スラッシュコマンドを参照してください。「layered-rails でこのファイルをレビューして」「app/models/order.rb に対して仕様テストを実行して」などの自然言語でのリクエストは、このスキルが読み込まれている環境であればどこでも利用できます。
ワークフロー
このスキルに含まれる再利用可能な手順です。ファイルを読み、対象のコードに適用してください。
- アーキテクチャ分析 — Railsコードベースのレイヤーアーキテクチャを全体的に監査します
- コードレビュー — レイヤー違反がないか、差分またはファイルセットをレビューします
- 仕様テスト — コードが現在のレイヤーに属するかどうかを評価します
- サービスレイヤー監査 —
app/services/とサービスに類するクラスを詳細に監査します(クラスタごとの提案、契約、レイヤーの適切性) - コールバック分析 — Active Record のコールバックを評価し、切り出し候補を特定します
- ゴッドオブジェクト分析 — 肥大化したモデルを特定し、分解方法を提案します
- 段階的なレイヤー化計画 — レイヤーパターンを段階的に導入するためのロードマップです
- ArchSpec のセットアップ — CI でレイヤー境界を強制するために、カスタマイズした
Archspec.rbを生成し、検証します
コア原則
4つのルール
- 一方向のデータフロー — データは上から下へのみ流れます
- 逆方向の依存なし — 下位レイヤーは上位レイヤーに依存しません
- 抽象化の境界 — 各抽象化は1つのレイヤーにのみ属します
- 接続を最小限にする — レイヤー間の接続が少ないほど、結合度が低くなります
よくある違反
| 違反 | 例 | 修正 |
|---|---|---|
| モデルが Current を使用 | モデル内の Current.user | user を明示的なパラメータとして渡す |
| サービスが request を受け取る | サービス内の param :request | request から値オブジェクトを抽出 |
| コントローラーにビジネスロジックがある | アクション内の価格計算 | サービスまたはモデルに抽出 |
| 貧血モデル | すべてのロジックがサービスにある | ドメインロジックをモデルに保つ |
| カテゴリ | 参照 |
|---|---|
| レイヤー違反 (モデル内の Current、サービス内の request、モデル内の通知、コントローラー内のビジネスロジック) | layer-violations.md |
| サービスオブジェクト (貧血モデル、雑多なオブジェクトの寄せ集め、早すぎる抽象化) | service-objects.md |
| コールバック (操作コールバック、コールバックのスキップ、制御フラグ) | callbacks.md |
| Concern (コードの断片化、肥大化) | concerns.md |
| ヘルパー (ヘルパー内での HTML 構築) | helpers.md |
| ジョブ (貧血ジョブ) | jobs.md |
| テスト (誤ったレイヤーのテスト) | testing.md |
仕様テスト
オブジェクトの仕様が、その抽象化レイヤーの主要な責務を超える機能を記述している場合、そのような機能は下位レイヤーに抽出すべきです。
適用方法:
- コードが処理する責務を列挙する
- それぞれをレイヤーの主要な関心事に対して評価する
- 誤った場所にある責務を適切なレイヤーに抽出する
詳細なガイドについては 仕様テストの参照 を参照してください。
パターンカタログ
| パターン | レイヤー | 使用する場合 | 参照 |
|---|---|---|---|
| サービスオブジェクト | アプリケーション | ドメイン操作のオーケストレーション | service-objects.md |
| クエリオブジェクト | ドメイン | 複雑で再利用可能なクエリ | query-objects.md |
| フォームオブジェクト | プレゼンテーション | 複数モデルのフォーム、複雑なバリデーション | form-objects.md |
| フィルターオブジェクト | プレゼンテーション | リクエストパラメータの変換 | filter-objects.md |
| プレゼンター | プレゼンテーション | ビュー固有のロジック、複数のモデル | presenters.md |
| シリアライザー | プレゼンテーション | API レスポンスのフォーマット | serializers.md |
| ポリシーオブジェクト | アプリケーション | 認可の決定 | policy-objects.md |
| 値オブジェクト | ドメイン | 不変で同一性を持たない概念 | value-objects.md |
| コラボレーターオブジェクト | ドメイン | 型付きデリゲート内の 1 つのモデルの振る舞いの断片 | collaborator-objects.md |
| ステートマシン | ドメイン | 状態、イベント、遷移 | state-machines.md |
| Concern | ドメイン | 共有される振る舞いの抽出 | concerns.md |
| リポジトリ | ドメイン | 最後の手段 — AR スコープ (シンプル) とクエリオブジェクト (クエリ構築) では不十分な場合に、AR データからマッピングされたカスタムドメインオブジェクトを返す | repositories.md |
パターン選択ガイド
「このコードはどこに置けばよいですか?」
| 次のような場合は…… | 次を検討してください…… |
|---|---|
| 複雑な複数モデルのフォーム | Form Object |
| リクエストパラメーターのフィルタリング/変換 | Filter Object |
| ビュー固有のフォーマット | Presenter |
| 複数箇所で使われる複雑なデータベースクエリ | Query Object |
| 複数のモデルにまたがるビジネス処理 | Service Object(待合室として) |
| 認可ルール | Policy Object |
| 複数チャネルへの通知 | Delivery Object(Active Delivery) |
覚えておいてください: サービスは、適切な抽象化が生まれるまでコードを置いておくための「待合室」です。app/servicesを無秩序なオブジェクトの寄せ集めにしないでください。
リファクタリングのシナリオ
最も一般的なレイヤー化の変更について、標準的な変更前/変更後の例を示します。レイヤー化計画ワークフローでは、フェーズを提案する際にこれらを参照テンプレートとして使用します。
| シナリオ | 対象領域 | 参照 |
|---|---|---|
| コールバックをサービスに切り出す | コールバック、after_createチェーン | callbacks-to-service.md |
| 認可をポリシーに切り出す | 認可、権限 | authorization-to-policy.md |
| クエリロジックをクエリオブジェクトに切り出す | 複雑なスコープ、レポート用クエリ | query-to-query-object.md |
| モデルからCurrentを切り出す | ドメイン内のCurrent.* | current-from-model.md |
| 関連オブジェクトを使って巨大なオブジェクトを分解する | 巨大なモデル、大規模なUser/Account | god-object-decomposition.md |
| 暗黙的なステートマシンを置き換える | タイムスタンプベースのステータス | implicit-to-explicit-state-machine.md |
| ビューロジックをプレゼンターに切り出す | テンプレートロジック、フォーマット | view-logic-to-presenter.md |
| 複雑な入力にForm Objectを使用する | 肥大化したコントローラー、複数モデルのフォーム | complex-input-to-form-object.md |
スラッシュコマンド
これらのスラッシュコマンドを使用できるのは、このスキルがClaude Codeプラグイン(/plugin install layered-rails@layered-rails-skills)としてインストールされている場合のみです。スキルがskills.shまたは、周囲のプラグインを含まずにskills/layered-rails/を提供するその他の方法でインストールされている場合、コマンドは利用できません。その場合は、対応するワークフローを直接実行する(ワークフローを参照)か、通常の言葉で依頼してください。
| コマンド | ワークフロー | 目的 |
|---|---|---|
/layered-rails:review | review | レイヤードアーキテクチャの観点からコード変更をレビューする |
/layered-rails:spec-test | spec-test | 特定のファイルで仕様テストを実行する |
/layered-rails:analyze | analyze | コードベース全体の抽象化レイヤーを分析する |
/layered-rails:analyze-services | analyze-services | app/services/とサービスに似たクラスを監査する — 規約、クラスター、レイヤーの健全性、テストへの影響 |
/layered-rails:analyze-callbacks | analyze-callbacks | モデルのコールバックを評価し、切り出し候補を見つける |
/layered-rails:analyze-gods | analyze-gods | 変更頻度×複雑さを用いて巨大なオブジェクトを見つける |
/layered-rails:plan [goal] | plan | レイヤードパターンを段階的に導入する計画を立てる |
/layered-rails:archspec | archspec | CIでレイヤー境界を強制するArchspec.rbを生成し、検証する |
トピック別リファレンス
特定のトピックについて詳しく知りたい場合:
| トピック | リファレンス |
|---|---|
| 認可(RBAC、ABAC、ポリシー) | authorization.md |
| 通知(マルチチャネル配信) | notifications.md |
| ビューコンポーネント | view-components.md |
| AI 統合(LLM、エージェント、RAG、MCP) | ai-integration.md |
| 設定 | configuration.md |
| コールバック(スコアリング、抽出) | callbacks.md |
| Current 属性 | current-attributes.md |
| インストルメンテーション(ログ、メトリクス) | instrumentation.md |
Gem リファレンス
ライブラリ固有のガイダンス:
| Gem | 用途 | リファレンス |
|---|---|---|
| action_policy | 認可フレームワーク | action-policy.md |
| view_component | コンポーネントフレームワーク | view-component.md |
| anyway_config | 型付き設定 | anyway-config.md |
| active_delivery | マルチチャネル通知 | active-delivery.md |
| alba | JSON シリアライズ | alba.md |
| workflow | ステートマシン | workflow.md |
| rubanok | フィルター/変換 DSL | rubanok.md |
| active_agent | AI エージェントフレームワーク | active-agent.md |
| active_job-performs | 貧血ジョブを解消 | active-job-performs.md |
| archspec | CI でレイヤー境界を強制(Archspec.rb 設定を参照) | archspec.md |
抽出の判断基準
モデルから抽出するタイミング:
| 判断基準 | 指標 | 対応 |
|---|---|---|
| ゴッドオブジェクト | 変更頻度 × 複雑度が高い | Concern、委譲先、または別のモデルに分解する |
| 操作コールバック | スコア 1-2/5 | サービスまたはイベントハンドラーに抽出する |
| コード種別で分割された Concern | 成果物の種類ごとにグループ化されている | 振る舞いを表す Concern に変更するか、抽出する |
| Current への依存 | モデルが Current.* を読み取る | 明示的なパラメーターとして渡す |
コールバックのスコアリング:
| 種類 | スコア | 残す? |
|---|---|---|
| 変換器(値を計算する) | 5/5 | はい |
| 正規化器(入力をサニタイズする) | 4/5 | はい |
| ユーティリティ(カウンターキャッシュ) | 4/5 | はい |
| オブザーバー(副作用) | 2/5 | 場合による |
| 操作(ビジネス上の手順) | 1/5 | 抽出する |
詳しいガイドは抽出の判断基準リファレンスを参照してください。
モデルの構成
モデルファイル内の推奨順序:
class User < ApplicationRecord
# 1. Gems/DSL extensions
has_secure_password
# 2. Associations
belongs_to :account
has_many :posts
# 3. Enums
enum :status, { pending: 0, active: 1 }
# 4. Normalization
normalizes :email, with: -> { _1.strip.downcase }
# 5. Validations
validates :email, presence: true
# 6. Scopes
scope :active, -> { where(status: :active) }
# 7. Callbacks (transformers only)
before_validation :set_defaults
# 8. Delegations
delegate :name, to: :account, prefix: true
# 9. Public methods
def full_name = "#{first_name} #{last_name}"
# 10. Private methods
private
def set_defaults
self.locale ||= I18n.default_locale
end
end
成功チェックリスト
適切にレイヤー分けされたコード:
- 逆方向の依存関係がない(下位レイヤーが上位レイヤーに依存しない)
- モデルが Current 属性にアクセスしない
- サービスがリクエストオブジェクトを受け取らない
- コントローラーが薄い(HTTP 関連の処理のみ)
- ドメインロジックがサービスではなくモデルにある
- コールバックのスコアが 4 以上、または抽出されている
- Concern がコード種別で分割されず、振る舞いを表している
- 抽象化が複数のレイヤーにまたがらない
- テストが適切なレイヤーの責務を検証している
ガイドライン
- ドメインの言葉を使う - モデルにはビジネス概念に基づいた名前を付けます(User ではなく Participant、GeneratedImage ではなく Cloud)
- 抽象化よりパターンを優先する - 抽出する前にコードを十分に使い込みます。早すぎる抽象化は重複よりも悪い結果を招きます
- サービスは待合室 -
app/servicesをコードの恒久的な置き場所にしないでください - 暗黙的より明示的に - Current 属性よりも明示的なパラメーターを優先します
- 抽出の基準 - メソッドが 15 行を超える場合や外部 API を呼び出す場合は、抽出を検討します