An abstraction appears when repetitions have exposed a shared axis of change — not by counting copies. The first duplication is cheaper than the wrong abstraction: the wrong abstraction forces every future case to lie about its nature. “On the third repetition” is a mnemonic: by the third time the axis is usually visible.
YAGNI — You Aren’t Gonna Need It — reads literally: don’t write code nobody needs today. Not a “might as well” function, not a “just in case” parameter, not a factory for a single implementation. The cost isn’t the lines: from day one this code demands reading, tests, and edits in every refactoring — and it tells the reader about an axis of change that doesn’t exist. A practical test: if you can’t name a second case already present in the code, there is no second case. “We’ll probably need it” in practice means “we won’t, and if we do, it will take a different shape.”
What this looks like with OCP. An interface plus a factory instead of an if on type is the canonical “extend with new code, don’t modify old code” (1): a new variant is added as an implementation, old code stays untouched. That exact construction is the textbook YAGNI violation while there is only one implementation: three entities instead of one branch, for an axis of change nobody has proven. The order is the reverse of the habitual one — first the second and third repetition, then the abstraction; OCP is applied to an axis that has already shown itself, not to a predicted one.