# Code Smell Patterns Reference

> Comprehensive catalog of code quality and design smells in Python.

- Skill: `tools-only/code-smell-patterns-reference` (Agent Skill, multi-file: 3 files)
- Install (CLI): `npx skillmds@latest add tools-only/code-smell-patterns-reference`
- Raw SKILL.md: https://api.skillmd.com/api/skills/tools-only/code-smell-patterns-reference/raw
- Safety review: pending (external: skill-scanner PASS, skillspector PASS)
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Coding & Dev Tools
- Author: tools-only (https://skillmd.com/u/tools-only)
- Updated: 2026-09-29
- Page: https://skillmd.com/skills/tools-only/code-smell-patterns-reference

---

# Code Smell Patterns Reference

Comprehensive catalog of code quality and design smells in Python.

## Code Quality Smells

### Pattern 1: Duplicate Code

**Description:** Same or very similar code appears in multiple places.

**Impact:** Changes must be made in multiple locations, increasing maintenance burden and bug risk.

**Detection:**
- Identical or nearly identical code blocks
- Copy-pasted functions with minor variations
- Similar logic in multiple methods

**Example:**
```python
# ❌ Duplicate code
class UserService:
    def create_user(self, data):
        if not data.get('email'):
            raise ValueError("Email required")
        if not data.get('name'):
            raise ValueError("Name required")
        # Create user...

    def update_user(self, data):
        if not data.get('email'):
            raise ValueError("Email required")
        if not data.get('name'):
            raise ValueError("Name required")
        # Update user...

# ✅ Extract common validation
class UserService:
    def _validate_user_data(self, data):
        if not data.get('email'):
            raise ValueError("Email required")
        if not data.get('name'):
            raise ValueError("Name required")

    def create_user(self, data):
        self._validate_user_data(data)
        # Create user...

    def update_user(self, data):
        self._validate_user_data(data)
        # Update user...
```

**Refactoring:** Extract Method, Pull Up Method, Form Template Method

### Pattern 2: Magic Numbers

**Description:** Numeric literals with unclear meaning appearing directly in code.

**Impact:** Hard to understand intent, difficult to change, easy to make mistakes.

**Example:**
```python
# ❌ Magic numbers
def calculate_discount(price):
    if price > 1000:
        return price * 0.15
    elif price > 500:
        return price * 0.10
    else:
        return price * 0.05

# ✅ Named constants
BULK_ORDER_THRESHOLD = 1000
LARGE_ORDER_THRESHOLD = 500
BULK_DISCOUNT_RATE = 0.15
LARGE_DISCOUNT_RATE = 0.10
STANDARD_DISCOUNT_RATE = 0.05

def calculate_discount(price):
    if price > BULK_ORDER_THRESHOLD:
        return price * BULK_DISCOUNT_RATE
    elif price > LARGE_ORDER_THRESHOLD:
        return price * LARGE_DISCOUNT_RATE
    else:
        return price * STANDARD_DISCOUNT_RATE
```

**Refactoring:** Replace Magic Number with Symbolic Constant

### Pattern 3: Hardcoded Values

**Description:** Configuration values, paths, or strings embedded directly in code.

**Impact:** Difficult to change for different environments, violates DRY principle.

**Example:**
```python
# ❌ Hardcoded values
def save_file(data):
    with open('/var/app/data/output.txt', 'w') as f:
        f.write(data)

def send_email(user):
    send_to('admin@example.com', f'User {user.name} registered')

# ✅ Configuration-based
import os

class Config:
    OUTPUT_PATH = os.getenv('OUTPUT_PATH', '/var/app/data/output.txt')
    ADMIN_EMAIL = os.getenv('ADMIN_EMAIL', 'admin@example.com')

def save_file(data):
    with open(Config.OUTPUT_PATH, 'w') as f:
        f.write(data)

def send_email(user):
    send_to(Config.ADMIN_EMAIL, f'User {user.name} registered')
```

**Refactoring:** Introduce Parameter Object, Use Configuration

### Pattern 4: Commented-Out Code

**Description:** Code that has been commented out but not removed.

**Impact:** Clutters codebase, creates confusion about what's actually used.

**Example:**
```python
# ❌ Commented code
def process_order(order):
    # Old implementation
    # validate_order(order)
    # calculate_total(order)
    # charge_payment(order)

    # New implementation
    process_payment_v2(order)
    send_confirmation(order)

# ✅ Clean code
def process_order(order):
    process_payment(order)
    send_confirmation(order)
```

**Refactoring:** Delete the code (version control preserves history)

### Pattern 5: Long Identifier Names

**Description:** Excessively long variable or function names.

**Impact:** Reduces readability, makes code harder to scan.

**Example:**
```python
# ❌ Too long
def calculate_total_price_including_tax_and_shipping_for_customer_order(order):
    pass

# ✅ Appropriately named
def calculate_order_total(order):
    """Calculate total including tax and shipping."""
    pass
```

**Refactoring:** Rename, use docstrings for detailed explanations

### Pattern 6: Inconsistent Naming

**Description:** Similar concepts use different naming conventions.

**Impact:** Confusing, harder to learn codebase.

**Example:**
```python
# ❌ Inconsistent
def getUserData(user_id):
    pass

def fetch_product_info(product_id):
    pass

def RetrieveOrderDetails(order_id):
    pass

# ✅ Consistent
def get_user(user_id):
    pass

def get_product(product_id):
    pass

def get_order(order_id):
    pass
```

**Refactoring:** Standardize naming conventions

## Design Smells

### Pattern 7: God Class

**Description:** Class that knows too much or does too much.

**Impact:** Hard to understand, test, and maintain. Violates Single Responsibility Principle.

**Indicators:**
- More than 20 methods
- Touches many different concerns
- Large number of fields
- Many dependencies

**Example:**
```python
# ❌ God class
class UserManager:
    def create_user(self, data): pass
    def update_user(self, user_id, data): pass
    def delete_user(self, user_id): pass
    def authenticate_user(self, username, password): pass
    def send_welcome_email(self, user): pass
    def send_password_reset_email(self, user): pass
    def generate_password_reset_token(self, user): pass
    def validate_password_strength(self, password): pass
    def hash_password(self, password): pass
    def log_user_activity(self, user, action): pass
    def export_user_data(self, user): pass
    def import_user_data(self, data): pass
    def calculate_user_statistics(self, user): pass
    def get_user_recommendations(self, user): pass
    # ... 20+ more methods

# ✅ Split by responsibility
class UserRepository:
    def create(self, data): pass
    def update(self, user_id, data): pass
    def delete(self, user_id): pass
    def find_by_id(self, user_id): pass

class UserAuthenticationService:
    def authenticate(self, username, password): pass
    def hash_password(self, password): pass
    def validate_password_strength(self, password): pass
    def generate_reset_token(self, user): pass

class UserNotificationService:
    def send_welcome_email(self, user): pass
    def send_password_reset_email(self, user): pass

class UserAnalyticsService:
    def log_activity(self, user, action): pass
    def calculate_statistics(self, user): pass
    def get_recommendations(self, user): pass
```

**Refactoring:** Extract Class, Extract Service

### Pattern 8: Feature Envy

**Description:** Method uses more features from another class than its own.

**Impact:** Poor cohesion, method is in the wrong place.

**Example:**
```python
# ❌ Feature envy
class Order:
    def __init__(self, items, customer):
        self.items = items
        self.customer = customer

    def calculate_total(self):
        # Uses customer features heavily
        discount_rate = self.customer.get_discount_rate()
        is_premium = self.customer.is_premium_member()
        shipping_address = self.customer.get_shipping_address()

        total = sum(item.price for item in self.items)

        if is_premium:
            total *= (1 - discount_rate)

        if shipping_address.country != 'US':
            total += 50  # International shipping

        return total

# ✅ Move method to appropriate class
class Customer:
    def calculate_order_total(self, items):
        total = sum(item.price for item in items)

        if self.is_premium_member():
            total *= (1 - self.get_discount_rate())

        if self.shipping_address.country != 'US':
            total += 50

        return total

class Order:
    def __init__(self, items, customer):
        self.items = items
        self.customer = customer

    def calculate_total(self):
        return self.customer.calculate_order_total(self.items)
```

**Refactoring:** Move Method, Extract Method

### Pattern 9: Inappropriate Intimacy

**Description:** Classes that access each other's internal details too much.

**Impact:** Tight coupling, changes ripple across classes.

**Example:**
```python
# ❌ Inappropriate intimacy
class BankAccount:
    def __init__(self):
        self.balance = 0
        self._transaction_log = []

class AccountManager:
    def transfer_funds(self, from_account, to_account, amount):
        # Directly accessing internals
        if from_account.balance >= amount:
            from_account.balance -= amount
            to_account.balance += amount
            from_account._transaction_log.append(f"Transferred {amount}")
            to_account._transaction_log.append(f"Received {amount}")

# ✅ Use proper encapsulation
class BankAccount:
    def __init__(self):
        self._balance = 0
        self._transaction_log = []

    def withdraw(self, amount):
        if self._balance >= amount:
            self._balance -= amount
            self._log_transaction(f"Withdrew {amount}")
            return True
        return False

    def deposit(self, amount):
        self._balance += amount
        self._log_transaction(f"Deposited {amount}")

    def _log_transaction(self, message):
        self._transaction_log.append(message)

class AccountManager:
    def transfer_funds(self, from_account, to_account, amount):
        if from_account.withdraw(amount):
            to_account.deposit(amount)
            return True
        return False
```

**Refactoring:** Move Method, Hide Delegate, Encapsulate Field

### Pattern 10: Data Clumps

**Description:** Same group of variables appears together in multiple places.

**Impact:** Suggests missing abstraction, code duplication.

**Example:**
```python
# ❌ Data clumps
def create_user(name, email, phone, address_street, address_city, address_zip):
    pass

def update_user(user_id, name, email, phone, address_street, address_city, address_zip):
    pass

def send_mail(name, email, phone, address_street, address_city, address_zip):
    pass

# ✅ Introduce parameter object
from dataclasses import dataclass

@dataclass
class Address:
    street: str
    city: str
    zip_code: str

@dataclass
class ContactInfo:
    name: str
    email: str
    phone: str
    address: Address

def create_user(contact_info: ContactInfo):
    pass

def update_user(user_id: int, contact_info: ContactInfo):
    pass

def send_mail(contact_info: ContactInfo):
    pass
```

**Refactoring:** Extract Class, Introduce Parameter Object

### Pattern 11: Primitive Obsession

**Description:** Using primitive types instead of small objects for simple tasks.

**Impact:** Missing domain concepts, validation logic scattered.

**Example:**
```python
# ❌ Primitive obsession
def process_order(order_id: str, customer_email: str, total_cents: int):
    # Validation scattered
    if '@' not in customer_email:
        raise ValueError("Invalid email")
    if total_cents < 0:
        raise ValueError("Invalid amount")
    # Process...

# ✅ Use value objects
from dataclasses import dataclass

@dataclass
class Email:
    address: str

    def __post_init__(self):
        if '@' not in self.address:
            raise ValueError("Invalid email")

@dataclass
class Money:
    cents: int

    def __post_init__(self):
        if self.cents < 0:
            raise ValueError("Amount cannot be negative")

    @property
    def dollars(self):
        return self.cents / 100

@dataclass
class OrderId:
    value: str

def process_order(order_id: OrderId, email: Email, total: Money):
    # Validation is built into the types
    # Process...
```

**Refactoring:** Replace Data Value with Object, Introduce Value Object

### Pattern 12: Long Parameter List

**Description:** Functions with too many parameters.

**Impact:** Hard to understand, remember, and use correctly.

**Example:**
```python
# ❌ Long parameter list
def create_invoice(
    customer_id,
    customer_name,
    customer_email,
    items,
    subtotal,
    tax_rate,
    tax_amount,
    discount_code,
    discount_amount,
    shipping_cost,
    total,
    payment_method,
    billing_address,
    shipping_address
):
    pass

# ✅ Use parameter objects
from dataclasses import dataclass
from typing import List

@dataclass
class Customer:
    id: str
    name: str
    email: str

@dataclass
class InvoiceDetails:
    items: List[object]
    subtotal: float
    tax_rate: float
    tax_amount: float
    discount_code: str
    discount_amount: float
    shipping_cost: float
    total: float

@dataclass
class PaymentInfo:
    method: str
    billing_address: str
    shipping_address: str

def create_invoice(customer: Customer, details: InvoiceDetails, payment: PaymentInfo):
    pass
```

**Refactoring:** Introduce Parameter Object, Preserve Whole Object

### Pattern 13: Shotgun Surgery

**Description:** Single change requires modifications across many classes.

**Impact:** Easy to miss changes, high risk of bugs.

**Example:**
```python
# ❌ Shotgun surgery - adding a new payment method requires changes everywhere
class OrderProcessor:
    def process(self, order):
        if order.payment_method == 'credit_card':
            # handle credit card
        elif order.payment_method == 'paypal':
            # handle paypal
        # Need to add cash here

class InvoiceGenerator:
    def generate(self, order):
        if order.payment_method == 'credit_card':
            # credit card invoice
        elif order.payment_method == 'paypal':
            # paypal invoice
        # Need to add cash here

class Receipt:
    def create(self, order):
        if order.payment_method == 'credit_card':
            # credit card receipt
        elif order.payment_method == 'paypal':
            # paypal receipt
        # Need to add cash here

# ✅ Use polymorphism
from abc import ABC, abstractmethod

class PaymentMethod(ABC):
    @abstractmethod
    def process(self, amount): pass

    @abstractmethod
    def generate_invoice(self): pass

    @abstractmethod
    def create_receipt(self): pass

class CreditCardPayment(PaymentMethod):
    def process(self, amount): pass
    def generate_invoice(self): pass
    def create_receipt(self): pass

class PayPalPayment(PaymentMethod):
    def process(self, amount): pass
    def generate_invoice(self): pass
    def create_receipt(self): pass

class CashPayment(PaymentMethod):  # Just add one new class
    def process(self, amount): pass
    def generate_invoice(self): pass
    def create_receipt(self): pass

class OrderProcessor:
    def process(self, order):
        order.payment_method.process(order.total)
```

**Refactoring:** Move Method, Inline Class, Replace Conditional with Polymorphism

### Pattern 14: Lazy Class

**Description:** Class that doesn't do enough to justify its existence.

**Impact:** Unnecessary complexity, maintenance overhead.

**Example:**
```python
# ❌ Lazy class
class UserNameFormatter:
    def format(self, name):
        return name.strip().title()

class User:
    def __init__(self, name):
        formatter = UserNameFormatter()
        self.name = formatter.format(name)

# ✅ Inline the class
class User:
    def __init__(self, name):
        self.name = name.strip().title()
```

**Refactoring:** Inline Class, Collapse Hierarchy

## Detection Strategies

### Metrics-Based Detection

**Function/Method Complexity:**
- Lines of code > 50
- Cyclomatic complexity > 10
- Nesting depth > 4
- Parameters > 5

**Class Complexity:**
- Methods > 15 (large class)
- Methods > 20 (god class)
- Fields > 10
- Dependencies > 7

**Code Duplication:**
- Identical code blocks > 5 lines
- Similar code with minor variations
- Token-based similarity > 80%

### Pattern-Based Detection

**Look for:**
- Multiple methods accessing same external data (Feature Envy)
- Same parameter groups (Data Clumps)
- Primitive types for domain concepts (Primitive Obsession)
- Direct field access between classes (Inappropriate Intimacy)
- Long if-else chains on type (Switch Statements smell)

### Tool-Based Detection

**Python tools:**
- `radon` - Cyclomatic complexity, maintainability index
- `pylint` - General code quality
- `flake8` - Style and quality
- `mccabe` - Complexity checker
- `vulture` - Dead code
- `bandit` - Security issues

## Prioritization

**High Priority (Fix Soon):**
- God classes
- Shotgun surgery
- Feature envy
- Long parameter lists

**Medium Priority (Plan Refactoring):**
- Large classes
- Duplicate code
- Data clumps
- Primitive obsession

**Low Priority (Nice to Have):**
- Magic numbers
- Lazy classes
- Long method names
- Inconsistent naming

