After 47 years of mass-producing bugs, I’ve developed a refined nose for code smells. And by “refined,” I mean I’ve learned to completely ignore them. Join me on this journey of olfactory denial.

What Are Code Smells?

Code smells are patterns that suggest something might be wrong with your code. The keyword is “might.” Martin Fowler and his friends love cataloging these supposed problems:

  • Long methods
  • Large classes
  • Duplicate code
  • Feature envy
  • Data clumps
  • Primitive obsession

You know what I smell? Job security.

Why Code Smells Are Actually Code Perfume

Code Smell What They Say What I Hear
Long Method “Hard to understand” “Nobody will touch my code”
God Class “Too many responsibilities” “Single point of expertise”
Duplicate Code “Maintenance nightmare” “Redundancy is reliability”
Magic Numbers “Unclear intent” “Obvious if you know the system”
Dead Code “Remove it” “Historical documentation”

As the PHB from Dilbert would say: “I don’t understand what you do, therefore it must be valuable.” Your incomprehensible code is job security incarnate.

The Long Method: A Love Story

My masterpiece is a 3,847-line method called processEverything(). It:

  • Validates user input
  • Connects to 7 different databases
  • Calls 23 external APIs
  • Generates PDF reports
  • Sends emails
  • Updates the UI
  • Makes coffee (metaphorically)

Someone suggested I “extract methods.” I asked them: “Into what? Smaller methods that do less?” They couldn’t answer. Checkmate.

public void processEverything(Object... params) {
    // Line 1 of 3847
    // ... (imagine 3845 more lines here)
    // Line 3847
    log.info("Done processing everything");
}

As XKCD 1513 notes, code quality is subjective. My 3,847 lines are poetry.

Embracing Duplicate Code

The DRY principle (Don’t Repeat Yourself) is overrated. I prefer the WET principle: Write Everything Twice.

Benefits of duplicate code:

  1. If one copy breaks, you have a backup
  2. Each copy can evolve independently
  3. You can grep for functionality by looking for duplicates
  4. More lines = more value delivered
# user_service.py
def validate_email(email):
    if '@' in email and '.' in email:
        return True
    return False

# order_service.py  
def validate_email(email):
    if '@' in email and '.' in email:
        return True
    return False

# notification_service.py
def validate_email(email):
    if '@' in email and '.' in email:
        return True
    return False

# Why extract to a shared utility? Then you'd have a DEPENDENCY!

The God Class: Monotheism for Code

Object-oriented “experts” say classes should have a single responsibility. But why worship multiple small gods when you can have one omnipotent class?

My ApplicationManager.java does everything:

public class ApplicationManager {
    // Database operations
    public void saveUser() { }
    public void deleteUser() { }
    public void getUsers() { }
    
    // Authentication
    public void login() { }
    public void logout() { }
    public void resetPassword() { }
    
    // Payment processing
    public void chargeCard() { }
    public void refund() { }
    
    // Email
    public void sendWelcomeEmail() { }
    public void sendInvoice() { }
    public void sendReminder() { }
    
    // Reporting
    public void generatePDF() { }
    public void exportCSV() { }
    
    // File management
    public void uploadFile() { }
    public void deleteFile() { }
    
    // ... 247 more methods
}

2,341 lines, 263 methods, 1 class. This is peak object-oriented programming.

Magic Numbers: Actually Magical

So-called “magic numbers” are just numbers whose meaning is obvious to anyone who’s been here for 15 years:

if (status === 7) {
    // Everyone knows 7 means "pending review"
    timeout = 86400000;  // Obviously 24 hours in milliseconds
    maxRetries = 3;      // Standard retry count
    bufferSize = 8192;   // Optimal buffer, trust me
    
    if (errorCode === 23 || errorCode === 47 || errorCode === 128) {
        // These are the recoverable errors, obviously
        retry();
    }
}

Constants? Named variables? That’s just extra typing. Your brain should be the lookup table.

Feature Envy: Actually Friendship

When a method uses more data from another class than its own, it’s called “feature envy.” I call it networking.

class OrderProcessor:
    def calculate_shipping(self, customer):
        # This method REALLY loves Customer
        if customer.address.country == "US":
            if customer.membership.tier == "gold":
                if customer.history.total_orders > 100:
                    if customer.preferences.fast_shipping:
                        return customer.address.calculate_zone_rate()
        # ... 200 more lines accessing Customer

Why move this method to Customer? Then I’d have to open a different file. The horror.

Data Clumps: Actually Friendship Groups

When the same three or four data items appear together in multiple places, you could create a class. Or you could embrace the camaraderie:

function createUser(firstName, lastName, email, phone, street, city, state, zip) { }
function updateUser(firstName, lastName, email, phone, street, city, state, zip) { }
function validateUser(firstName, lastName, email, phone, street, city, state, zip) { }
function formatUser(firstName, lastName, email, phone, street, city, state, zip) { }

8 parameters, 4 functions, infinite flexibility. Need to add a field? Just add another parameter everywhere. Consistency!

Dead Code: Digital Archaeology

Commented-out code and unused functions are not “dead code.” They’re historical artifacts:

// TODO: Remove this after the 2019 migration
// public void oldPaymentProcess() {
//     // This was the original implementation
//     // Keeping it just in case
//     // Don't delete - John said this might be needed
//     // Actually I think Sarah needs this
//     // UPDATE 2021: Maybe we'll need this for the new client
//     // UPDATE 2023: Still here, still useful somehow
// }

// Unused function - DO NOT DELETE
public void legacyExport() {
    // No one knows what calls this
    // But removing it might break something
    // Better safe than sorry
}

As Catbert would say: “Anything you delete will be exactly what you need tomorrow.”

Primitive Obsession: Actually Minimalism

Using primitives everywhere instead of small objects is called “primitive obsession.” I call it performance optimization:

// "Best practice" - wasteful objects
Money price = new Money(19.99, Currency.USD);
Email userEmail = new Email("user@example.com");
PhoneNumber phone = new PhoneNumber("+1-555-0100");

// My approach - efficient primitives
double price = 19.99;  // It's obviously dollars
String email = "user@example.com";  // What else would it be?
String phone = "+1-555-0100";  // Numbers are strings, deal with it

Why create 47 wrapper classes when String and int exist?

My Code Smell Tolerance Scale

Smell Intensity Action Required
Faint whiff Ignore completely
Noticeable odor Still ignore
Strong smell Consider ignoring
Overwhelming stench Add air freshener (comment)
Code actively decomposing Blame the intern

The Ultimate Defense

When someone points out code smells in your codebase, deploy the ultimate counter-argument:

“It works in production.”

That’s it. That’s the defense. If the smelly code is running in production without incident, it’s not smelly — it’s battle-tested.

# This method has 47 parameters, 12 global variables,
# 3 nested try-catch blocks, and talks to 6 databases.
# It also handles authentication, logging, and email.
# Code reviewers hate it.
# 
# But it's been in production since 2014.
# Zero reported bugs.
# Seniority wins.

Conclusion

Code smells are just the opinion of people who have time to refactor. Real engineers ship features. Real engineers embrace the smell. Real engineers have air purifiers in their offices.

The next time someone mentions “code smell” in a review, respond with:

“I prefer to call it ‘code character.’ It tells a story.”

And remember the wisdom of XKCD 1205: sometimes the time spent complaining about code smells exceeds the time saved by fixing them.

Your nose will adjust. Your standards will lower. And one day, you too will write a 3,847-line method and call it art.


The author’s IDE has stopped showing warning icons. It gave up in 2016. They have an understanding.