关于 layered-rails
layered-rails 是一项将分层架构原则应用于 Rails 开发的技能,提供代码库审计、代码评审、渐进式重构规划和模式选择工作流。
主要功能
- 01审计架构和层边界
- 02评审代码变更中的违规
- 03测试代码是否属于当前层
- 04规划渐进式架构改造
- 05生成用于 CI 的 ArchSpec 检查
适用场景
- 01审计 Rails 代码库
- 02检查差异中的层违规
- 03规划分阶段重构
- 04在 CI 中强制执行边界
安装
复制下面的命令,在终端中运行。
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 应用分为四个架构层,采用单向数据流:
┌─────────────────────────────────────────┐
│ 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 │
└─────────────────────────────────────────┘
* Job 是内部入站入口:从设计上看,它们遵循与控制器相同的规则,但无需处理身份验证和用户输入。
**核心规则:**低层绝不能依赖高层。
如需了解各层的完整职责以及“四项规则”的深入解析,请参阅架构分层参考。
此技能的用途
以下情况可使用此技能:
- 分析代码库——使用架构分析进行全面审计,或使用服务层审计、回调分析或巨型对象分析聚焦具体问题。
- 审查代码变更——针对 diff、文件或分支运行代码审查工作流。
- 运行规范测试——针对单个文件或目录使用规范测试工作流,评估代码是否属于当前所在层。
- 规划渐进式采用——使用分层改造计划工作流生成分阶段路线图,聚焦于“引入授权”或“拆解巨型对象”等目标。
- 规划功能——我会将以下分层原则应用到你即将编写的代码中。
- 实现特定模式——例如授权、通知、视图组件、AI 集成等。请参阅下文的模式目录和主题参考。
在安装了此技能插件的 Claude Code 中(/plugin install layered-rails@layered-rails-skills),上述每个工作流也可通过斜杠命令调用——请参阅斜杠命令。在加载了此技能的任何环境中,也可以使用自然语言请求(“使用 layered-rails 审查此文件”“对 app/models/order.rb 运行规范测试”)。
工作流
此技能中包含的可复用流程。读取文件并将其应用到目标代码:
- 架构分析——全面审计 Rails 代码库的分层架构
- 代码审查——审查 diff 或文件集,检查是否违反分层规则
- 规范测试——评估代码是否属于当前所在层
- 服务层审计——深入审计
app/services/和类似服务的类(按集群提出建议、检查契约和分层规范) - 回调分析——评估 Active Record 回调并寻找可提取的候选项
- 巨型对象分析——识别过于庞大的模型并提出拆解建议
- 渐进式分层改造计划——采用分层模式的渐进路线图
- ArchSpec 设置——生成并验证定制的
Archspec.rb,在 CI 中强制执行分层边界
核心原则
四项规则
- 单向数据流——数据只能从上向下流动
- 禁止反向依赖——低层绝不依赖高层
- 抽象边界——每个抽象只能属于一个层
- 尽量减少连接——层间连接越少,耦合越松散
常见违规
| 违规 | 示例 | 修复方法 |
|---|---|---|
| 模型使用 Current | 模型中的 Current.user | 将用户作为显式参数传入 |
| 服务接受请求 | 服务中的 param :request | 从请求中提取值对象 |
| 控制器包含业务逻辑 | 在 action 中进行定价计算 | 提取到服务或模型中 |
| 贫血模型 | 所有逻辑都在服务中 | 将领域逻辑保留在模型中 |
| 类别 | 参考 |
|---|---|
| 分层违规(模型中使用 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 |
| 协作者对象 | 领域层 | 在类型化委托对象中封装某个模型的一部分行为 | collaborator-objects.md |
| 状态机 | 领域层 | 状态、事件、转换 | state-machines.md |
| Concern | 领域层 | 提取共享行为 | concerns.md |
| 仓储 | 领域层 | 最后手段 — 在 AR 作用域(简单查询)和查询对象(构建查询)都无法满足需求后,返回由 AR 数据映射而来的自定义领域对象 | repositories.md |
模式选择指南
“这段代码应该放在哪里?”
| 如果你有…… | 可以考虑…… |
|---|---|
| 复杂的多模型表单 | 表单对象(Form Object) |
| 请求参数筛选/转换 | 筛选对象(Filter Object) |
| 特定于视图的格式化 | Presenter |
| 多处使用的复杂数据库查询 | 查询对象(Query Object) |
| 涉及多个模型的业务操作 | 服务对象(作为候置区) |
| 授权规则 | 策略对象(Policy Object) |
| 多渠道通知 | 交付对象(Delivery Object,Active Delivery) |
请记住: 服务是代码的“候置区”,用于暂存代码,直到出现合适的抽象。不要让 app/services 变成杂乱对象的集合。
重构场景
最常见分层改造的规范前后转换示例。分层改造计划工作流 会在提出阶段方案时将这些示例用作参考模板。
| 场景 | 目标区域 | 参考 |
|---|---|---|
| 将回调提取到服务中 | callbacks、after_create 链 | callbacks-to-service.md |
| 将授权提取到策略中 | authorization、permissions | 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 |
| 将视图逻辑提取到 Presenter 中 | 模板逻辑、格式化 | view-logic-to-presenter.md |
| 为复杂输入使用表单对象 | 臃肿控制器、多模型表单 | 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 | 生成并验证 Archspec.rb,以便在 CI 中强制执行分层边界 |
主题参考
深入了解特定主题:
| 主题 | 参考 |
|---|---|
| 授权(RBAC、ABAC、策略) | authorization.md |
| 通知(多渠道交付) | notifications.md |
| 视图组件 | view-components.md |
| AI 集成(LLM、Agent、RAG、MCP) | ai-integration.md |
| 配置 | configuration.md |
| 回调(评分、提取) | callbacks.md |
| 当前属性 | 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 Agent 框架 | active-agent.md |
| active_job-performs | 消除贫血任务 | active-job-performs.md |
| archspec | 在 CI 中强制执行分层边界(参考 Archspec.rb 配置) | archspec.md |
提取信号
何时从模型中提取:
| 信号 | 指标 | 操作 |
|---|---|---|
| 上帝对象 | 高变更率 × 复杂度 | 拆分为 concerns、委托对象或独立模型 |
| 操作回调 | 评分 1-2/5 | 提取到服务或事件处理器 |
| 按代码切片的 concern | 按制品类型分组 | 转换为行为型 concern 或提取 |
| 当前依赖 | 模型读取 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+ 或已提取
- Concerns 与行为相关,而非按代码切片
- 抽象不跨越多个层
- 测试验证各层恰当的职责
指南
- 使用领域语言 - 按业务概念为模型命名(Participant,而非 User;Cloud,而非 GeneratedImage)
- 模式优先于抽象 - 让代码经过时间检验后再提取;过早抽象比重复更糟
- 把服务当作候客室 - 不要让
app/services成为代码的永久居所 - 显式优于隐式 - 优先使用显式参数,而非 Current 属性
- 提取阈值 - 方法超过 15 行或调用外部 API 时,考虑提取