Code review agent based on Sandi Metz's object-oriented design principles from "Practical Object-Oriented Design in Ruby" and "99 Bottles of OOP". Use when users request code reviews, ask about OO design principles, need refactoring guidance, want to check code against SOLID principles, or mention Sandi Metz, POODR, 99 Bottles, or terms like "shameless green", "flocking rules", or "Law of Demeter".
Reviews code against Sandi Metz's object-oriented design principles (POODR, 99 Bottles), checking for SOLID violations, Law of Demeter, and the four rules (100-line classes, 5-line methods, 4 parameters, 4 instance variables). Use when users request code reviews, ask about OO design, or mention Sandi Metz, POODR, or 99 Bottles.
/plugin marketplace add el-feo/ai-context/plugin install ruby-rails@jebs-dev-toolsThis skill inherits all available tools. When active, it can use any tool Claude has access to.
references/principles_examples.mdscripts/code_reviewer.rbReview code using Sandi Metz's principles: Single Responsibility, SOLID, Law of Demeter, "Tell Don't Ask", and the four famous rules (classes ≤100 lines, methods ≤5 lines, parameters ≤4, instance variables ≤4).
For code review requests, follow this workflow:
Check every class and method:
Violation format: "Class 'OrderManager' has 127 lines (max: 100)" Suggestion: "Extract responsibilities into collaborating classes. Ask: Can this class be described in one sentence?"
Indicators of violations:
Key question to suggest: "Can you describe this class/method in one sentence without using 'and'?"
Check for:
ClassName.new) → Suggest dependency injectionobject.property.method.value) → Law of Demeter violationLaw of Demeter: "Only talk to immediate friends"
self.methodmethod_parameter.method@instance_variable.methodobject.attribute.another_attribute.methodAnti-pattern:
if user.admin?
user.delete_all
end
Better:
user.perform_admin_action(:delete_all)
Principle: Objects should make their own decisions, not have their state queried and then acted upon.
Identify candidates for polymorphism:
if object.is_a?(Type)) → Use duck typing or polymorphismPattern from 99 Bottles: Replace conditionals with polymorphic message sends to objects that know their own behavior.
Structural:
Coupling:
Conditional Logic:
Naming:
Comments:
Poor names that indicate design problems:
save_and_send → Should be two methodsPrinciple: Names should reveal intent. If you can't name it clearly, it probably has unclear responsibilities.
Structure feedback by principle area:
📏 SANDI METZ'S FOUR RULES
✓ Pass: Class 'Order' size good (45 lines)
⚠️ Warning: Method 'process' has 12 lines (max: 5) [line 23]
💡 Extract smaller methods with intention-revealing names
🎯 SINGLE RESPONSIBILITY
ℹ️ Info: Class 'OrderManager' has 9 public methods [line 1]
💡 Ask: Can this class be described in one sentence?
🔗 DEPENDENCIES
❌ Error: Message chain detected: customer.address.street.name [line 45]
💡 Use delegation. Add customer.street_name method
💬 TELL, DON'T ASK
⚠️ Warning: Conditional based on object query [line 67]
💡 Let objects make their own decisions
📊 SUMMARY
✓ Passes: 12
ℹ️ Info: 5
⚠️ Warnings: 8
❌ Errors: 2
From 99 Bottles of OOP - encourage this refactoring approach:
Key wisdom: "Make the change easy, then make the easy change"
Suggest these when appropriate:
Extract Method: When methods too long
# Before: 15-line method
# After: 3-line method calling 3 extracted methods (each ≤5 lines)
Extract Class: When classes have too many responsibilities
# Before: OrderManager with 8 instance variables
# After: Order + Payment + Shipping (each with ≤4 instance variables)
Replace Conditional with Polymorphism: For case/if-elsif on type
# Before: case type when 'book'... when 'electronics'...
# After: Book.price, Electronics.price (each knows own behavior)
Introduce Parameter Object: For long parameter lists
# Before: create_order(name, email, street, city, state, zip)
# After: create_order(customer_info)
When showing before/after examples, keep them concise:
Before (violations):
class OrderManager
def process(name, email, address, phone, items, discount, method)
# 20 lines of nested conditionals
end
end
After (principles applied):
class Order
def total
items.sum(&:price) - discount.amount
end
end
class Discount
def amount
# polymorphic behavior
end
end
Sandi Metz: "Break them only if you have a good reason and you've tried not to."
If user has broken a rule intentionally, acknowledge it and ask if they want alternatives or if the violation is justified.
For deeper understanding, the skill is based on:
Key talks (available online):
This skill should be used when the user asks to "create a slash command", "add a command", "write a custom command", "define command arguments", "use command frontmatter", "organize commands", "create command with file references", "interactive command", "use AskUserQuestion in command", or needs guidance on slash command structure, YAML frontmatter fields, dynamic arguments, bash execution in commands, user interaction patterns, or command development best practices for Claude Code.
This skill should be used when the user asks to "create an agent", "add an agent", "write a subagent", "agent frontmatter", "when to use description", "agent examples", "agent tools", "agent colors", "autonomous agent", or needs guidance on agent structure, system prompts, triggering conditions, or agent development best practices for Claude Code plugins.
This skill should be used when the user asks to "create a hook", "add a PreToolUse/PostToolUse/Stop hook", "validate tool use", "implement prompt-based hooks", "use ${CLAUDE_PLUGIN_ROOT}", "set up event-driven automation", "block dangerous commands", or mentions hook events (PreToolUse, PostToolUse, Stop, SubagentStop, SessionStart, SessionEnd, UserPromptSubmit, PreCompact, Notification). Provides comprehensive guidance for creating and implementing Claude Code plugin hooks with focus on advanced prompt-based hooks API.