Detects code smells, anti-patterns, and common bugs with quantified thresholds and severity scoring. Use when reviewing code quality, finding maintainability issues, detecting SOLID violations, or identifying technical debt.
Systematically detects code smells, anti-patterns, and SOLID violations with quantified severity scoring. Use when reviewing code quality, finding maintainability issues, or identifying technical debt.
/plugin marketplace add mgd34msu/goodvibes-plugin/plugin install goodvibes@goodvibes-marketThis skill inherits all available tools. When active, it can use any tool Claude has access to.
references/complexity-metrics.mdSystematic detection of code smells, anti-patterns, and maintainability issues with quantified thresholds for scoring.
Full smell analysis:
Analyze this codebase for code smells with severity scoring and file:line references.
Specific category:
Check for SOLID principle violations in the services directory.
| Severity | Multiplier | Impact | Action |
|---|---|---|---|
| Bloater | 1.5x | High cognitive load, hard to modify | Refactor soon |
| Object-Orientation Abuser | 1.25x | Poor extensibility, rigid design | Refactor next sprint |
| Change Preventer | 1.5x | Ripple effects, fear of change | Prioritize refactoring |
| Dispensable | 1.0x | Clutter, confusion | Clean up opportunistically |
| Coupler | 1.25x | Tight coupling, hard to test | Decouple incrementally |
Code that has grown excessively large and hard to work with.
Threshold: >50 lines (warning), >100 lines (violation) Deduction: 0.5 points base per 10 functions over threshold
Detection Commands:
# Find long functions (approximate)
# TypeScript/JavaScript
grep -n "function\|=>\|async" src/**/*.ts | wc -l
# Get function lengths using AST tools
npx escomplex src/ --format json 2>/dev/null | jq '.reports[].functions[] | select(.sloc.logical > 50)'
# Python
radon cc src/ -j 2>/dev/null | jq '.[] | .[] | select(.loc > 50)'
Manual Detection:
# Count lines between function start and end
awk '/function.*\{/{start=NR} /^\s*\}/{if(NR-start>50) print FILENAME":"start":"NR-start}' src/**/*.ts
Evidence Template:
Location: {file}:{startLine}-{endLine}
Function: {name}()
Lines: {count} (threshold: 50)
Deduction: 0.05 * ceil(({count} - 50) / 10) points
Threshold: >300 lines (warning), >500 lines (violation) Deduction: 1.0 point base per class over threshold
Detection Commands:
# Files over 300 lines
find src -name "*.ts" -exec wc -l {} \; | awk '$1 > 300 {print}'
# Count classes per file
grep -c "^class\|^export class" src/**/*.ts
Evidence Template:
Location: {file}
Lines: {count} (threshold: 300)
Classes: {classCount}
Deduction: 1.0 point
Threshold: >5 primitive parameters in function Deduction: 0.5 points per occurrence
Detection Patterns:
// SMELL: Too many primitives
function createUser(
name: string,
email: string,
phone: string,
street: string,
city: string,
zip: string,
country: string
) { ... }
// BETTER: Use objects
interface Address {
street: string;
city: string;
zip: string;
country: string;
}
function createUser(
name: string,
email: string,
phone: string,
address: Address
) { ... }
Detection Commands:
# Find functions with many parameters
grep -rn "function.*,.*,.*,.*,.*," src/
grep -rn "=>.*,.*,.*,.*,.*," src/
Threshold: >4 parameters Deduction: 0.25 points per function
Detection Commands:
# Functions with 5+ parameters
grep -rEn "function\s+\w+\s*\([^)]*,[^)]*,[^)]*,[^)]*,[^)]*\)" src/
Fix Pattern:
// BEFORE: 6 parameters
function createOrder(userId, productId, quantity, address, paymentMethod, coupon) {}
// AFTER: Parameter object
interface CreateOrderParams {
userId: string;
productId: string;
quantity: number;
address: Address;
paymentMethod: PaymentMethod;
coupon?: string;
}
function createOrder(params: CreateOrderParams) {}
Threshold: Same 3+ fields appearing together in 3+ places Deduction: 0.5 points per clump
Example:
// SMELL: Same fields everywhere
function validateAddress(street, city, zip) {}
function formatAddress(street, city, zip) {}
function saveAddress(userId, street, city, zip) {}
// BETTER: Extract class
class Address {
constructor(public street: string, public city: string, public zip: string) {}
validate() {}
format() {}
}
Incorrect application of OOP principles.
Threshold: Switch/if-else chain on type in multiple places Deduction: 0.75 points per violation
Detection Commands:
# Type-based switches
grep -rn "switch.*type\|switch.*kind" src/
grep -rn "if.*instanceof.*else.*instanceof" src/
grep -rn "\.type\s*===\s*['\"]" src/
SMELL Pattern:
// SMELL: Type switching
function calculateArea(shape) {
switch (shape.type) {
case 'circle': return Math.PI * shape.radius ** 2;
case 'rectangle': return shape.width * shape.height;
case 'triangle': return 0.5 * shape.base * shape.height;
}
}
function draw(shape) {
switch (shape.type) { // Same switch again!
case 'circle': drawCircle(shape);
case 'rectangle': drawRectangle(shape);
case 'triangle': drawTriangle(shape);
}
}
FIX Pattern:
// BETTER: Polymorphism
interface Shape {
calculateArea(): number;
draw(): void;
}
class Circle implements Shape {
constructor(private radius: number) {}
calculateArea() { return Math.PI * this.radius ** 2; }
draw() { /* circle drawing */ }
}
Threshold: Subclass doesn't use inherited methods/properties Deduction: 0.5 points per occurrence
Detection Signs:
SMELL Pattern:
class Bird {
fly() { /* flying logic */ }
sing() { /* singing logic */ }
eat() { /* eating logic */ }
}
class Penguin extends Bird {
fly() {
throw new Error("Penguins can't fly"); // SMELL!
}
}
Threshold: Fields only used in some methods Deduction: 0.25 points per field
SMELL Pattern:
class Order {
private tempTotal: number; // Only used in calculateTotal
private tempDiscount: number; // Only used in calculateTotal
calculateTotal() {
this.tempTotal = this.items.reduce((sum, i) => sum + i.price, 0);
this.tempDiscount = this.coupon ? this.tempTotal * 0.1 : 0;
return this.tempTotal - this.tempDiscount;
}
}
FIX:
class Order {
calculateTotal() {
const total = this.items.reduce((sum, i) => sum + i.price, 0);
const discount = this.coupon ? total * 0.1 : 0;
return total - discount; // Local variables, not fields
}
}
Code that makes changes difficult and risky.
Threshold: Class changes for multiple unrelated reasons Deduction: 1.0 point per class
Detection Signs:
SMELL Pattern:
class UserManager {
// Database concerns
saveToDatabase(user) {}
loadFromDatabase(id) {}
// Email concerns
sendWelcomeEmail(user) {}
sendPasswordReset(user) {}
// Validation concerns
validateEmail(email) {}
validatePassword(password) {}
// Formatting concerns
formatForDisplay(user) {}
formatForExport(user) {}
}
Threshold: One change requires edits to 5+ files Deduction: 1.0 point per pattern
Detection Signs:
Detection Commands:
# Find scattered concepts
grep -rln "userRole\|user\.role\|role.*user" src/ | wc -l
grep -rln "isAdmin\|is_admin\|admin.*true" src/ | wc -l
Threshold: Adding a subclass requires adding another subclass elsewhere Deduction: 0.75 points
SMELL Pattern:
Shape -> Circle, Rectangle, Triangle
ShapeRenderer -> CircleRenderer, RectangleRenderer, TriangleRenderer
ShapeSerializer -> CircleSerializer, RectangleSerializer, TriangleSerializer
Every new shape requires three new classes!
Code that adds no value.
Threshold: Any unreachable or unused code Deduction: 0.25 points per 100 lines of dead code
Detection Commands:
# Unused exports (TypeScript)
npx ts-prune 2>/dev/null
# Unused dependencies
npx depcheck 2>/dev/null
# Unused files
npx unimported 2>/dev/null
# Python
vulture src/ 2>/dev/null
Threshold: Unused abstractions "for future use" Deduction: 0.5 points per occurrence
Detection Signs:
SMELL Pattern:
// YAGNI violation
interface DataStore {
save(data: any): void;
load(id: string): any;
delete(id: string): void;
query(filter: any): any[]; // Never used
backup(): void; // Never used
restore(backup: any): void; // Never used
}
class PostgresStore implements DataStore {
query(filter: any) { throw new Error("Not implemented"); }
backup() { throw new Error("Not implemented"); }
restore() { throw new Error("Not implemented"); }
}
Threshold: >10 similar lines in 2+ places Deduction: 0.5 points per duplication
Detection Commands:
# JavaScript/TypeScript duplicate detection
npx jscpd src/ --min-lines 10 --min-tokens 50
# Generic duplicate finder
npx copy-paste-detector src/
Detection Patterns:
# Find similar function names
grep -rn "function validate\|const validate" src/ | sort
# Find repeated patterns
grep -rn "try {" src/ | head -20
Threshold: Comments that explain "what" instead of "why" Deduction: 0.1 points per 10 bad comments
SMELL Patterns:
// UNNECESSARY: Explains what (obvious from code)
// Increment counter by 1
counter++;
// Add user to list
users.push(user);
// GOOD: Explains why (not obvious)
// Using += 1 instead of ++ for consistency with Python team's style
counter += 1;
// Storing raw user object for cache invalidation in afterSave hook
users.push(user);
Code with excessive coupling.
Threshold: Method uses more from other class than its own Deduction: 0.5 points per method
SMELL Pattern:
// SMELL: calculateTotal uses Order more than itself
class OrderPrinter {
calculateTotal(order: Order) {
let total = 0;
for (const item of order.items) {
total += item.price * item.quantity;
}
total -= order.discount;
total *= (1 + order.taxRate);
return total;
}
}
// BETTER: Move to Order
class Order {
calculateTotal() {
let total = this.items.reduce((sum, item) =>
sum + item.price * item.quantity, 0);
return (total - this.discount) * (1 + this.taxRate);
}
}
Threshold: Classes access each other's private/internal data Deduction: 0.75 points per occurrence
Detection Commands:
# Direct property access on other classes
grep -rn "\._\w\+\s*=" src/ # Accessing _private fields
grep -rn "\.#\w\+\s*=" src/ # Accessing #private fields
Threshold: >3 chained method calls accessing data Deduction: 0.25 points per occurrence
SMELL Pattern:
// SMELL: Long chain
const city = order.customer.address.city.name;
// BETTER: Tell, don't ask
const city = order.getDeliveryCity();
Detection Commands:
# Find long chains
grep -rn "\.\w\+\.\w\+\.\w\+\.\w\+" src/
Threshold: Class delegates most work to another class Deduction: 0.5 points per class
SMELL Pattern:
// SMELL: UserService just delegates to User
class UserService {
getName(user: User) { return user.getName(); }
getEmail(user: User) { return user.getEmail(); }
setEmail(user: User, email: string) { user.setEmail(email); }
}
Threshold: Class has >1 reason to change Deduction: 1.0 point per violation
Detection Heuristics:
Threshold: Modifying existing code to add features Deduction: 0.75 points per violation
Detection Signs:
Threshold: Subclass can't substitute for parent Deduction: 0.75 points per violation
Detection Signs:
Threshold: Interface with >7 methods or unused methods Deduction: 0.5 points per violation
Detection Commands:
# Large interfaces
grep -A 20 "^interface\|^export interface" src/**/*.ts | grep -c "("
Threshold: High-level module depends on low-level implementation Deduction: 0.75 points per violation
SMELL Pattern:
// SMELL: Direct instantiation
class OrderService {
private db = new PostgresDatabase(); // Concrete!
private mailer = new SendGridMailer(); // Concrete!
}
// BETTER: Inject interfaces
class OrderService {
constructor(
private db: Database, // Interface
private mailer: EmailService // Interface
) {}
}
| Category | Smell | Threshold | Base Deduction |
|---|---|---|---|
| Bloater | Long Method | >50 lines | 0.5 |
| Bloater | Large Class | >300 lines | 1.0 |
| Bloater | Primitive Obsession | >5 params | 0.5 |
| Bloater | Long Parameter List | >4 params | 0.25 |
| OO Abuser | Switch on Type | multiple places | 0.75 |
| OO Abuser | Refused Bequest | unused inheritance | 0.5 |
| Change Preventer | Divergent Change | multi-reason class | 1.0 |
| Change Preventer | Shotgun Surgery | 5+ file changes | 1.0 |
| Dispensable | Dead Code | any | 0.25/100 lines |
| Dispensable | Speculative Generality | unused abstractions | 0.5 |
| Dispensable | Duplicate Code | >10 similar lines | 0.5 |
| Coupler | Feature Envy | method uses other class | 0.5 |
| Coupler | Message Chains | >3 chained calls | 0.25 |
| SOLID | SRP Violation | multiple responsibilities | 1.0 |
| SOLID | OCP Violation | modifying for extension | 0.75 |
| SOLID | DIP Violation | concrete dependencies | 0.75 |
## Code Smell Analysis: {project}
### Summary
| Category | Count | Total Deduction |
|----------|-------|-----------------|
| Bloaters | {n} | {points} |
| OO Abusers | {n} | {points} |
| Change Preventers | {n} | {points} |
| Dispensables | {n} | {points} |
| Couplers | {n} | {points} |
| SOLID Violations | {n} | {points} |
| **Total** | **{sum}** | **{totalPoints}** |
### Top Offenders
#### 1. {ClassName} - God Class
- **Location:** `{file}:{line}`
- **Lines:** {count}
- **Responsibilities:** {list}
- **Deduction:** {points}
{repeat for top 10 issues}
This skill contributes to multiple categories:
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.