The “don’t repeat yourself” principle is well established, but over-aggressive refactorizarions to extract common code are also widely known for creating hard to maintain code due to the introduction of tight coupling between components that should not be coupled. A passing resemblance between code blocks is reason enough to extract them away, even if that ends up breaking Liskov’s substitution principle.
To mitigate problems caused by DRY fundamentalisms, the “write everything twice” (WET) principle was coined. WET works by postponing aggressive refactorizarions, the kind that introduces complexity and couples unrelated code just because it bears some resemblance, by creating a rule of thumb where similar code blocks showing up twice in the code should not be refactored, and only code that shows up multiple times should be considered for this task. However, this rule ignores context and nuances, and can dissuade developers from cleaning up code.
So, where do you stand on the topic? How do you deal with duplicate code? Do you follow any specific rule of thumb?
I don’t think DRY or WET or the “rule of 3” can address the nuances of some abstractions. I think most of the times when I decide to abstract something, it’s not because the code looks repetitive, but because I’ve decomposed the architecture into components with specific responsibilities that work well together.
In other words, I don’t abstract from the bottom up, looking at repetitive code. I abstract from the top down, considering what capabilities are required from a system and decomposing the system to deliver those capabilities.
Of course, repetitive code might be a smell, suggesting that there is room for abstraction, but I don’t design the abstraction based (entirely) on the existing code.