Superficially, "Don't write bugs" really only translates to "don't be sloppy, if you're aware of ways that your code will fail in edge cases, handle those edge cases. Develop techniques and habits that will avoid bugs, like better encapsulation."
However, "Don't write bugs" is a joke for a seasoned programmer who's had to work with political constraints. Bugs often arise from major design flaws that can't be fixed in an afternoon. Other bugs arise from management compromises to meet a deadline or price point. Even worse, some bugs arise from problems with external APIs that are completely out of a programmer's control. At this point, "don't write bugs" can really only translate to trying to defend against corner cases that are impractical to fix.
"Impractical to fix," meaning, fixing the bug requires navigating politics. This could be working with a vendor to fix a broken API. It could also be working with management to allocate time to refactor a defective design.
Also: There are poor programmers who just can't "Don't write bugs." They can't think through edge cases; or a fundamentally incapable of understanding edge cases that lead to bugs. (And handling these kind of programmers is a different topic altogether.)
"Impractical to fix" can also mean writing an awful lot of complicated code to work around edge conditions that may never arise in reality. And the cost of writing that complicated code may result in additional bugs you didn't foresee due to the law of unintended consequences.
It becomes a tradeoff between the bug that you think you're smart enough to see but which may never happen, and the bugs that you're not able to see right now.
And I've definitely been on the wrong side of that equation and dealt with overly complicated code considering edge cases that were not useful, which caused complicated but practical bugs which affected many customers -- and I wound up replacing the overly thought out code with simpler code that was understandable and the "bug" I reintroduced never affected anyone AFAIK years later.
I've also been on the right side of that equation and picked simpler approaches and never had the overly complicated edge conditions that I could "see" in the code actually crop up and affect anything.
It isn't just political, sometimes you really can just technically outsmart yourself.
Plus there's the issue of if design decisions that are 10 years old should be refactored at the cost of introducing breaking changes and pain on everyone using your software. Sometimes you wind up writing some less-robust-than-ideal code which is due to those kinds of foundational issues. And the existence of a single difficult to fix bug is generally not sufficient to restort to blowing up your entire world and starting over again.
I worked with a developer who claimed, with a straight face, that he wrote bug-free code. When I pointed out places where the code would not behave as desired, his usual reaction was to assert that the input was invalid or would never happen, or that the problem was that some other service or code did the wrong thing.
So, while I understand your point about not "gold plating" code and being stuck solving problems of your own making, there really is a limit to how much code can pretend like failures don't happen and inputs can be other than what is expected. Failing to validate inputs from users is a well-known cause of many security problems, for example.
You have greatly misunderstood my point. I'm pointing out that sometimes the cure can be worse than the disease.
Failing to validate inputs is fairly trivial and not what I'm talking about.
And I'm not talking about defending my own code as perfect or any kind of egocentric nonsense like that.
I'm talking about reviewing other people's code that I have a difficult time understanding due to a large amount of conditional logic for edge conditions which have never been reported as bugs before. I've accepted that code and then experienced it blowing up really horribly. It also just isn't clear that its better to solve bugs that nobody will ever hit at the cost to clarity and future maintenance and future bugs which people actually hit.
I'd rather people write "buggier" simpler code if the bugs that are mitigated aren't practical. And what I'm talking about here is the "undefined compiler behavior" grey areas of APIs. Those would of course be better never having been created in the first place and everyone should have done excellent design and input validation to start, but that never happens perfectly (because eventually shipping code takes precedence over perfection) and 10 years later you've got a job to do.
And the TL;DR there is that people can actually outsmart themselves trying to think of every edge condition under the sun, and I've watched that happen to other people and had to mop up the fallout.
Sometimes the edge condition will also simply take too long. Mitigating a bug that has been in the codebase for 10 years, has never been reported, and is unlikely to be reported in the next 10 years is not going to be terribly useful if it takes the next 3 months of your time because of how deeply buried in the design the bug is. That is a good one to make a note of and if it starts to surface as a problem you've then had time to think about strategies that might take it down to 1 month or less.
Please do validate all your inputs and write robust code against all the edge conditions you can think of when you're greenfielding though, it will make things easier later. At the same time if you argue that you're shipping flawlessly perfectly designed code I bet that's a lie.
Oh, I've also ripped out 60% of a codebase that was just horribly overdesigned as well, and was solving problems that the author wanted to teach themselves things that weren't actually relevant to the problemspace.
+1. "Don't write bugs" is pretty much the 4Head response to a programmer asking "How do I not write buggy code?"
> if you're aware of ways that your code will fail in edge cases, handle those edge cases.
Another key point I want to add is that for every method you write, you should carefully audit the domain of your input and only accept information necessary for your method to work. That way you don't handle edge cases not relevant to your method. The exception probably here is critical edge cases that will SIGSEV, SIGILL, etc and kill your whole process. You usually want to check those - and if you are having to do that frequently that's code smell.
However, "Don't write bugs" is a joke for a seasoned programmer who's had to work with political constraints. Bugs often arise from major design flaws that can't be fixed in an afternoon. Other bugs arise from management compromises to meet a deadline or price point. Even worse, some bugs arise from problems with external APIs that are completely out of a programmer's control. At this point, "don't write bugs" can really only translate to trying to defend against corner cases that are impractical to fix.
"Impractical to fix," meaning, fixing the bug requires navigating politics. This could be working with a vendor to fix a broken API. It could also be working with management to allocate time to refactor a defective design.
Also: There are poor programmers who just can't "Don't write bugs." They can't think through edge cases; or a fundamentally incapable of understanding edge cases that lead to bugs. (And handling these kind of programmers is a different topic altogether.)