The Art of Ignoring Code Smells
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:
- If one copy breaks, you have a backup
- Each copy can evolve independently
- You can grep for functionality by looking for duplicates
- 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.