I've been writing software since the early '90s. In that time, I've mass-replied to email threads about indentation. I've blocked pull requests over naming conventions. I've given a conference-room speech about code coverage that I now find genuinely embarrassing.
I was not a casual participant in these debates. I was a zealot.
Thirty years later, I have some confessions. Here are the things I used to swear by that I no longer care about — and the moments that cured me.
Tabs vs. Spaces
The granddaddy. The holy war. The one that Silicon Valley dedicated an entire subplot to, and every developer watching nodded like it was a documentary.
I was a spaces guy. Four spaces, no exceptions. I would bring it up in interviews — not as a question, but as a statement of values. "We use four spaces here." Like I was describing the company's mission.
The moment that cured me: I once sat in a meeting — a real meeting, with real humans who were being paid real salaries — and watched two senior engineers argue about this for twenty minutes. Twenty minutes. We had a production bug in the queue. A customer was waiting. And we were debating whitespace.
That afternoon I added a .editorconfig file to the repo, set the rule, and committed it. The formatter handled it from that point forward. Nobody ever discussed it again.
The lesson: If your opinion can be enforced by a config file, it's not an engineering decision. It's a preference. Automate it and move on.
100% Code Coverage
I used to preach this one with the fervor of a convert. I'd review PRs and flag anything that dropped coverage below the threshold. I had a dashboard. I had a Slack bot that announced coverage changes. I was insufferable.
Then I watched a team hit 100% coverage and ship a bug that took down production for six hours.
How? Every test passed. Every line was covered. But the tests were testing implementation, not behavior. They verified that functions were called with the right arguments — not that the system actually did what users expected. When the underlying behavior drifted, the tests kept passing because they were testing the scaffolding, not the building.
The coverage number was perfect. The software was broken.
What I care about now is much simpler: does this test catch a real bug? If I delete this test, is there a scenario where broken code ships that wouldn't have shipped otherwise? If the answer is no, the test is just ceremony — a green checkmark that makes you feel responsible without actually protecting anything.
Coverage is a vanity metric. A useful one, sometimes. But a vanity metric.
"Clean Code" Absolutism
I've read the book. I've taught the principles. I've told junior developers that functions should be no longer than five lines and every variable name should read like prose.
And then I watched what happens when a team takes that advice to its logical extreme.
I inherited a codebase that was immaculate. Every function was four lines long. Every name was descriptive. The linter was happy. Uncle Bob would have wept with joy.
It was also completely impossible to debug. Following a single request through the system meant jumping through twelve layers of abstraction, each one a beautifully named four-line function that delegated to another beautifully named four-line function. The call stack looked like a table of contents. Understanding what the code did required holding a mental map that no human brain could maintain.
Meanwhile, down the hall, another team had a service with a 200-line function that everyone apologized for. You know what? It worked. It had worked for three years. New developers could read it top to bottom and understand exactly what it did. When it broke, you could find the bug in minutes because everything was right there.
Clean code principles are useful guidelines. They are not commandments. Three lines of duplicated code is sometimes better than a premature abstraction that nobody can follow. The question isn't "is this clean?" The question is: can someone new understand this code in a reasonable amount of time? That's it. That's the whole test.
Choosing the "Right" Framework
Early in my career, I watched a team spend three weeks evaluating JavaScript frameworks for a project. They built spreadsheets. They ran benchmarks. They debated bundle sizes. They wrote proof-of-concept apps in four different frameworks.
The project would have been finished in three weeks.
I've seen this pattern repeat dozens of times across my career. The seductive trap of believing that picking the right tool is the most important decision, when really the most important decision is to start building.
For 90% of projects, the "right" framework is whichever one your team already knows. The second-best framework that ships is infinitely better than the perfect framework that's still being evaluated. The best technology choice is almost always the boring one.
Honorable Mentions
A rapid-fire round of things I've stopped losing sleep over:
Bracket placement — same line vs. next line. I have genuinely seen a pull request rejected over this. The PR fixed a production bug. The bug stayed in production for another day while the developer reformatted their braces. We deserved that outage.
Git commit message formatting — Conventional commits are fine. So is just writing what you did in plain English. Nobody is reading your git log for literary merit. Write something useful and move on.
REST vs. GraphQL debates before you have users — You're optimizing an API for traffic patterns you haven't observed yet. Ship something. You can re-architect when you actually understand your access patterns, which you won't until real humans are using your software.
"We should rewrite this in Rust" — No. You should fix the memory leak in the service that's actually running. In production. Right now. Rust is a great language. It is not a magic wand you wave at operational problems.
Spending a week choosing between two nearly identical libraries — They both do the thing. Pick one. If it turns out to be wrong, you'll switch later. You probably won't switch later.
What Actually Matters
After 30 years, my list of things I genuinely care about has gotten very short:
- Does it work?
- Can someone else maintain it?
- Did you ship it?
That's it. Everything else is noise dressed up as professionalism.
The best engineers I've worked with aren't the ones with the strongest opinions about formatting or the deepest knowledge of design patterns. They're the ones who solve problems, communicate clearly, and ship reliable software. They have opinions about tabs and brackets and frameworks — everyone does — but they don't confuse those opinions with engineering.
I still have preferences. I still configure my linters and formatters. I still write tests and care about code quality. But I stopped mistaking preferences for principles somewhere around year twenty, and I've been a better engineer — and a much better engineering leader — ever since.
If you're early in your career and you're passionately arguing about any of these things: good. It means you care. Just know that in ten or twenty years, you'll look back on these arguments the way I do — with a mix of fondness and mild embarrassment.
The code doesn't care about your formatting. It cares about whether it works.