Claude Code Plugins

Community-maintained marketplace

Feedback

code-smell-detector

@mgd34msu/goodvibes-plugin
0
0

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.

Install Skill

1Download skill
2Enable skills in Claude

Open claude.ai/settings/capabilities and find the "Skills" section

3Upload to Claude

Click "Upload skill" and select the downloaded ZIP file

Note: Please verify skill by going through its instructions before using it.

SKILL.md

name code-smell-detector
description 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.

Code Smell Detector

Systematic detection of code smells, anti-patterns, and maintainability issues with quantified thresholds for scoring.

Quick Start

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 Classification

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

Bloaters

Code that has grown excessively large and hard to work with.

Long Method / Function

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

Large Class / Module

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

Primitive Obsession

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/

Long Parameter List

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) {}

Data Clumps

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() {}
}

Object-Orientation Abusers

Incorrect application of OOP principles.

Switch Statements on Type

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 */ }
}

Refused Bequest

Threshold: Subclass doesn't use inherited methods/properties Deduction: 0.5 points per occurrence

Detection Signs:

  • Override methods that throw "Not Implemented"
  • Empty implementations of parent methods
  • Subclass only uses 1-2 of many inherited methods

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!
  }
}

Temporary Field

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
  }
}

Change Preventers

Code that makes changes difficult and risky.

Divergent Change

Threshold: Class changes for multiple unrelated reasons Deduction: 1.0 point per class

Detection Signs:

  • Class has methods for different domains (UI + DB + business logic)
  • Multiple developers edit same class for unrelated features
  • Class name is generic ("Manager", "Handler", "Processor")

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) {}
}

Shotgun Surgery

Threshold: One change requires edits to 5+ files Deduction: 1.0 point per pattern

Detection Signs:

  • Adding a new field requires changes in many files
  • Same concept scattered across codebase
  • Feature flags checked in 10+ places

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

Parallel Inheritance Hierarchies

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!


Dispensables

Code that adds no value.

Dead Code

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

Speculative Generality

Threshold: Unused abstractions "for future use" Deduction: 0.5 points per occurrence

Detection Signs:

  • Interfaces with single implementation
  • Abstract methods never overridden differently
  • Parameters/hooks never used
  • "TODO: implement when needed" comments

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"); }
}

Duplicate Code

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

Comments (Unnecessary)

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);

Couplers

Code with excessive coupling.

Feature Envy

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);
  }
}

Inappropriate Intimacy

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

Message Chains

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/

Middle Man

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); }
}

SOLID Violations

Single Responsibility Principle (SRP)

Threshold: Class has >1 reason to change Deduction: 1.0 point per violation

Detection Heuristics:

  • Class has methods in different domains
  • Class imports from many unrelated modules
  • Class has >300 lines
  • Class name contains "And" or is very generic

Open/Closed Principle (OCP)

Threshold: Modifying existing code to add features Deduction: 0.75 points per violation

Detection Signs:

  • Switch statements that grow with each feature
  • If-else chains on type
  • God functions with many conditionals

Liskov Substitution Principle (LSP)

Threshold: Subclass can't substitute for parent Deduction: 0.75 points per violation

Detection Signs:

  • Override that throws NotImplementedException
  • Override that changes behavior contract
  • Type checking before calling inherited method

Interface Segregation Principle (ISP)

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 "("

Dependency Inversion Principle (DIP)

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
  ) {}
}

Summary Scoring Table

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

Report Template

## 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}

Integration with Brutal Reviewer

This skill contributes to multiple categories:

  • Maintainability (8%): Bloaters, Dispensables
  • SOLID/DRY (10%): SOLID violations, Couplers
  • Organization (12%): Change Preventers, Large Classes