The server went down on a Tuesday afternoon in October, and I remember the specific quality of silence that followed — the kind where everyone in the room is waiting to see if you'll fix it or cry. I was twenty-six, freshly promoted to what my employer generously called "lead developer" at a small content agency, and I had just discovered that our production database had no backup more recent than eleven months old. Eleven months. I had set up the backup job myself, watched it run once, and then never verified it again. The cron task had quietly failed sometime in late November of the previous year, and I had been blissfully, catastrophically unaware.
That afternoon taught me something I've been turning over ever since: the worst tech decisions I made were rarely dramatic. They weren't bold gambles that blew up spectacularly. They were acts of assumption — moments where I decided that something was probably fine and moved on.
The Backup That Wasn't, and the Confidence That Was
Let me stay with that database for a moment, because it deserves the scrutiny I failed to give it at the time. The failure wasn't technical in any interesting sense. The cron job broke because a file path changed during a routine server migration, and nobody — including me — thought to run a post-migration checklist. We restored from what we had, lost nearly a year of incremental client data, and spent three weeks in apologetic phone calls.
What I carried away wasn't just "set up monitoring for your backups," though I did that, obsessively, for the next decade. What I carried away was a sharper understanding of how confidence becomes a liability. I had set up the backup. I had watched it succeed. In my mind, the problem was solved, filed, done. The system had become invisible to me precisely because I trusted it — and invisible systems are where the worst failures hide.
There's a particular kind of tech hubris that affects people who are good enough to build something that works once. It's not arrogance exactly. It's more like a premature sense of closure. You close the ticket. You move on. And somewhere in the background, the thing you built is quietly changing shape.
Betting on a Framework Nobody Else Would
A few years later, I made a different kind of mistake — one with a longer fuse.
It was 2013, and I was freelancing, picking up web projects wherever I could find them. A client needed a content management system for a mid-sized editorial operation, something with a clean API and a flexible templating layer. I had been experimenting with a framework that a small but vocal community had been evangelizing on the forums I frequented. The documentation was thin but enthusiastic. The GitHub stars were climbing. I was convinced I was getting in early on something important.
I built the whole project on it. Took me three months. The client was happy. I was proud.
Eighteen months later, the lead maintainer announced he was stepping away for personal reasons, and the project entered what open-source communities euphemistically call "maintenance mode." What they mean is: nobody is fixing anything. By 2016 the client needed a significant feature update, and I had to tell them that the foundation their editorial system was built on had essentially stopped existing. We migrated everything to a more established platform over the course of two painful months.
The lesson I resisted learning was this: community size is not vanity — it's infrastructure. A framework's GitHub stars matter less than its bus factor, its corporate backing, its age. I had chosen novelty over durability, and I had made that choice on behalf of someone else.
The Tool I Adopted to Avoid Learning the Right Thing
Somewhere in the middle of all this, I developed a habit that I'm only now fully willing to name.
Whenever I encountered a problem that required learning something genuinely difficult — a new paradigm, a concept I'd have to sit with for weeks before it clicked — I would find a tool that abstracted it away. This isn't inherently wrong. Abstraction is how software development scales. But I was using abstraction as avoidance, and the difference matters enormously.
The clearest example: I spent almost two years working with databases through ORMs without ever properly understanding the query layer underneath. I knew enough to get things done. I could ship features. But I couldn't diagnose a slow query without running it through a GUI tool and hoping the visual explanation was enough. When a client's application started crawling under load, I was useless at the level where the actual problem lived.
I eventually learned SQL the hard way — by needing it desperately, at speed, with someone waiting. That's the worst classroom, and I had enrolled myself in it through years of comfortable avoidance.
The worst tech decisions I made often had this shape: choose the shortcut, defer the understanding, and then discover that the understanding was the whole point.
Scaling for a Future That Never Arrived
There's one more decision I want to confess, because it cost more than time.
In 2018 I was consulting for a startup — two founders, a handful of early users, a promising idea. They asked me to help architect their backend. I was deep in a phase of reading about distributed systems, event-driven architecture, microservices. I was genuinely excited about these ideas. And I let that excitement run ahead of what the project actually needed.
I built them something elegant and overengineered. Multiple services. An event bus. Separate deployment pipelines. The kind of architecture that makes for a compelling conference talk and a miserable Monday morning when one of two engineers has to debug why an event isn't propagating between services.
They scaled down six months later, one of the founders left, and the remaining engineer — who was not a backend specialist — was left maintaining a system that required three mental models just to understand how a user registration worked.
I had optimized for a scale they never reached, and in doing so I had made their present harder in service of a future that never arrived. The right call would have been a boring monolith that a single person could hold in their head. Boring is underrated. Boring survives.
What I Actually Learned, Years Later
I've been thinking about all of this because a friend recently asked me for advice on a tech stack choice for his new project. He wanted to know what I'd recommend. What I told him was: pick the thing with the longest paper trail, verify everything that runs unattended, and don't build for the version of your project that exists only in your optimistic imagination.
He looked slightly disappointed. I think he wanted permission to use something new and interesting.
I understand the impulse. I have lived inside it for most of my working life. The new thing is exciting in a way that the established thing simply cannot be. The new thing feels like a bet on the future, and nobody wants to feel like they're betting on the past.
But the worst tech decisions I made were almost always dressed up as bets on the future. They wore the language of innovation, of getting in early, of building for scale. What they actually were, most of the time, was a failure of patience — an unwillingness to sit with the slower, harder, less glamorous option long enough to see why it had survived.
The database is backed up now. I check the logs every morning. It's not interesting work. It's the best habit I have.