The Myth of Clean Code
I have written some truly awful code.
I've committed every sin I'm about to tell you not to commit. I've written 800-line functions that do fourteen different things and also check the weather. I've named variables temp, temp2, and temp_final in the same function. I've abstracted the absolute hell out of addition because I read somewhere that "composition over inheritance" was important and I'd just learned what interfaces were.
I have been, in short, an absolute nightmare to work with at times.
But here's the thing - and I really need you to understand this - you are going to do all of these things too. You're going to read this, nod sagely, and then immediately go write a function called doStuff() that does seven unrelated things because you're tired and the deadline is tomorrow and your brain is made of cheese.
We are all terrible. Let me tell you about it.
The Myth I Believed
When I first read "Clean Code," I had a revelation. I was going to write perfect, beautiful, artisanal code. Every function would be a haiku. Every class would sing.
I spent three weeks refactoring a working system because the variable names weren't descriptive enough.
The system broke. I introduced five new bugs. My coworker asked me what the hell I was doing.
I had no good answer.
The Sins I've Committed (And You Will Too)
Let me catalogue my failures so you can at least see them coming:
Sin #1: Over-Abstraction (My Personal Favorite)
I once wrote three interfaces and four classes to handle logging messages to a file. It was beautiful. It was flexible. It was completely unnecessary.
The system already had logging. I just didn't like how it worked.
I spent two days building my perfect logging framework. It would have taken me twenty minutes to just use what was there.
You will do this. You will convince yourself that this time the abstraction is justified. It won't be.
Sin #2: Premature Optimization
I rewrote a database query because I was convinced it would be slow at scale.
We had 47 users.
The query ran in 3 milliseconds.
I spent four hours on it.
Sin #3: Bikeshedding Myself Into Madness
I once spent an entire afternoon debating with myself whether a function should be called getUserData() or fetchUserInformation().
The function was six lines long and called by exactly one other function.
No one cared. Not even me, really. But I couldn't ship until it was "right."
It still bothers me that I picked getUserData() instead of queryUserTable().
Balls. >_<
Sin #4: Not Shipping
I've killed more features by refactoring than by inadvertently introducing bugs.
"Just a bit cleaner," I'd say. "Just needs better separation of concerns."
Meanwhile, users were waiting for the feature. My boss was waiting for the feature. The business was waiting for the feature.
But the code wasn't clean enough.
Here's what over-abstraction looks like in practice:
# The "clean code" version
class NumberAdder
def initialize(calculator)
@calculator = calculator
end
def add(a, b)
@calculator.perform_addition(a, b)
end
end
# Just do this instead:
def add(a, b)
a + b
end
What I Should Have Done (And You Should Try, Even Though You Won't)
Here's the uncomfortable truth: context matters more than principles.
You know this. I know this. We all know this.
And yet I've watched developers (me, I'm talking about me) refactor a throwaway script like they're building the Mars rover's navigation system.
A startup MVP doesn't need the same architecture as a banking system. A script you'll run once doesn't need the same rigor as a library used by millions. A proof-of-concept doesn't need perfect test coverage.
But you'll do it anyway. Because it feels good to write "proper" code. Because someone might see it. Because you read that blog post about SOLID principles and now you have opinions about the Liskov Substitution Principle.
Stop it. Ship the thing.
What Actually Matters (When You Can Be Bothered)
Look, if you're actually going to try - and I admire your optimism - here's what to focus on:
Does It Work?
This seems obvious. It isn't.
I've reviewed pull requests where the code was beautifully architected, perfectly formatted, and completely wrong.
Functional first. Always. You can't refactor broken.
Can Someone Else Understand It?
And by "someone else" I mean you, six months from now, at 2 AM, when the pager goes off.
That clever bit with the triple-nested ternary operator? Future you will hate current you. Future me already hates me plenty, but maybe you can catch a break if you just nest those three conditions.
Comments aren't admitting defeat. They're leaving breadcrumbs for the poor bastard who has to fix your code. Which, again, will probably be you.
Is It Maintainable?
Can you add a feature without rewriting the entire module?
Can you fix a bug without a PhD in your own code?
Can someone new join the team and contribute in less than six months?
If not, your "clean" code is actually quite dirty.
Does It Serve the Business Need?
Here's the bit that matters most: pretty code that doesn't solve problems is useless.
I don't care how elegant your solution is if it doesn't do what users need.
Ship working software. Make it pretty later if there's time.
Narrator: There's never time.
What I'm Trying to Do Now (With Mixed Results)
I'm trying to write code for humans first, computers second.
I'm trying to make intentional trade-offs instead of following rules blindly.
I'm trying to know when to optimize and when to ship.
I'm trying to leave things better than I found them, but not perfect. Perfect is the enemy of done, and done is what pays the bills.
Am I succeeding? Not really. I still bike-shed. I still over-engineer. I still refactor things that don't need refactoring.
But I ship more than I used to. And the code works more often than it used to. And my coworkers seem slightly less annoyed with me.
Progress.
The Point (If There Is One)
Read "Clean Code." It's a good book. Learn from it.
Then use your actual human brain to apply it contextually.
The best code is code that ships, works, and doesn't make your coworkers want to seriously consider the ramifications of homicide quit.
Everything else is just us making ourselves feel better about the fact that we're writing instructions for rocks we've flattened and - by virtue of magical electrocution - tricked into a simulation of thinking. [citation needed - @daisyowl says the internet, but we don't trust the internet, so...]
You're going to commit all my sins anyway. At least now you'll feel appropriately guilty about it.