"DRY—Don’t Repeat Yourself
Every piece of knowledge must have a single, unambiguous, authoritative representation within a system."
Always good to revisit original phrasings of things. I think the catchiness of the lower-information acronym did this one a disservice. I find myself explaining with some regularity that repetition of code is not necessarily repetition of ideas, and if I have `f(x, g(y), h(z))` both here and there but for different reasons then it's introducing artificial coupling to break it out into a single function. The focus, in the longer expression, on knowledge is exactly right. DRY isn't a call for "Huffman coding".
I like DRY and generally I'm the sort of person who's always spinning off chunks of code into their own functions, classes, modules, etc. and almost always hating anywhere I have duplicated code.
That said, I think DRY can sometimes lead people astray. One problem is that the boiled down concept of "DRY" has nothing to say about quality. Reusing bad code can often be much, much worse than the alternative. Sometimes it's critical to "sunset" code that is "working" because it's not good code, and it would take too much to make it good. Then tie any new attempt to reuse that functionality to an effort to create a better replacement. If instead people think "oh hey, this exists already and it sorta works, whelp, better be DRY!" then they can turn a small problem of bad code into a big problem of horrible code that becomes even less maintainable and more of an effort sink as it acquires little patches and fixes to add support to all the new stuff using it, and as it becomes more and more indispensable and costly to replace. Whereas if the first person deciding to be aggressively DRY had looked at the code and instead said "this is garbage, I'm writing my own better thing" then maybe everyone else coming along later would have ended up using the better replacement and over time it would have become trivial to migrate the one usage of the original to the better version.
The mental model I've started to adopt is instead one around "littering". Basically: don't create garbage code, and don't use it. Garbage code is code that has future cleanup inherently attached to it. Repeated code can be garbage code because there's inherently either deduplication work or duplication of fixing/redesign/adaptation work attached to it, it's basically like littering in the code base. But by the same token you don't solve that problem by finding a use for garbage, you still have future cleanup and bug fixing work attached to the code, only now it's worse because it has different use cases to support and higher consequences if it breaks.
Your points about garbage code are interesting, and I think there's much to be said for that strategy.
Regarding your first sentence, you should be frequently spinning off chunks of code, but you should be careful that you're not adding coupling where it doesn't exist in the domain.
Again, I like the knowledge formulation of DRY.
"This is the way we render a FOO" is one piece of knowledge, and shouldn't be repeated every time you try to render a FOO.
"There should be a FOO rendered here" is one piece of knowledge, and shouldn't be repeated at multiple layers in your stack.
Now... what if we've been good about the above, but there's some similar code in "how we render a FOO" and "how we render a BAR"?
If the code is similar because we want a consistent style across FOO and BAR, then "we want such-and-such a style" is a piece of knowledge, and it should be represented in one place!
If the code is similar, but only coincidentally, and either might change in any direction tomorrow, then there's a question: "Is it a coherent abstraction?" We want abstractions such that we can give them a clear name, such that when we make a change to how we render only FOO or BAR we'll be obviously moving to a new abstraction and won't be tempted to change the function, and such that we know to reach for this function when it's applicable in a new context.
Alternatively, is it just a gathering of a particular grab bag of functionality? If you're pulling that out, you're not improving your code - you're compressing it.
I think that agrees very much with my comment, but is sort of orthogonal to the comment above - which I think would recommend reimplementing even the right abstraction if the existing implementation is sufficiently poor.
One way I've always heard it referred to is: refactor the code so your task is easy to do. If making a new abstraction does that (just had this happen last week for me) then so be it.
I think that is incomplete. One should be aware of what other tasks a refactor is making more difficult or more error prone; it is not purely a matter of whether it makes the current task easy.
Always good to revisit original phrasings of things. I think the catchiness of the lower-information acronym did this one a disservice. I find myself explaining with some regularity that repetition of code is not necessarily repetition of ideas, and if I have `f(x, g(y), h(z))` both here and there but for different reasons then it's introducing artificial coupling to break it out into a single function. The focus, in the longer expression, on knowledge is exactly right. DRY isn't a call for "Huffman coding".