layered-rails
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseLayered Rails
分层架构的Rails应用
Design and review Rails applications using layered architecture principles.
运用分层架构原则来设计和评审Rails应用。
Quick Start
快速开始
Rails applications are organized into four architecture layers with unidirectional data flow:
┌─────────────────────────────────────────┐
│ PRESENTATION LAYER │
│ Controllers, Views, Channels, Mailers │
└─────────────────────────────────────────┘
↓
┌─────────────────────────────────────────┐
│ APPLICATION LAYER │
│ Service Objects, Form Objects, etc. │
└─────────────────────────────────────────┘
↓
┌─────────────────────────────────────────┐
│ DOMAIN LAYER │
│ Models, Value Objects, Domain Events │
└─────────────────────────────────────────┘
↓
┌─────────────────────────────────────────┐
│ INFRASTRUCTURE LAYER │
│ Active Record, APIs, File Storage │
└─────────────────────────────────────────┘Core Rule: Lower layers must never depend on higher layers.
Rails应用被组织为四个架构层,遵循单向数据流:
┌─────────────────────────────────────────┐
│ PRESENTATION LAYER │
│ Controllers, Views, Channels, Mailers │
└─────────────────────────────────────────┘
↓
┌─────────────────────────────────────────┐
│ APPLICATION LAYER │
│ Service Objects, Form Objects, etc. │
└─────────────────────────────────────────┘
↓
┌─────────────────────────────────────────┐
│ DOMAIN LAYER │
│ Models, Value Objects, Domain Events │
└─────────────────────────────────────────┘
↓
┌─────────────────────────────────────────┐
│ INFRASTRUCTURE LAYER │
│ Active Record, APIs, File Storage │
└─────────────────────────────────────────┘核心规则: 下层绝不能依赖上层。
What Would You Like To Do?
你想执行哪些操作?
- Analyze codebase - Run for full analysis or
/layers:analyze,/layers:analyze:callbacksfor specific checks/layers:analyze:gods - Review code changes - Run for layered architecture review
/layers:review - Run specification test - Run on specific files
/layers:spec-test - Plan gradual adoption - Run to plan incremental layerification
/layers:gradual [goal] - Plan feature implementation - I'll guide you using layered principles
- Implement specific pattern - I'll help with authorization, notifications, view components, AI integration, etc.
- 分析代码库 - 运行 进行全面分析,或运行
/layers:analyze、/layers:analyze:callbacks进行专项检查/layers:analyze:gods - 评审代码变更 - 运行 进行分层架构评审
/layers:review - 运行规范测试 - 对特定文件运行
/layers:spec-test - 规划逐步落地 - 运行 来规划分层架构的增量落地
/layers:gradual [goal] - 规划功能实现 - 我会基于分层原则为你提供指导
- 实现特定模式 - 我会协助你实现授权、通知、视图组件、AI集成等模式
Core Principles
核心原则
The Four Rules
四大规则
- Unidirectional Data Flow - Data flows top-to-bottom only
- No Reverse Dependencies - Lower layers never depend on higher layers
- Abstraction Boundaries - Each abstraction belongs to exactly one layer
- Minimize Connections - Fewer inter-layer connections = looser coupling
- 单向数据流 - 数据仅从上到下流动
- 无反向依赖 - 下层绝不能依赖上层
- 抽象边界 - 每个抽象仅属于一个层级
- 最小化连接 - 层间连接越少,耦合度越低
Common Violations
常见违规情况
| Violation | Example | Fix |
|---|---|---|
| Model uses Current | | Pass user as explicit parameter |
| Service accepts request | | Extract value object from request |
| Controller has business logic | Pricing calculations in action | Extract to service or model |
| Anemic models | All logic in services | Keep domain logic in models |
See Anti-Patterns Reference for complete list.
| 违规类型 | 示例 | 修复方案 |
|---|---|---|
| 模型使用Current | | 将用户作为显式参数传入 |
| 服务接收request | 服务中使用 | 从request中提取值对象 |
| 控制器包含业务逻辑 | 动作中包含定价计算 | 提取到服务或模型中 |
| 贫血模型 | 所有逻辑都在服务中 | 将领域逻辑保留在模型中 |
完整列表请查看 反模式参考。
The Specification Test
规范测试
If the specification of an object describes features beyond the primary responsibility of its abstraction layer, such features should be extracted into lower layers.
How to apply:
- List responsibilities the code handles
- Evaluate each against the layer's primary concern
- Extract misplaced responsibilities to appropriate layers
See Specification Test Reference for detailed guide.
如果一个对象的规范描述超出了其抽象层的主要职责,这些功能应被提取到更低层级。
应用方法:
- 列出代码处理的所有职责
- 逐一评估每个职责是否符合所在层级的核心关注点
- 将错位的职责提取到合适的层级
详细指南请查看 规范测试参考。
Pattern Catalog
模式目录
| Pattern | Layer | Use When | Reference |
|---|---|---|---|
| Service Object | Application | Orchestrating domain operations | service-objects.md |
| Query Object | Domain | Complex, reusable queries | query-objects.md |
| Form Object | Presentation | Multi-model forms, complex validation | form-objects.md |
| Filter Object | Presentation | Request parameter transformation | filter-objects.md |
| Presenter | Presentation | View-specific logic, multiple models | presenters.md |
| Serializer | Presentation | API response formatting | serializers.md |
| Policy Object | Application | Authorization decisions | policy-objects.md |
| Value Object | Domain | Immutable, identity-less concepts | value-objects.md |
| State Machine | Domain | States, events, transitions | state-machines.md |
| Concern | Domain | Shared behavioral extraction | concerns.md |
| 模式 | 层级 | 适用场景 | 参考文档 |
|---|---|---|---|
| Service Object | 应用层 | 编排领域操作 | service-objects.md |
| Query Object | 领域层 | 复杂、可复用的查询 | query-objects.md |
| Form Object | 表示层 | 多模型表单、复杂验证 | form-objects.md |
| Filter Object | 表示层 | 请求参数转换 | filter-objects.md |
| Presenter | 表示层 | 视图特定逻辑、多模型处理 | presenters.md |
| Serializer | 表示层 | API响应格式化 | serializers.md |
| Policy Object | 应用层 | 授权决策 | policy-objects.md |
| Value Object | 领域层 | 不可变、无标识的概念 | value-objects.md |
| State Machine | 领域层 | 状态、事件、转换 | state-machines.md |
| Concern | 领域层 | 提取共享行为 | concerns.md |
Pattern Selection Guide
模式选择指南
"Where should this code go?"
| If you have... | Consider... |
|---|---|
| Complex multi-model form | Form Object |
| Request parameter filtering/transformation | Filter Object |
| View-specific formatting | Presenter |
| Complex database query used in multiple places | Query Object |
| Business operation spanning multiple models | Service Object (as waiting room) |
| Authorization rules | Policy Object |
| Multi-channel notifications | Delivery Object (Active Delivery) |
Remember: Services are a "waiting room" for code until proper abstractions emerge. Don't let become a bag of random objects.
app/services“这段代码应该放在哪里?”
| 如果你有... | 考虑使用... |
|---|---|
| 复杂的多模型表单 | Form Object |
| 请求参数过滤/转换 | Filter Object |
| 视图特定格式化 | Presenter |
| 多处使用的复杂数据库查询 | Query Object |
| 跨多模型的业务操作 | Service Object(作为过渡) |
| 授权规则 | Policy Object |
| 多渠道通知 | Delivery Object(Active Delivery) |
注意: Service Object是代码的“过渡区”,直到合适的抽象出现。不要让 变成存放随机对象的“垃圾袋”。
app/servicesCommands Reference
命令参考
| Command | Purpose |
|---|---|
| Review code changes from layered architecture perspective |
| Run specification test on specific files |
| Full codebase abstraction layer analysis |
| Score model callbacks, find extraction candidates |
| Find God objects via churn × complexity |
| Plan gradual adoption of layered patterns |
| 命令 | 用途 |
|---|---|
| 从分层架构角度评审代码变更 |
| 对特定文件运行规范测试 |
| 全面分析代码库的抽象层级 |
| 评分模型回调,寻找可提取的候选 |
| 通过变更频率×复杂度寻找上帝对象 |
| 规划分层模式的逐步落地 |
Topic References
主题参考
For deep dives on specific topics:
| Topic | Reference |
|---|---|
| Authorization (RBAC, ABAC, policies) | authorization.md |
| Notifications (multi-channel delivery) | notifications.md |
| View Components | view-components.md |
| AI Integration (LLM, agents, RAG, MCP) | ai-integration.md |
| Configuration | configuration.md |
| Callbacks (scoring, extraction) | callbacks.md |
| Current Attributes | current-attributes.md |
| Instrumentation (logging, metrics) | instrumentation.md |
特定主题的深入探讨:
| 主题 | 参考文档 |
|---|---|
| 授权(RBAC、ABAC、策略) | authorization.md |
| 通知(多渠道投递) | notifications.md |
| 视图组件 | view-components.md |
| AI集成(LLM、Agent、RAG、MCP) | ai-integration.md |
| 配置 | configuration.md |
| 回调(评分、提取) | callbacks.md |
| Current属性 | current-attributes.md |
| Instrumentation(日志、指标) | instrumentation.md |
Gem References
Gem参考
For library-specific guidance:
| Gem | Purpose | Reference |
|---|---|---|
| action_policy | Authorization framework | action-policy.md |
| view_component | Component framework | view-component.md |
| anyway_config | Typed configuration | anyway-config.md |
| active_delivery | Multi-channel notifications | active-delivery.md |
| alba | JSON serialization | alba.md |
| workflow | State machines | workflow.md |
| rubanok | Filter/transformation DSL | rubanok.md |
| active_agent | AI agent framework | active-agent.md |
| active_job-performs | Eliminate anemic jobs | active-job-performs.md |
特定库的使用指导:
| 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 Agent框架 | active-agent.md |
| active_job-performs | 消除贫血Job | active-job-performs.md |
Extraction Signals
提取信号
When to extract from models:
| Signal | Metric | Action |
|---|---|---|
| God object | High churn × complexity | Decompose into concerns, delegates, or separate models |
| Operation callback | Score 1-2/5 | Extract to service or event handler |
| Code-slicing concern | Groups by artifact type | Convert to behavioral concern or extract |
| Current dependency | Model reads Current.* | Pass as explicit parameter |
Callback Scoring:
| Type | Score | Keep? |
|---|---|---|
| Transformer (compute values) | 5/5 | Yes |
| Normalizer (sanitize input) | 4/5 | Yes |
| Utility (counter caches) | 4/5 | Yes |
| Observer (side effects) | 2/5 | Maybe |
| Operation (business steps) | 1/5 | Extract |
See Extraction Signals Reference for detailed guide.
何时从模型中提取代码:
| 信号 | 指标 | 操作 |
|---|---|---|
| 上帝对象 | 高变更频率×复杂度 | 分解为Concern、委托或独立模型 |
| 操作型回调 | 评分1-2/5 | 提取到服务或事件处理器 |
| 代码切片型Concern | 按 artifact 类型分组 | 转换为行为型Concern或提取 |
| 依赖Current | 模型读取Current.* | 作为显式参数传入 |
回调评分:
| 类型 | 评分 | 是否保留? |
|---|---|---|
| 转换器(计算值) | 5/5 | 是 |
| 归一化器(清理输入) | 4/5 | 是 |
| 工具类(计数器缓存) | 4/5 | 是 |
| 观察者(副作用) | 2/5 | 可考虑 |
| 操作型(业务步骤) | 1/5 | 提取 |
详细指南请查看 提取信号参考。
Model Organization
模型组织
Recommended order within model files:
ruby
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模型文件内的推荐顺序:
ruby
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
endSuccess Checklist
成功检查清单
Well-layered code:
- No reverse dependencies (lower layers don't depend on higher)
- Models don't access Current attributes
- Services don't accept request objects
- Controllers are thin (HTTP concerns only)
- Domain logic lives in models, not services
- Callbacks score 4+ or are extracted
- Concerns are behavioral, not code-slicing
- Abstractions don't span multiple layers
- Tests verify appropriate layer responsibilities
分层良好的代码:
- 无反向依赖(下层不依赖上层)
- 模型不访问Current属性
- 服务不接收request对象
- 控制器轻量化(仅处理HTTP相关逻辑)
- 领域逻辑位于模型中,而非服务中
- 回调评分4+或已被提取
- Concern是行为型的,而非代码切片型
- 抽象不跨多个层级
- 测试验证了层级职责的合理性
Guidelines
指导原则
- Use domain language - Name models after business concepts (Participant, not User; Cloud, not GeneratedImage)
- Patterns before abstractions - Let code age before extracting; premature abstraction is worse than duplication
- Services as waiting room - Don't let become permanent residence for code
app/services - Explicit over implicit - Prefer explicit parameters over Current attributes
- Extraction thresholds - Consider extraction when methods exceed 15 lines or call external APIs
- 使用领域语言 - 用业务概念为模型命名(如Participant而非User;Cloud而非GeneratedImage)
- 先模式后抽象 - 让代码沉淀后再提取;过早抽象比重复代码更糟糕
- 服务作为过渡区 - 不要让 成为代码的永久居所
app/services - 显式优于隐式 - 优先使用显式参数而非Current属性
- 提取阈值 - 当方法超过15行或调用外部API时,考虑提取