DRY (or Don’t Repeat Yourself) was probably the first pearl of programming wisdom you learned when you began to explore software development. And, yes, it was also the worst advice ever.
We are taught not to repeat ourselves in order to explain procedures and the benefits of code reuse, which are numerous. DRY code (or code without duplication) is said to lead to faster development, easier maintenance, and a more secure and reliable system. And, there’s real truth to that.
So, why is DRY the worst piece of advice in software?
It’s such a simple and memorable mnemonic that it is easy to latch onto it as a rule. And, since it's a rule, it feels good to remove duplication, knowing beyond a doubt that you’re doing the right thing for your code.
But, the acronym doesn’t leave any room for nuance in the rule. It is all or nothing. Either you repeat yourself, or you don’t. Thing is, real software is never that simple. And, there are a couple important exceptions to the rule. Namely, you should:
- Favor clarity over de-duplication; and,
- Avoid premature abstraction.
Let's take a look at each...
Favoring clarity over de-duplication
Getting a computer to do what we want can be difficult. Writing software that clearly communicates what it is doing — through well chosen metaphors with well-named constructs — is much harder. And, conjuring tests that clearly express why the code works the way it does might be the hardest thing we do.
Clarity is hard. But, it is also critical. We need to be clear in order to ensure that the next developer in the code (who might be us, six months on) is able to understand our intentions.
As such, anything that obscures the what or the why should be eschewed, including DRY. If code with duplication is easier to understand than code without, then we should always favor the code with duplication.
This is particularly important in testing, where it may be better to duplicate setup in each test than to hide it in a
before block at the top of a long file, or (worse) in a separate shared spec file. Not only will it be easier to follow your intentions, but the output from your specs will be much easier to understand when they fail.
Avoiding premature abstraction
Equally important is to resist the urge to de-duplicate your code prematurely. Doing so leads to bad abstractions — ones that make the software more difficult to extend later.
What happens when you remove duplication before you have enough examples of what it should look like is that the next engineer, with a slightly different use case may decide to extend your code rather than unwinding it to find the real underlying abstraction. This results in the insertion of an
ifstatement in the code.
Of course, one
ifmight not be too bad. But, the next engineer after that might see it as a pattern and add an
else clause to the existing
if statement. Before long, you’ve got a mess, all because you listened to DRY.
For best results, allow for some moisture
DRY is a handy mnemonic. But, it doesn’t tell the whole story. It is perfectly healthy to leave your code moist in many situations. Here are a couple of handy mnemonics to help you remember that DRY doesn’t say it all:
- Write Expressive Tests (WET)
- Don't Abstract Me Prematurely (DAMP)
In other words, prefer WET tests and DAMP code over trying to be so DRY that your code chafes.
If you're interested in more on this topic, I recommend the following articles: