OnceAndOnlyOnce is often not practical. Sometimes the duplication is purely coincidental, for example, and factoring may just be a waste of time if the two things drift apart again. Thus in practice there is a repeat quantity limit that triggers one to seek duplication fixes. Every developer or shop has some level (formal or informal), it just varies widely.
For example, a DuplicationRefactoringThreshold of 4 means that you wait until you see a concept duplicated 4 times before you bother to refactor it. Even the worst of shops will start to factor if they see large chunks of code repeated say 100 times. One would say they have a high refactoring threshold.
Strikes me as exactly the same issue as repeated values in a relational table not necessarily violating normal forms. It's the functional dependencies that matter.
This doesn't by itself handle the cases like "this window here does the same thing for foos as this other one does for bars". But then again, that's what DoTheSimplestThingThatCouldPossiblyWork is for: if it is possible to use the same window for both, then that is (at least a candidate for) the simplest thing.
Then again, perhaps 'functional dependency' would include that example as a case of 'doing the same thing', in the sense of 'the meaning of the one operation is tied to the meaning of the other'. Dunno.
Re: "Strikes me as exactly the same issue as repeated values in a relational table not necessarily violating normal forms. It's the functional dependencies that matter."
You mean like 500 people in a People table having the same favorite color of "blue"?
I don't see any way around that. They can all point to "blue" instead of store it, but that might save a few bytes at best. It is almost like saying all the "print" or "output" statements in a large program is duplication. Other than shortening the function or method name, it is hard to factor more compactly. Some "things" are simply popular and are used/referenced a lot. It is generally considered only a violation of OnceAndOnlyOnce if it is larger or more complex.
In other words, they have a too-low DuplicationRefactoringThreshold. OnceAndOnlyOnce is a beautiful thing when it's done properly, but you need to have a sufficiently high threshold to know how to do it properly in any given case.
Print is a perfect example of what not to factor, because anything which depends on the fact that we're printing is factored into the print method. (cwillu)
Why do the log kits (like log4j) exist then? I believe that they are refactoring the "print" logic. I feel like the choice where to refactor or not is very difficult. I think that is another sign that ProgrammingIsArt. (feel free to refactor, move, delete, etc. But please keep the meaning, AurelianoCalvo).
Logging is a rather specialized form of printing. Unless your application is dedicated to be run as a one-shot command-line tool, you probably don't want your log output spewed to stdout or wherever print outputs to by default. You want to be able to choose what KIND of data you want logged, and WHERE you want it logged. In my own experience, when I started writing if(verboseLevel > 3) output(x) I realized it was time to get a smarter logging system. (ahigerd)
If I see two methods, each 200 lines long. Three strikes? No, I extract one method. :-)
The chances of both being identical in usage is small in my observation. Managing the differences can be no small chore. Related: VariationsTendTowardCartesianProduct. If multiple things are "kind of the same" but have nitty little differences, which is very common in my domain, perhaps it's time to split up the parts that are the same from the parts that are not. In other words, change the granularity of your refactoring. I often get better reuse when I refactor "in the small".