Something related that's been on my mind recently: a lot of the advantage in building well-designed programs (documented, modular, built to be tested, free of smells, etc.) is less about getting the program right than about getting future changes right, either by someone else, or even yourself when you've forgotten how to do it. But future changes only matter if you want to use the existing program as a starting point.

McIlroy's pipeline is a little bit hard to read, but I would bet that most people with moderate experience in building shell pipelines could rebuild something equivalent from scratch, even if they'd have trouble explaining how the current pipeline works. (Or people with experience in Python, Perl, etc. could throw together an equivalent script from scratch quickly.)

An implication is that, if you're in a language where you can write a productive program to do a task from scratch within (say) 30 minutes, there's a lot less of a reason to think about good programming design than if you're in a language where doing that same task from scratch is likely to take you a day. In the second language, most of the value of writing documented and well-structured code is so that it takes you 30 minutes when someone asks you to modify it. But in the first language, you can throw away your code when you're done with it and still solve the modified problem within 30 minutes.

Another possible implication: it's better to build reusable components (libraries and utilities) than easily-modifiable code. Part of why McIlroy's pipeline works so well is that tools like "tr" and "uniq" exist - and most of us will never have reason to modify the source code of those tools. We need to know what their interfaces are, but we don't need to know their internals.

This comment reminds me of something of a thought-experiment-come-hacky-side-project that I can’t seem to find.

The premise was, what if you could never edit a function? Instead, you had to delete it and recreate it entirely whenever changes were needed.

The incentives are twofold - keep functions small, so you don’t lose too much investment if you have to delete code, and think before you start writing, else you waste time.

As I remember, this project came with an AST manipulator that would helpfully delete your function if it’s unit tests failed.