🎁 Get the FREE AI Skills Starter Guide β€” Subscribe β†’
BytesAgainBytesAgain
πŸ¦€ ClawHub

Code Smell Diagnosis

by @quochungto

Scan a codebase or code fragment for the 22 named code smells from Fowler's refactoring catalog and produce a prioritized diagnosis report with the specific...

⚑ When to Use
TriggerAction
This skill applies when:
- A developer says "this code is a mess" but cannot name what exactly is wrong
- A code review surfaces problems that need specific names and specific fixes, not just "clean this up"
- A refactoring effort is starting and needs a prioritized list of what to address first
- Code keeps breaking in the same places β€” a smell is likely attracting bugs
- A pull request adds complexity to already-complex code and needs a targeted intervention
**The core insight from Fowler and Beck:** Refactoring without diagnosis is guesswork. When you can name the smell precisely, the refactoring prescription follows directly. "This is Feature Envy" immediately implies Move Method. "This is a Switch Statement on a type code" immediately implies Replace Type Code with Subclasses or Replace Type Code with State/Strategy followed by Replace Conditional with Polymorphism. The name unlocks the remedy.
**This is the hub skill.** Sibling skills execute specific remedies once a smell is diagnosed:
- `type-code-refactoring-selector` β€” when Primitive Obsession or Switch Statements are present
- `conditional-simplification-strategy` β€” when Switch Statements or complex conditionals are present
- `class-responsibility-realignment` β€” when Feature Envy, Inappropriate Intimacy, or Shotgun Surgery are present
- `big-refactoring-planner` β€” when multiple smells indicate a systemic design problem
- `data-organization-refactoring` β€” when Data Clumps, Primitive Obsession, or Data Class are present
---
πŸ’‘ Examples

Example 1: Service Class Audit

Scenario: A developer inherits a PaymentService class (280 lines, 12 methods, 9 instance variables) and asks for a diagnosis before adding a new payment gateway.

Step 1 β€” Structural read:

  • 280 lines, 12 methods: candidate for Large Class
  • 9 instance variables: some look like they form clusters (gatewayUrl, gatewayApiKey, gatewayTimeout β†’ Data Clumps candidate)
  • Method names: processPayment, validateCard, logTransaction, formatCurrency, sendWebhook, retryWebhook, buildGatewayRequest, parseGatewayResponse β€” some methods clearly work on gateway concerns, others on local concerns
  • Step 2 β€” Smell check (selected findings):

    *Divergent Change (HIGH):* The class changes when the gateway changes (3 methods: buildGatewayRequest, parseGatewayResponse, processPayment) AND when the webhook logic changes (2 methods: sendWebhook, retryWebhook) AND when logging changes (1 method: logTransaction). Three axes of change in one class.

    *Data Clumps (MEDIUM):* gatewayUrl, gatewayApiKey, gatewayTimeout appear together in every gateway-related method signature. Deleting gatewayUrl makes the others meaningless.

    *Long Method (MEDIUM):* processPayment is 55 lines with embedded comments marking sections ("// validate", "// build request", "// process", "// log").

    Step 3 β€” Prioritize: Divergent Change first (it's a change preventer). Data Clumps second (will simplify gateway extraction). Long Method third (the extracted sections will become methods in the new class).

    Diagnosis report excerpt:

    ### Finding #1 β€” Divergent Change β€” HIGH

    Location: PaymentService (entire class) Evidence: The class changes for at least three distinct reasons: (1) Gateway integration changes β†’ buildGatewayRequest, parseGatewayResponse, processPayment (2) Webhook delivery changes β†’ sendWebhook, retryWebhook (3) Logging changes β†’ logTransaction Prescription: Extract Class for each axis of change. - Extract GatewayClient (gateway request/response) - Extract WebhookDispatcher (send + retry logic) - PaymentService retains orchestration only Why this prescription: Divergent Change calls for Extract Class on each axis. The test: "I have to change these N methods every time X happens." Three different values of X = three different classes needed. Next step: Extract GatewayClient first β€” it's the largest axis and will expose the Data Clumps smell for remedy.


    Example 2: Single Method Diagnosis

    Scenario: A code reviewer asks what's wrong with this Python method:

    def calculate_charge(customer_type, base_price, quantity, discount_code,
                         loyalty_years, is_weekend, tax_rate):
        if customer_type == 'enterprise':
            price = base_price * quantity * 0.85
        elif customer_type == 'retail':
            price = base_price * quantity
        elif customer_type == 'wholesale':
            price = base_price * quantity * 0.7
        else:
            price = base_price * quantity

    if discount_code == 'SUMMER10': price *= 0.90 elif discount_code == 'VIP20': price *= 0.80

    if loyalty_years > 5: price *= 0.95

    if is_weekend: price *= 1.05

    return price * (1 + tax_rate)

    Step 2 β€” Smell check:

    *Long Parameter List (HIGH):* 7 parameters. Why this branch: there is no obvious existing object that holds these β€” customer_type, loyalty_years suggest a Customer object; base_price, quantity, discount_code suggest an Order. Two Introduce Parameter Object applications.

    *Switch Statements (HIGH):* The customer_type branching recurs β€” any new customer type requires finding every switch on customer_type and adding a case. Why this branch: type code affects behavior, and customer type is unlikely to change at runtime β†’ Replace Type Code with Subclasses on Customer, then Replace Conditional with Polymorphism for the pricing logic.

    Diagnosis report excerpt:

    ### Finding #1 β€” Switch Statements β€” HIGH

    Location: calculate_charge(), lines 2-9 (customer_type branching) Evidence: A switch on customer_type determines pricing multiplier. This switch will exist wherever customer pricing is computed. Every new customer type requires finding every such switch. Prescription: Replace Type Code with Subclasses (EnterpriseCustomer, RetailCustomer, WholesaleCustomer); then Replace Conditional with Polymorphism (each subclass implements its own price multiplier method). Why this branch: type code affects behavior; customer type doesn't change at runtime for a given customer β†’ subclassing is appropriate. (If type changed at runtime, use Replace Type Code with State/Strategy instead.) Next step: Introduce Parameter Object first (Finding #2) to create a Customer object; then apply type code replacement on that object.

    Finding #2 β€” Long Parameter List β€” HIGH

    Location: calculate_charge() signature (7 parameters) Evidence: customer_type, loyalty_years β†’ Customer data cluster. base_price, quantity, discount_code β†’ Order data cluster. Deleting customer_type makes loyalty_years ambiguous without context. Prescription: Introduce Parameter Object twice β€” Customer(customer_type, loyalty_years) and Order(base_price, quantity, discount_code). Then: Preserve Whole Object β€” pass Customer and Order, not their fields. Next step: Define Customer and Order dataclasses; update the signature. This unblocks the Switch Statement refactoring (Finding #1).

    Refactoring sequence: 1. Introduce Parameter Object: Customer, Order 2. Replace Type Code with Subclasses on Customer 3. Replace Conditional with Polymorphism for pricing 4. Preserve Whole Object in calculate_charge signature


    Example 3: Inheritance Hierarchy Diagnosis

    Scenario: A codebase has Animal, Dog, Cat, Bird hierarchy. A developer notices that every time a new animal species is added, a parallel set of AnimalSound, DogSound, CatSound, BirdSound classes must also be added.

    Step 2 β€” Smell check:

    *Parallel Inheritance Hierarchies (HIGH):* Subclassing Animal always requires subclassing AnimalSound. The prefix pattern is exact (Dog/DogSound, Cat/CatSound).

    *Prescription:* Make instances of one hierarchy refer to instances of the other (Strategy pattern). Move Method and Move Field from AnimalSound hierarchy into Animal hierarchy using a sound strategy object. Once all behavior is moved, the AnimalSound hierarchy disappears.


    View on ClawHub
    TERMINAL
    clawhub install bookforge-code-smell-diagnosis

    πŸ§ͺ Use this skill with your agent

    Most visitors already have an agent. Pick your environment, install or copy the workflow, then run the smoke-test prompt above.

    πŸ” Can't find the right skill?

    Search 60,000+ AI agent skills β€” free, no login needed.

    Search Skills β†’