This is by far the most insidious problem as you can't just wrap duplicated code up into a function and move all the code to one place.
Usually this problem appears not just as functionality duplicated in many places but each time the functionality is also intertwined with other features and cannot be decomposed to get rid of the duplication.
In most styles of programming there is no way to get around this issue as it has to do with program "design." Unless you can make a design that anticipates the duplication, likely a duplication is inevitable.
However, if you make your variables immutable as much as possible you can get around this issue and solve what was seemingly a "design" problem but was in fact only a problem with mutable variables. It's too bad the majority of programmers don't know about this.
Something that doesn't occur often enough, but should: then rewrite the function for various optimizations - speed, size, security, whatever, while ensuring the same input will always produce the same output.
It's more than just side effects. A common design issue people hit is that midway through a projects lifetime they hit a feature request that is basically a slight permutation of an existing feature.
They realize that they cannot reuse the code because of the way they "designed" the program. Ideally you want to reuse existing code, or if no function specifically supports this feature you can encapsulate a relevant line of code into some sort of container so that it can be reused in multiple places. This is a way of decomposing your code, or aka: dividing a function into multiple pieces so components can be deployed in multitudes of other location thereby maximizing code re-use.
What happens is that most people realize that no matter how much they plan out a design they cannot execute the decomposition procedure above. A design choice made at the inception of the project fixes the shape of the code and limits flexibility. Thus they do code duplication as a workaround hack.
I am saying that this problem is actually caused by mutability.
What is seemingly a structural problem only occurs because you have a mutable variable. You can cut your code and divide a primitive into a thousand possible pieces if you wanted too but the minute you have a mutable variable in your code the division cannot be done.
Think about it. To surgically remove a mutable variable out of a piece of code you must not just cut out the variable but you must also bring every function or procedure that mutates that variable along for the ride. If your function has an entire network of functions mutating procedures than that function cannot be divided into smaller functions.
An immutable function can be cut into a thousand pieces and rebuilt in a different way. This is the best known solution for program design and organization.
Code duplication is one of the biggest mistakes I made as a new developer. As you became a better engineer, you learn how to simplify and extract common patterns into shared classes/libraries/components to avoid duplication. Code duplication is almost a cardinal sin due to the complexity and bugs that tend to result.
With this rule duplicates rarely happen anywhere but in utility functions that extend the standard library.
It's similar to KISS. Yes I get why simplicity is great but it doesn't mean it's universally great. Is this acronym telling me to follow some random principle because the acronym forms a word? Many Complex systems exist in the world as an antithesis to KISS, so this principle isn't universal at all.
Why not stop duplication in ALL cases? What is the statistical evidence or logical proof that justifies "three?"
I stick with the Rule of Three as a rule of thumb, and it seems that the repeated logic diverges about as often as it converges.
Once you start thinking about a third implementation, it's time to put the logic in one place.
I’m not sure why you can’t just say, “Deduplication is often good, but use your own judgement.” I guess it’s not as catchy?