From sustainable-rails
Review and design Rails applications using sustainability principles from "Sustainable Web Development with Ruby on Rails" by David Bryant Copeland. Use when analyzing Rails codebases for sustainability, reviewing PRs, planning features, or applying patterns for business logic separation, database design, testing, and operations. Triggers on "sustainable", "sustainability", "carrying cost", "business logic separation", "service layer", "fan-in", "fat model", "thin controller".
How this skill is triggered — by the user, by Claude, or both
Slash command
/sustainable-rails:sustainable-railsThis skill is limited to the following tools:
The summary Claude sees in its skill listing — used to decide when to auto-load this skill
Design and review Rails applications for long-term sustainability.
references/core/business-logic-separation.mdreferences/core/rails-architecture.mdreferences/core/sustainability-principles.mdreferences/examples/end-to-end.mdreferences/patterns/app-setup.mdreferences/patterns/boundary-classes.mdreferences/patterns/controllers.mdreferences/patterns/database.mdreferences/patterns/helpers.mdreferences/patterns/html-templates.mdreferences/patterns/jobs.mdreferences/patterns/models-database-access.mdreferences/patterns/models-validations-callbacks.mdreferences/patterns/routes.mdreferences/patterns/service-layer-design.mdreferences/patterns/view-testing.mdreferences/topics/api-endpoints.mdreferences/topics/auth.mdreferences/topics/css.mdreferences/topics/javascript-management.mdDesign and review Rails applications for long-term sustainability.
Sustainable Rails organizes code to minimize carrying costs — the ongoing cost of keeping code working as requirements change. The core architecture:
┌─────────────────────────────────────────┐
│ BOUNDARY LAYER │
│ Controllers, Jobs, Mailers, Rake Tasks │
│ (receive input, trigger logic, output) │
└─────────────────────────────────────────┘
↓
┌─────────────────────────────────────────┐
│ SERVICE LAYER │
│ app/services/ — Business Logic Classes │
│ (isolated, low fan-in, high churn OK) │
└─────────────────────────────────────────┘
↓
┌─────────────────────────────────────────┐
│ MODEL LAYER │
│ Active Records — Database Access Only │
│ (high fan-in, must stay simple/stable)│
└─────────────────────────────────────────┘
↓
┌─────────────────────────────────────────┐
│ DATABASE LAYER │
│ PostgreSQL — Source of Truth │
│ (constraints enforce correctness) │
└─────────────────────────────────────────┘
Core Rule: Business logic does NOT go in Active Records. Keep high fan-in classes simple and stable.
/sustainable:review for sustainability-focused review/sustainable:analyze for full sustainability analysisThree values in priority order:
Business logic is complex, has high churn, and therefore has more bugs. Classes used widely (high fan-in) amplify bug impact. Therefore:
See Business Logic Separation.
| Violation | Example | Fix |
|---|---|---|
| Business logic in model | Widget#purchase method with conditionals | Extract to WidgetPurchaser service class |
| Fat model | Model growing with every feature | Separate service per domain concept |
| Validation as data integrity | Relying on validates for correctness | Add database constraints (NOT NULL, CHECK, FK) |
| Complex controller | Business logic in actions | Delegate to service, controller is "configuration" |
| Callback abuse | after_commit :send_notification | Move side effects to service layer |
| Scopes as business logic | Complex scopes encoding domain rules | Move to service class methods |
| Active Job indirection | Using Active Job when you can use backend directly | Use Sidekiq/SolidQueue API directly |
| Pattern | Location | Use When | Reference |
|---|---|---|---|
| Service Classes | app/services/ | Any business logic beyond CRUD | service-layer-design.md |
| Rich Result Objects | Service return values | Service methods need to communicate outcomes | service-layer-design.md |
| Database Constraints | Migrations | Data must be correct regardless of code path | database.md |
| Thin Controllers | Controllers | HTTP handling only | controllers.md |
| Thin Models | Models | Database access + simple derived attributes | models-database-access.md |
| Boundary Classes | Jobs, Mailers, Rake | Receive input, delegate to services | boundary-classes.md |
| Canonical Routes | Routes | RESTful resources with only: | routes.md |
| Semantic HTML | Views | Build with meaningful tags, style with CSS | html-templates.md |
| If you have... | Put it in... |
|---|---|
| Domain-specific logic (conditionals, rules, workflows) | Service class in app/services/ |
| Database access patterns | Active Record class/scope method |
| Simple derived attribute from DB columns | Active Record instance method |
| HTTP request handling | Controller (keep it "configuration") |
| Parameter type conversion | Controller private method |
| Email formatting | Mailer (no business logic) |
| Deferred/fault-tolerant execution | Job that delegates to service |
| One-off or recurring automation | Rake task that delegates to service |
| Reusable markup | Partial with locals (not layouts) |
| Markup formatting | Helper (for small inline components) |
| Data correctness rules | Database constraints + validations for UX |
| Command | Purpose |
|---|---|
/sustainable:review | Review code changes for sustainability patterns |
/sustainable:analyze | Full codebase sustainability analysis |
| Topic | Reference |
|---|---|
| Sustainability Principles | sustainability-principles.md |
| Rails Architecture | rails-architecture.md |
| Business Logic Separation | business-logic-separation.md |
| Database Design | database.md |
| Service Layer Design | service-layer-design.md |
| Authentication & Authorization | auth.md |
| API Endpoints | api-endpoints.md |
| Operations & Observability | operations.md |
| Process & Workflows | process-workflows.md |
| CSS Strategy | css.md |
| JavaScript (Minimize) | javascript-minimization.md |
| JavaScript (Manage) | javascript-management.md |
| Monoliths & Microservices | monoliths-microservices.md |
| Technical Leadership | technical-leadership.md |
| Pattern | Reference |
|---|---|
| App Setup (bin/setup, bin/ci) | app-setup.md |
| Routes | routes.md |
| HTML Templates | html-templates.md |
| Helpers | helpers.md |
| View Testing | view-testing.md |
| Models (Database Access) | models-database-access.md |
| Models (Validations & Callbacks) | models-validations-callbacks.md |
| Controllers | controllers.md |
| Jobs | jobs.md |
| Boundary Classes | boundary-classes.md |
| End-to-End Example | end-to-end.md |
Well-sustained code:
before_validation) and operational trackingresources with only: — no unused routesbin/setup, bin/run, and bin/ci scripts are maintainedresources routing. Don't fight Rails.WidgetEditingService#edit_widget over generic call methods.npx claudepluginhub mcrundo/sustainable-rails-skill --plugin sustainable-railsReviews and refactors Rails apps to Vanilla Rails style: thin controllers, rich domain models, no unnecessary service layers. For PR reviews, codebase analysis, simplification.
Writes and reviews Rails code following DHH's 37signals style guide; advises on architecture while respecting existing conventions like Tailwind or RSpec.
Applies DHH's 37signals Rails style to Ruby code: fat models, thin controllers, Hotwire patterns, REST purity, database constraints, and clarity-over-cleverness. For generation, refactoring, and review.