Use when refactoring fat Rails models with repetitive prefixes like entropy_*, notification_*, or multi-association coordination. Extracts PORO wrappers that group operations around nouns/concepts.
View on GitHubZempTime/zemptime-marketplace
vanilla-rails
January 20, 2026
Select agents to install to:
npx add-skill https://github.com/ZempTime/zemptime-marketplace/blob/main/vanilla-rails/skills/writing-affordances/SKILL.md -a claude-code --skill writing-affordancesInstallation paths:
.claude/skills/writing-affordances/# Writing Affordances Extract PORO wrappers that group 3+ operations around a noun/concept, keeping parent model focused. **Announce:** "I'm using the writing-affordances skill to evaluate this for affordance extraction." ## Detection Triggers - 3+ methods share prefix: `entropy_calculate`, `entropy_remind`, `entropy_cleanup` - Methods coordinate 2+ associations (`assignments` + `watches` + `events`) - Fat model with mixed conceptual domains - Related methods but connection non-obvious **Don't use for:** Single trait (use concern) | Single association (use extension) | 1-2 methods (use plain method) ## Decision Heuristics Ask yourself: 1. **"Can I pass this around?"** - Would `notify(description)` be clearer than `notify(event)`? 2. **"Do I call it or does Rails?"** - Explicit calls = Affordance | Callbacks/validations = Concern 3. **"Prefix cluster?"** - `entropy_*` methods = Extract `entropy` affordance (prefix = noun) 4. **"Call site clarity?"** - `card.entropy.auto_clean_at` vs `card.entropy_auto_clean_at` 5. **"Need infrastructure + operations?"** - Concern provides associations/callbacks, affordance provides API See @detecting.md for complete decision framework. ## Pattern Comparison | Pattern | Use When | Example | Key Question | |---------|----------|---------|--------------| | **Affordance** | Group operations around noun | `card.entropy.auto_clean_at` | "Can I pass this around?" | | **Concern** | Infrastructure or implicit behavior | `Searchable` (callbacks only) | "Does Rails call it implicitly?" | | **Concern + Affordance** | Both infrastructure AND operations | Concern sets up associations, affordance provides API | "Need both?" | | **Association Ext** | Single association operations | `card.comments.recent` | "Only touching one has_many?" | ## Critical Constraints **Violating these = wrong pattern:** - **3+ methods minimum** - Don't create single-method affordances - **PORO only** - No ActiveRecord inheritance - **Parent is ONLY dependenc