layered-rails について
layered-railsは、単純なパターンでは対応しにくくなったアプリを扱うRails開発者向けのガイダンススキルです。4層アーキテクチャ、コード配置の判断、責務を抽出する目安を解説し、小規模アプリでは簡潔さを勧めます。
主な機能
- 01Railsの4層構造と依存ルール
- 02層ごとのコード配置ガイダンス
- 03抽出の目安とコールバック評価
- 04パターン選択と関連スキルの案内
- 05モデル構成と複雑度の指針
活用シーン
- 01新しいRailsコードの配置先の判断
- 02層の違反やリファクタリング対象の特定
- 03コールバックの評価と副作用の抽出
- 04複雑なRailsドメインへの構造追加
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ majesticlabs-dev/ majestic-marketplace --skill layered-railsインストール後、Claude Code で/layered-railsを入力して読み込まれたか確認します。
同梱ファイルreferences/extraction-signals.mdreferences/pattern-catalog.md
詳細
レイヤード Rails アーキテクチャ
対象読者: 単一ファイルのパターンでは対応しきれなくなったアプリケーションに取り組む Rails 開発者。 目標: コードをどのレイヤーに配置するか、いつ抽出するか、実装にどの既存スキルを使うかを把握します。
4 層アーキテクチャ
Presentation → Application → Domain → Infrastructure
(HTTP/UI) (Orchestration) (Business) (Persistence/APIs)
基本ルール: 下位レイヤーは上位レイヤーに依存してはなりません。データは上から下へのみ流れます。
レイヤーの責務
| レイヤー | 担当するもの | 担当しないもの |
|---|---|---|
| プレゼンテーション | HTTP に関する処理、パラメーター、レンダリング、チャネル、メーラー | ビジネスロジック、直接的な DB クエリー |
| アプリケーション | モデル間のオーケストレーション、認可、フォームの検証 | 永続化の詳細、レンダリング |
| ドメイン | ビジネスルール、検証、関連付け、値オブジェクト | HTTP コンテキスト、リクエストオブジェクト、Current.* |
| インフラストラクチャ | ActiveRecord、外部 API、ファイルストレージ、キャッシュ | ビジネスルール、プレゼンテーション |
よくあるレイヤー違反
| 違反 | 問題である理由 | 修正方法 |
|---|---|---|
モデル内の Current.user | ドメインがプレゼンテーションのコンテキストに依存している | ユーザーを明示的なパラメーターとして渡す |
サービス内の request パラメーター | アプリケーションがプレゼンテーションに依存している | サービスを呼び出す前に必要な値を取り出す |
| コントローラー内の料金計算 | ビジネスロジックがプレゼンテーションにある | モデルメソッドまたはサービスに移す |
| すべてのロジックをサービスに置き、モデルを貧血状態にする | ドメインレイヤーが空洞化している | ドメインロジックはモデルに置き、サービスはオーケストレーションを担う |
| モデルからメールを直接送信する | ドメインがインフラストラクチャの副作用に依存している | データ変換にはコールバックのみを使い、メール送信は切り出す |
仕様テスト
コードの配置場所が適切かを診断します。
- オブジェクトが担う責務をすべて列挙します
- それぞれについて、「これはこのレイヤーの主な関心事に属するか?」と確認します
- いいえの場合 → 適切なレイヤーに抽出します
例: 認証、アバター処理、通知設定、アクティビティログを担う User モデル。
- 認証 → ドメイン(そのままにする)
- アバター処理 → インフラストラクチャ(サービス/ジョブに抽出)
- 通知設定 → ドメイン(コンサーンとしてそのままにする)
- アクティビティログ → インフラストラクチャ(オブザーバー/イベントに抽出)
手法の全容については、references/extraction-signals.md を参照してください。
コールバックの評価
各コールバックを 1〜5 で評価します。スコアが 1〜2 のものはすべて抽出します。
| スコア | 種類 | 例 | 対応 |
|---|---|---|---|
| 5 | 変換 | before_validation :normalize_email | そのままにする |
| 4 | 正規化 | before_save :strip_whitespace | そのままにする |
| 4 | ユーティリティ | after_create :update_counter_cache | そのままにする |
| 2 | オブザーバー | after_save :notify_admin | 抽出を検討 |
| 1 | オペレーション | after_create :send_welcome_email, :provision_account | 抽出する |
目安: コールバックを削除するとモデル自身のデータ整合性が損なわれる場合は、そのままにします。外部への副作用を引き起こす場合は、抽出します。
パターンの選択
「このコードはどこに置けばよいでしょうか?」
| 状況 | パターン | レイヤー | スキル |
|---|---|---|---|
| 複雑な複数モデルのフォーム | Form Object | プレゼンテーション | — |
| リクエストパラメーターのフィルタリング | Filter Object | プレゼンテーション | — |
| ビュー固有のフォーマット | Presenter / ViewComponent | プレゼンテーション | viewcomponent-coder |
| 認可ルール | Policy Object | アプリケーション | action-policy-coder |
| ビジネス操作(1回限り) | Service / Interaction | アプリケーション | active-interaction-coder |
| 複数モデルのオーケストレーション | Service Object | アプリケーション | active-interaction-coder |
| 状態ライフサイクルの管理 | State Machine | ドメイン | aasm-coder |
| 複雑で再利用可能なクエリ | Query Object | ドメイン | — |
| 不変の概念(Money、DateRange) | Value Object | ドメイン | — |
| モデル間で共有する振る舞い | Concern | ドメイン | — |
| 型付き設定 | Config Object | インフラストラクチャ | anyway-config-coder |
| ドメインイベント/監査証跡 | Event Sourcing | インフラストラクチャ | event-sourcing-coder |
| JSON に保存される属性 | Store Model | ドメイン | store-model-coder |
判断ツリー
Is it about HTTP/params/rendering?
YES → Presentation layer
Multi-model form? → Form Object
Filtering params? → Filter Object
Formatting for view? → Presenter or ViewComponent
NO ↓
Is it authorization?
YES → Policy Object (action-policy-coder)
NO ↓
Does it orchestrate multiple models/services?
YES → Application layer
One-time operation? → Service/Interaction (active-interaction-coder)
Needs typed inputs? → ActiveInteraction (active-interaction-coder)
NO ↓
Is it a business rule about a single model?
YES → Domain layer (keep in model or concern)
Has state transitions? → AASM (aasm-coder)
Reusable query? → Query Object
Immutable value? → Value Object
NO ↓
Is it about persistence/external APIs/caching?
YES → Infrastructure layer
サービスは待合室
app/services/ は一時的な置き場所であり、恒久的な場所ではありません。
- 生き残ったサービスは、最終的にそれが表す本当の抽象を明らかにするはずです
- サービスが単一モデルの操作をラップしている場合 → おそらくモデルに置くべきです
- サービスが3つ以上のモデルを連携させている場合 → 正当なオーケストレーターです
- サービスが複雑になってきた場合 → 内部に隠れている Form Object、Policy、Query Object を探します
においチェック: app/services/ にサブディレクトリがなく、ファイルが50個以上ある場合、待合室が恒久的な保管場所になっています。
抽出の兆候
既存の場所からコードを抽出するタイミング:
| 兆候 | しきい値 | 対応 |
|---|---|---|
| メソッドの長さ | 15行超 | メソッドまたはオブジェクトを抽出 |
| モデル内の外部 API 呼び出し | 1回でも | サービス/ゲートウェイに抽出 |
| 神オブジェクト | 高い変更頻度 × 高い複雑度 | 分解(references/extraction-signals.md を参照) |
| 仕様がレイヤーの関心事を超えている | 仕様テストに失敗 | 適切なレイヤーに抽出 |
| コールバックのスコア | 1~2/5 | サービスまたはイベントハンドラーに抽出 |
| クエリロジックの重複 | 2か所以上 | Query Object を抽出 |
モデル内の Current.* | 使用箇所がある | 明示的なパラメーターとして渡す |
完全な方法については、references/extraction-signals.md を参照してください。
モデルの整理
モデルファイル内の推奨される順序:
class Order < ApplicationRecord
# 1. Extensions/DSL (has_secure_password, acts_as_*)
# 2. Associations
# 3. Enums
# 4. Normalizations
# 5. Validations
# 6. Scopes
# 7. Callbacks (transformers/normalizers only — score 4-5)
# 8. Delegations
# 9. Public methods
# 10. Private methods
end
レイヤードスタイルとDHHスタイルの使い分け
このスキルは dhh-coder を補完するものであり、置き換えるものではありません。
| 状況 | 使用するもの |
|---|---|
| 小規模/中規模アプリ、標準的な CRUD | dhh-coder — シンプルに保つ |
| 複雑なドメイン、複数の境界づけられたコンテキスト | layered-rails — 構造を追加する |
| 単純なチェックを超える認可 | レイヤードガイダンス経由で action-policy-coder |
| 500行を超える肥大化したモデル | layered-rails の抽出の兆候 |
| 標準的なコントローラーアクション | dhh-coder — 7つの REST アクション |
| 複数ステップのビジネス操作 | レイヤードガイダンス経由で active-interaction-coder |
まずはシンプルさを優先してください。 複雑さが求める場合にのみ、レイヤードパターンを採用します。
成功チェックリスト
- 逆方向の依存関係がない(下位レイヤーが上位レイヤーを参照しない)
- モデルが
Currentの属性にアクセスしない - サービスがリクエスト/コントローラーオブジェクトを受け取らない
- コントローラーに含まれるのは HTTP に関する処理のみ
- ドメインロジックはサービスに漏れず、モデルに置かれている
- すべてのコールバックのスコアが4以上(または抽出済み)
- Concern は成果物の種類ではなく、振る舞いごとにまとめられている
- 各抽象は1つのレイヤーにのみ属している
Cross-References
| Need | Skill |
|---|---|
| Authorization policies | action-policy-coder |
| Typed business operations | active-interaction-coder |
| State machines | aasm-coder |
| Operations + state routing | business-logic-coder |
| ViewComponents | viewcomponent-coder |
| Typed configuration | anyway-config-coder |
| Event sourcing / audit | event-sourcing-coder |
| JSON attributes | store-model-coder |
| Refactoring execution | rails-refactorer |
| DHH-style simplicity | dhh-coder |
| Pattern catalog details | references/pattern-catalog.md |
| Extraction methodology | references/extraction-signals.md |