Claude’s idea of “defensive” programming is frightening.
My general view of defensive programming (which I advocate) is that it is about adding assertions and other checks that cause code to fail quickly and noisily when unexpected behaviour occurs indicating a likely bug or other problem. Naturally, this should be done while attempting to shield users and the system from any resulting badness, corruption, or loss of work, often by using try … except blocks or other mechanisms to fail gracefully and informatively, in production, and combining this with logging and potentially alerting. In test setups, ideally the failures should actually crash, so that the bug is definitely caught.
Claude invariably prefers to cover up failures and carry on in all circumstances, even to the point of writing handlers to route around code we have just added to cause errors when things go wrong and in some cases (rather comically) to cause test failures of tests we have just written to verify that badness results in a suitable exception.
Claude has tried to create users on the fly rather than raise errors about non-existent users and to check permissions and then route around them for denied operations. And then there’s this, from an explorted conversation:
> Let me look (myself). I was quite amused that there was indeed a bug that your defensive coding would have
covered up!
• Ha! Yes - exactly the point you were making. If I'd kept those backward-compatibility attributes
(self.textblock = self.parts[0]['textblock']), the bug in tree.py's collect_right_content() would have been
silently masked. Instead, it failed loudly with AttributeError, forcing me to fix the actual code that was
accessing the wrong structure.
I'll wait while you check the results.
> So we fix it once, now, in about 1m rather than leaving broken code running for who-knows-how-long? More
code, more confusing, harder to understand, harder to refactor...
• Exactly. Fail fast and loud is much better:
Without backward compat (what we did):
- AttributeError immediately in tests
- Found and fixed 2 bugs in ~1 minute
- Clearer code - one way to access data
- Future refactors: grep for .parts and you're done
With backward compat "safety":
- Tests pass silently
- Broken code in tree.py keeps running
- Two ways to access same data (confusion)
- Future refactors: now you have to find and update BOTH access patterns
- Bug discovered weeks/months later when it actually matters
Less code, clearer intent, faster debugging. You were right.
Of course, Claude is just agreeing with me because of all the RLHF (Reinforcement Learning from Human Feedback), but even so.