Posted 2025-01-23
When I was working at Telegram a long time ago, some people joked that our team shipped without bugs. While that was impossible, it was still close to the truth. Over the years, I kept returning to this idea and compared it with the teams around me to determine if it’s a good mindset for a developer in a small team or startup.
Over the years, when I led or joined a team, I would say, “We write code without bugs.” Everyone would laugh, but then we would actually ship without bugs. Why is that?
If you search this topic online, you’ll find many people arguing that bugs aren’t a big deal and that you should focus on shipping features. On the other side, there are purists who want to cover 99.99% of the code with tests and verify that their code works all the time. The thing is, this isn’t a binary question — whether buggy software is acceptable or not — but rather a spectrum. Still, people prefer binary thinking, and there are very few nuanced discussions on this topic.
People on the purist side of things are usually obsessed with processes, not with making a product. Conversely, there are people with commitment issues; they want to experiment non-stop and thus have no faith in robustness. People in the middle typically don’t hold a strong opinion—they just try to be non-contrarian, unifying beings.
Over the years, both extremes have proven to be wrong, and the most important thing is that both tend to end up with very slow performance, high costs, low quality, and a high risk of burnout.
While the reason for the purists’ slowness is obvious, the slowness of the other side is less so. On that side, people keep shipping features and slamming them together, which quickly makes the codebase unmaintainable. How quickly? Within a few weeks, many parts can become so convoluted that you can’t isolate problematic areas to rewrite them—everything depends on everything else. Meanwhile, some “successful” experiments also turn out to be problematic: they’re neither robust nor scalable and eventually require a full rewrite, costing a lot of time and money and, more importantly, posing a risky move for the business and the team’s mental health.
You might think it’s possible to balance these two extremes: some people rapidly ship features, while others focus on making the product robust, scalable, and maintainable. In my experience, this never works for a simple reason: business people don’t usually care about the second group, and that group will feel they’re not really part of the company. You see this in big tech companies, too—nobody cares about fixing bugs because you only get rewarded for shipping new features. That’s probably why some Google apps are such a mess.
So what’s the way out? In my opinion, the only way is to write code “without bugs.”
A short story: I was almost kicked out of school for low performance in Russian language (even though I was excelling at programming). However, I managed to pass the exit exam and ended up as one of the best performers in the school. My “trick” during that final year was simple: I always tried to write correctly, not just when I was asked to, but all the time. After a year of subconscious improvements, I aced the exam.
I applied this same trick to engineering, and it worked. I can now write code that isn’t buggy. Sure, I might still struggle with leetcode-style problems, but I’ll just invest more time in them to ensure they’re robust.
If I would try to estimate quantitively - I would say that i am at 10% from the side of ship fast guys, it is not really that big of a deal for busness - slowness by a single day in a two weeks, while saving weeks, months and thousands of dollars, often starting from the very next week.
When I’m thinking about tech design decisions, I think a few steps ahead but not too far, i am thinking about ergonomics of developer. It may take minutes or even hours, but it’s a good investment. Sometimes, to bootstrap a project, I’ll spend a couple of days figuring out a solid initial approach. It won’t be permanent, but it’s a good starting point that I continue to refine in the same manner. Let’s say you have a project: you want to check that the compiler works, that tests can be written easily, and you discard anything that will slow you down (looking at you, React Server Components). Maybe you slap some CI onto it (it’s free now and often just a one-click setup). Some days, I’m obsessed with reducing development complexity. I have yet to see such obsession being waste of time - almost always projects started to slow down to halt and needed it anyway. Instead of hacking something together, I’ll spend a bit more time making it reliable and flexible. Sometimes it feels like overkill, but it’s much better than spending weeks later on a convoluted codebase that doesn’t work. I might wrap certain libraries in simpler interfaces so they can be used everywhere without adding too much complexity. Isolate code that changes every day from the one that wouldn't at all. Sorry for generic advices: it is all common knowledge, no secrets here.
Why being closer to the other side is bad then? Because it requires much more consciousness. You need to actually think how to write something, you will "study" how to write a better code - it would never became a subconscious skill. And subconscious skills are the best skills - they are the fastest, they cost nothing to you and they are improving even in your sleep.
In the end, this all becomes muscle memory. You’ll be able to write code that’s not buggy, yet still ship at a good speed without thinking when you shouldnt and thinking much more when you should.