Like, if you saw Http.getClient(...).doGetRequest(...) a few times, it wouldn't be worth pulling them out into a myGetRequest(...) method. Your teammates already understand the existing, repeated statements, but they haven't seen myGetRequest(...) before, so you wouldn't be making the code any more readable to them.
But if you had Http.getClient("auth.myservice.com:8443").doGetRequest(...) in a few places, then I would pull out the host and port (or maybe the whole line), since it contains knowledge of where/how to authenticate.
Coming from the other direction: if I were reading the code, I can imagine myself looking for the one place where the auth happens, but I can't imagine myself needing to know the one place where Get requests happen (even if the 'Get' code is repeated much more than the 'auth' code)
One concrete example: If your software has to create really complex objects, would you rather describe _how_ to create those objects in 10 places or one place? That's a scenario where you don't want to repeat yourself.
Dan Abramov [wrote about](https://overreacted.io/goodbye-clean-code/) this (linked in the OP), but in his example he's removing repetitive code. He's not removing multiple copies of the _knowledge_ about what the program is supposed to do.
It's a subtle difference that seems more difficult to describe than I'd like, but it's an important one.
It's a bit difficult to get across in text, but the minimum number of repetitions of a piece of code to make it "worth" putting it in a function is... 1. (According to me, and Tony van Eerd of Postmodern C++ fame. I had come to this conclusion on my own, but his talk really articulated it well.)
It's all about limiting the scope of side-effects, accidental reuse or variables, etc. etc. such that a human can do chunking to understand the whole.
I generally find that this is not an easy thing to capture in "metrics" or "rules". Guidelines with reasonable rationales, etc. etc. and when-not-to's, definitely, but that's a really hard thing to do and it doesn't get many clicks.
EDIT: ... and just to get back to DRY. The acronym is far too absolutist, but Try-Not-To-Repeat-Yourself-Too-Much-Unless-You-Have-Good-Reason-To isn't quite as catchy, is it?
So for example, documentation (truths about the code) should derive from the code (eg by doc generation). Otherwise the docs & code will drift apart. Or if you're passing domain information across the wire between client & server, you should derive the data structures at both ends from a common source.
I don't get it. Code /IS/ knowledge and whenever I copy-paste code around, I duplicate not only code but also knowledge.
So you have an API that belongs to this project. When you change it, do so in one place, and then run your doc generator rather than change it in both function/method signatures and docs.
Or you have domain knowledge embedded in classes, and a wire protocol between peers or client & servers using different languages. Derive the data structures in the two different languages from common source (either one of the languages, or both from metadata).
I think the distinction between this kind of project-specific 'knowledge' and more abstract 'everything is knowledge' issues is clear enough in practice. But it is just a rule of thumb rather than a deep philosophical principle, and like all such will break down in individual cases.
whenever I copy-paste code around
But that's just one source of code duplication. Another might be (for example) duplicated code deriving from code generation. DRY might advocate this (as there's a clear canonical source of knowledge), whereas a generic rule against all 'duplication' wouldn't.
In that case, there is not a single piece of knowledge being duplicated, but rather two separate pieces of knowledge being possibly unified.
More that it's a guideline, not a law. We should always use best judgement to decide when the tradeoff of readability and declarative code is worth a small amount of repetition, rather than religiously refactoring something for the sake of it.