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?
Welcome to the main community in programming.dev! Feel free to post anything relating to programming here!
Cross posting is strongly encouraged in the instance. If you feel your post or another person’s post makes sense in another community cross post into it.
Hope you enjoy the instance!
Follow the wormhole through a path of communities !webdev@programming.dev
I tend to go with WET and I read one or two articles that introduced WET and explained one of the missunderstandings of DRY: It is about sharing knowledge and less about sharing code. Therefore as me tioned by another poster: it makes sense for business logic but less so fir everything else.
I’ve never heard of WET, but that is exactly the process I preach to my team. Refactor only once the same code block is used 3+ times as that tends to define a method that is a utility and not business logic specific.
This method has worked well in the past.
To expand on that: dry should only be considered for business logic anyway. Wet for everything else sounds great!
I agree with WET. We have a tendency to over-complicate things, sometimes you gotta take a breath and ask yourself if the refactor is actually worth it.
I just move any duplicate code into a function, no issues yet. (In face, fixing a single bug often ends up fixing multiple problems)
I can very much recommend taking a look at the AHA principle. Kent C dodds has a short and good presentation on it. That’s what i go by these days
Important/generalized patterns reveal themselves over time. I generally push for people to just write the specific thing they need for the given context and then if the same pattern shows up elsewhere, promote the code to a shared library. It’s really hard to anticipate the correct abstraction right from the start, and it’s easy to include a bunch of “just in case” parameterization that bloats the interface and adds a lot of conceptual overhead.
That being said, with low-leverage/complexity code like html views, repetition isn’t as problematic. Although, I do think that HTML components have matured enough to be the correct unit of abstraction, not CSS classes.
What does the code represent? What does it concern?
Focusing on the code and pattern too much may mislead. My thinking is primarily on composition and concern. The rest follows intuitively - fee with risk, gain, and effort assessment.
I’ve had occasional instances where code duplication is fine or not worth to fix/factor. But I feel like most of the time distinct concerns are easy and often important to factor.
found the german.
Lol, I guess I habe wrote it on mobile with autocorrect 🙃
I liked this talk on the subject: https://www.deconstructconf.com/2019/dan-abramov-the-wet-codebase
It’s a nice explanation of how it’s less about code that looks the same or currently performs the same operations, and more about what it means.
If the only difference between two classes or structs is hard coded config, rewrite to be a single implementation and pass the configs in.
If it’s more in depth than that it may not be worth refactoring but future copies should be designed more generically.
Of course functions still shouldn’t do more than one or two things. Hence they don’t get too complex.
And yeah, duplicates to avoid thight coupling (if still needed) are fine, if kept in moderation.
It depends on how much regression testing is in place to test that old and refactored code behaviours have the same outputs, and how much budget there is for writing this tests.
For old financial systems for example, the answer is often to repeat the code again, as there’s likely to be little tests to confirm existing behaviour and writing tests around very complex business domains is prohibitively expensive.
WET/DRY-ness is like a property of code – a metric or smell perhaps, but not something to goal towards. That’s like asking whether you drive fast or slow and whether we should all drive faster or slower.
I call this my “rule of three” - I wait until I’ve seen “something” three times before deciding on an abstraction. Two isn’t enough to get an idea of all the potential angles, and if you don’t touch it a third time, it’s probably not important enough to warrant the effort and risk of a refactor
I prefer the FP approach where I create smaller functions that I compose together in larger functions or methods wich rarely repeat themselves elsewhere identically. Forcing extractions and merging of such functions often leads to weird code acrobatics.