スキル一覧に戻る
mgd34msu

code-smell-detector

by mgd34msu

Plug in, Receive good vibes.

2🍴 0📅 2026年1月25日
GitHubで見るManusで実行

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

SeverityMultiplierImpactAction
Bloater1.5xHigh cognitive load, hard to modifyRefactor soon
Object-Orientation Abuser1.25xPoor extensibility, rigid designRefactor next sprint
Change Preventer1.5xRipple effects, fear of changePrioritize refactoring
Dispensable1.0xClutter, confusionClean up opportunistically
Coupler1.25xTight coupling, hard to testDecouple 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

CategorySmellThresholdBase Deduction
BloaterLong Method>50 lines0.5
BloaterLarge Class>300 lines1.0
BloaterPrimitive Obsession>5 params0.5
BloaterLong Parameter List>4 params0.25
OO AbuserSwitch on Typemultiple places0.75
OO AbuserRefused Bequestunused inheritance0.5
Change PreventerDivergent Changemulti-reason class1.0
Change PreventerShotgun Surgery5+ file changes1.0
DispensableDead Codeany0.25/100 lines
DispensableSpeculative Generalityunused abstractions0.5
DispensableDuplicate Code>10 similar lines0.5
CouplerFeature Envymethod uses other class0.5
CouplerMessage Chains>3 chained calls0.25
SOLIDSRP Violationmultiple responsibilities1.0
SOLIDOCP Violationmodifying for extension0.75
SOLIDDIP Violationconcrete dependencies0.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

スコア

総合スコア

60/100

リポジトリの品質指標に基づく評価

SKILL.md

SKILL.mdファイルが含まれている

+20
LICENSE

ライセンスが設定されている

+10
説明文

100文字以上の説明がある

0/10
人気

GitHub Stars 100以上

0/15
最近の活動

3ヶ月以内に更新がある

0/10
フォーク

10回以上フォークされている

0/5
Issue管理

オープンIssueが50未満

+5
言語

プログラミング言語が設定されている

+5
タグ

1つ以上のタグが設定されている

0/5

レビュー

💬

レビュー機能は近日公開予定です