Java

Code Smells Catalog

Code smells are surface indications of deeper problems. Like symptoms of an illness, they don't tell you exactly what's wrong, but they point you in the right direction. This article provides a comprehensive catalog of code smells with detection techniques, examples, and recommended refactorings.

📋 At a Glance

AspectDetails
Total Smells Covered22 core smells
CategoriesBloaters, OO Abusers, Change Preventers, Dispensables, Couplers
Detection ToolsSonarQube, IntelliJ inspections, SpotBugs
Key InsightSmell = Symptom, not disease
Business ImpactEarly smell detection prevents 60% of major refactorings

🎯 What You'll Learn

After reading this article, you will be able to:

  • Recognize all major code smells at a glance
  • Understand the root causes behind each smell
  • Apply appropriate refactorings for each smell
  • Configure tools for automatic smell detection
  • Prioritize smells based on impact and fix difficulty
  • Use smells in code reviews constructively

🔥 Production Story: The Thousand-Line Method

A team inherited a legacy e-commerce system. The checkout method was legendary:

JAVA(13 lines)
Code
Loading syntax highlighter...
The symptoms:
  • Bug fixes took 2 days minimum (half day just to understand the code)
  • Every change broke something else
  • No one could test it properly (integration test took 8 minutes)
  • New developers avoided touching it
The smells present:
  • Long Method (1,047 lines)
  • Feature Envy (reached into 12 different classes)
  • Data Clumps (same 5 parameters passed everywhere)
  • Comments (100+ comments explaining "what" instead of "why")
  • Duplicate Code (discount logic repeated 4 times with variations)
The fix: 3 weeks of systematic refactoring:
  • Extracted 14 focused methods
  • Created 6 collaborating services
  • Introduced Parameter Objects for data clumps
  • Result: Each method < 20 lines, 90% test coverage, bugs fixed in hours

🧠 Mental Model: Smell Categories

TEXT(36 lines)
Code
Loading syntax highlighter...

🔬 Deep Dive: Complete Smell Catalog

Category 1: Bloaters

Long Method

What: Method that's too long to understand at a glance.
Threshold: > 20 lines (some say 10)
Symptoms:
  • Multiple levels of abstraction in one method
  • Comments separating "sections"
  • Scrolling required to read method
  • Multiple responsibilities
JAVA(64 lines)
Code
Loading syntax highlighter...
Refactoring: Extract Method, Replace Temp with Query

Large Class (God Class)

What: Class that does too much.
Threshold: > 200-500 lines, > 15 public methods, > 10 fields
Symptoms:
  • Class name includes "Manager", "Processor", "Handler", "Util"
  • Many unrelated methods
  • Multiple groups of methods using different fields
  • Difficult to name precisely
JAVA(44 lines)
Code
Loading syntax highlighter...
Refactoring: Extract Class, Extract Subclass, Extract Interface

Primitive Obsession

What: Using primitives instead of small objects for domain concepts.
Symptoms:
  • String for email, phone, currency code
  • int for quantities, amounts, IDs
  • Validation logic scattered everywhere
JAVA(43 lines)
Code
Loading syntax highlighter...
Refactoring: Replace Primitive with Object, Introduce Parameter Object

Long Parameter List

What: Method with too many parameters.
Threshold: > 3-4 parameters
Symptoms:
  • Easy to mix up parameter order
  • Boolean parameters (what does true mean?)
  • Many parameters of same type
JAVA(34 lines)
Code
Loading syntax highlighter...
Refactoring: Introduce Parameter Object, Preserve Whole Object

Data Clumps

What: Same group of data appears together in multiple places.
Symptoms:
  • Same 3+ parameters passed to multiple methods
  • Same fields in multiple classes
  • Same local variables declared together
JAVA(31 lines)
Code
Loading syntax highlighter...
Refactoring: Extract Class, Introduce Parameter Object

Category 2: Object-Orientation Abusers

Switch Statements

What: Complex switch/if-else chains, especially on type.
Symptoms:
  • Switch on type field
  • Same switch repeated in multiple places
  • Adding new type requires changes everywhere
JAVA(26 lines)
Code
Loading syntax highlighter...
Refactoring: Replace Conditional with Polymorphism, Replace Type Code with State/Strategy

Temporary Field

What: Field that's only used in certain circumstances.
Symptoms:
  • Field is null/default most of the time
  • Complex conditionals check if field is set
  • Field only populated for specific operations
JAVA(35 lines)
Code
Loading syntax highlighter...
Refactoring: Extract Class, Introduce Null Object

Refused Bequest

What: Subclass doesn't use or want inherited behavior.
Symptoms:
  • Overriding methods to throw UnsupportedOperationException
  • Empty overrides
  • Ignoring inherited fields
JAVA(31 lines)
Code
Loading syntax highlighter...
Refactoring: Replace Inheritance with Delegation, Extract Superclass/Interface

Category 3: Change Preventers

Divergent Change

What: One class changed for multiple different reasons.
Symptoms:
  • "I have to change this class whenever..."
  • Different parts of class change for different features
  • Multiple developers editing same class for different reasons
JAVA(24 lines)
Code
Loading syntax highlighter...
Refactoring: Extract Class (one per reason for change)

Shotgun Surgery

What: Single change requires modifications to many classes.
Symptoms:
  • Adding a field requires changes in 10 places
  • Small feature touches many files
  • Fear of making changes due to ripple effects
JAVA(20 lines)
Code
Loading syntax highlighter...
Refactoring: Move Method, Move Field, Inline Class

Parallel Inheritance Hierarchies

What: Creating a subclass in one hierarchy requires creating subclass in another.
Symptoms:
  • Every Shape needs a ShapeFactory
  • Every Employee needs an EmployeeUI
  • Hierarchies mirror each other
JAVA(30 lines)
Code
Loading syntax highlighter...
Refactoring: Move Method, Collapse Hierarchy

Category 4: Dispensables

Comments (Excessive)

What: Comments that explain what code does instead of why.
Symptoms:
  • Every line has a comment
  • Comments repeat what code says
  • Comments become outdated
  • Comments apologize for bad code
JAVA(27 lines)
Code
Loading syntax highlighter...
Refactoring: Extract Method, Rename Method, Introduce Assertion

Duplicate Code

What: Same or similar code in multiple places.
Symptoms:
  • Copy-paste patterns
  • Bug fixed in one place but not another
  • Same structure with slight variations
JAVA(36 lines)
Code
Loading syntax highlighter...
Refactoring: Extract Method, Extract Class, Pull Up Method, Form Template Method

Speculative Generality

What: Code written for "future needs" that never come.
Symptoms:
  • Abstract class with only one subclass
  • Parameters/options that are never used
  • Complex configuration for simple needs
  • "We might need this someday"
JAVA(21 lines)
Code
Loading syntax highlighter...
Refactoring: Collapse Hierarchy, Inline Class, Remove Parameter

Category 5: Couplers

Feature Envy

What: Method uses more features of another class than its own.
Symptoms:
  • Method calls many getters on another object
  • Method manipulates another object's data extensively
  • Logic should probably live in the other class
JAVA(37 lines)
Code
Loading syntax highlighter...
Refactoring: Move Method, Extract Method

Inappropriate Intimacy

What: Classes that know too much about each other's internals.
Symptoms:
  • Classes access each other's private data (via reflection or package-private)
  • Bi-directional dependencies
  • Changes in one class break the other
JAVA(37 lines)
Code
Loading syntax highlighter...
Refactoring: Move Method, Move Field, Change Bidirectional to Unidirectional

Message Chains

What: Long chains of method calls navigating object structure.
Symptoms:
  • a.getB().getC().getD().doSomething()
  • Violation of Law of Demeter
  • Tight coupling to object structure
JAVA(27 lines)
Code
Loading syntax highlighter...
Refactoring: Hide Delegate, Extract Method, Move Method

Middle Man

What: Class that only delegates to another class.
Symptoms:
  • Most methods just call same method on another object
  • Class adds no value
  • Extra indirection without purpose
JAVA(46 lines)
Code
Loading syntax highlighter...
Refactoring: Remove Middle Man, Inline Method

📊 Smell Detection Tools Configuration

SonarQube Rules

YAML(13 lines)
Code
Loading syntax highlighter...

IntelliJ Inspections

TEXT(16 lines)
Code
Loading syntax highlighter...

⚠️ Common Mistakes

Mistake 1: Treating Smells as Absolutes

Problem: Blindly following smell thresholds.
TEXT(4 lines)
Code
Loading syntax highlighter...

Mistake 2: Refactoring Without Tests

Problem: Fixing smells while breaking functionality.
TEXT(3 lines)
Code
Loading syntax highlighter...

Mistake 3: Over-Refactoring

Problem: Creating new smells while fixing old ones.
TEXT(4 lines)
Code
Loading syntax highlighter...

🐛 Debug This: The Mystery of the Failing Refactoring

A developer reports: "I refactored this method to be shorter and now it doesn't work. But I only extracted methods - I didn't change any logic!"

JAVA(54 lines)
Code
Loading syntax highlighter...
Why does the refactored code fail? Find the hidden code smell!

✅ Solution:
The root cause is a Temporary Field smell combined with unsafe parallelization:
  1. Original problem: currentOrder is a temporary field - it's only valid during processOrder()
  2. Refactoring issue: The new code uses parallelStream(), which executes lambdas in different threads
  3. Race condition: By the time some parallel steps run, currentOrder might already be null
The code smells:
  • Temporary Field: currentOrder is set, used, then cleared - class state is inconsistent
  • Mutable Shared State: Field is modified during execution
  • Hidden Coupling: Methods implicitly depend on currentOrder being set
The lesson: Temporary Field smell makes code fragile. When you pass data through fields instead of parameters, you create hidden dependencies that break under refactoring. Always prefer passing data explicitly.
Fix: Pass order as parameter to each method instead of storing in field.

💻 Exercises

Exercise 1: Smell Identification

⭐ Difficulty: Easy | ⏱️ Time: 15 minutes

Task: Identify all smells in this code:
JAVA(33 lines)
Code
Loading syntax highlighter...
Find: Long Parameter List, Long Method, Switch Statements, Temporary Field, Primitive Obsession
✅ Solution:
SmellLocationSeverity
Long Parameter List6 parametersHigh
Long Method100+ lines impliedHigh
Switch Statementstype-based switchMedium
Temporary FieldtempReport, isProcessingMedium
Primitive ObsessionString type, String formatLow

Exercise 2: Refactoring Practice

⭐⭐ Difficulty: Medium | ⏱️ Time: 20 minutes

Task: Refactor this code to eliminate Feature Envy:
JAVA(18 lines)
Code
Loading syntax highlighter...
✅ Solution:
JAVA(33 lines)
Code
Loading syntax highlighter...

Exercise 3: Code Smell Catalog

⭐⭐ Difficulty: Medium | ⏱️ Time: 15 minutes

Task: Match each smell with its primary solution:
SmellSolution
1. Long MethodA. Replace with Strategy/Polymorphism
2. Long Parameter ListB. Extract Class
3. Data ClumpsC. Introduce Parameter Object
4. Switch StatementsD. Extract Method
5. Divergent ChangeE. Move Method to appropriate class
6. Feature EnvyF. Create dedicated class for clumped data
✅ Solution:
SmellSolution
Long MethodD. Extract Method
Long Parameter ListC. Introduce Parameter Object
Data ClumpsF. Create dedicated class for clumped data
Switch StatementsA. Replace with Strategy/Polymorphism
Divergent ChangeB. Extract Class
Feature EnvyE. Move Method to appropriate class

Exercise 4: Refactor Data Clumps

⭐⭐⭐ Difficulty: Medium-Hard | ⏱️ Time: 20 minutes

Task: Identify and fix the Data Clumps smell:
JAVA(12 lines)
Code
Loading syntax highlighter...
✅ Solution:
JAVA(20 lines)
Code
Loading syntax highlighter...

Exercise 5: Complete Smell Audit

⭐⭐⭐⭐ Difficulty: Hard | ⏱️ Time: 25 minutes

Task: Perform a complete smell audit on this class and refactor:
JAVA(35 lines)
Code
Loading syntax highlighter...
✅ Solution:

Smells found:

  1. Temporary Fields: initialized, conn, lastQuery
  2. Long Parameter List: 7 parameters
  3. Switch Statements: type-based branching
  4. Long Method: 100+ lines implied
  5. Inappropriate Intimacy: Direct DB connection handling
  6. Feature Envy: Email sending mixed with reporting
JAVA(29 lines)
Code
Loading syntax highlighter...

🎤 Senior-Level Interview Questions

Question #1: How do you prioritize which smells to fix?

Strong answer:

I use a risk-based approach:

  1. High priority:
    • Smells in hot paths (frequently changed code)
    • Smells blocking new features
    • Smells causing production bugs
  2. Medium priority:
    • Smells in moderately changed code
    • Smells slowing down development
  3. Low priority:
    • Smells in stable, rarely-touched code
    • Cosmetic smells in working code
Formula:
Priority = (Change Frequency × Bug Density × Business Impact)

Question #2: What's the relationship between smells and SOLID?

Strong answer:

Smells are symptoms of SOLID violations:

SmellUsually Violates
Long MethodSRP
Large ClassSRP
Divergent ChangeSRP
Shotgun SurgerySRP (inverted)
Switch StatementsOCP
Refused BequestLSP
Fat Interface smellISP
Feature EnvySRP, encapsulation

Knowing SOLID helps predict what refactoring to apply.


Question #3: When should you NOT fix a code smell?

Strong answer:
  1. Code is being deleted soon - waste of effort
  2. No test coverage - risk of breaking it
  3. Deadline pressure - log it, fix after
  4. Code is stable and working - "ain't broke"
  5. Smell is intentional (trade-off) - document why
  6. Fix creates worse smell - cure worse than disease

📝 Summary & Key Takeaways

Quick Reference Table

CategorySmellRefactoring
BloatersLong MethodExtract Method
BloatersLarge ClassExtract Class
BloatersPrimitive ObsessionValue Object
BloatersLong Parameter ListParameter Object
OO AbusersSwitch StatementsPolymorphism
OO AbusersRefused BequestComposition
Change PreventersDivergent ChangeExtract Class
Change PreventersShotgun SurgeryMove Method
DispensablesDuplicate CodeExtract Method
DispensablesCommentsSelf-documenting code
CouplersFeature EnvyMove Method
CouplersMessage ChainsHide Delegate

Detection Checklist

  • Method > 20 lines?
  • Class > 200 lines?
  • Parameters > 4?
  • Switch on type?
  • Same code in multiple places?
  • Method uses other class's data extensively?
  • Long chains of getters?

🏁 Conclusion

Code smells are your early warning system. They tell you where problems are brewing before they become crises. Learn to recognize them, and you'll catch issues while they're still easy to fix.

Key insight: Smells are symptoms, not diseases. The same smell can have different causes and need different solutions. Use your judgment.
Your next step: Continue to Part 5 (Code Quality Metrics Framework) to learn how to measure code quality objectively.

📅 Review Schedule for This Article

DayTaskTime
Day 1Review Code Smells Catalog table5 min
Day 3Redo Exercise 1 (Smell Identification)15 min
Day 7Answer interview questions without looking10 min
Day 14Redo Debug This (Temporary Field paradox)10 min
Day 30Audit one class in your project for code smells15 min

Next in series: [Part 5: Code Quality Metrics Framework]