Bart knows how to apply the DRY principle. Be like Bart.
“Don’t repeat yourself”. Every respectful developer learns this mantra very early in her career.
The common understanding of this principle is that you should not duplicate your code. Simple as that.
Do not replicate a pattern. If you find a duplicated one, refactor.
Violations of this rule will immediately be pointed out by other developers as an infringement of one of the most fundamental practices of software development.
Well, let me be honest on this one. This approach is completely wrong. One single, huge, unfortunate misinterpretation is making the life of many developers a lot harder.
Let me explain why.
Do you know the original definition of the DRY principle?
We took a very good insight about knowledge management and consistency, and turned it into code nonsense.
Even Wikipedia is dangerously awkward on defining DRY. Just check the DRY vs WET solutions paragraph. I don’t even know what has it to do with such principle.
DRY, as commonly interpreted, hurts your codebase by tightly coupling together completely unrelated parts of your code. It’s amazing how it naturally introduces unnecessary, accidental complexity.
Shared kernels or libraries, evergrowing Util namespaces (we all have one), inheritance trees. All in the name of an irrational need to avoid writing two similar pieces of code.
We took a very good insight about knowledge management and consistency, and turned it into code nonsense.
But there is a solution.
Now let me tell you why duplicating by default brings considerable advantages to your code.
Duplication allows for delayed decisions. And that’s gold in software development.
It’s ten times easier to refactor later from multiple specializations to a single abstraction than the other way around.
Our brain works just better in the former direction. Going backwards takes creative effort and significant cognitive load. Even lateral thinking, in the worst cases.
By applying DRY upfront, you’re building an abstraction that doesn’t exist in your domain. And you’re building it for the sake of grouping together a partial functionality that only apparently looks the same between different classes.
Similar classes are similar, they are not the same thing. They don’t serve the same purpose. They don’t run on the same use case.
You need to learn to be comfortable with literally copy/pasting whole classes and only change their namespace.
I even duplicate value objects across different modules. Here’s an example:
Different parts of the codebase. Different use cases. Different interfaces.
So different, separated, unrelated classes.
There is a high chance that two identical classes in different namespaces will diverge very soon in the future, even if at first they look exactly the same.
When you anticipate the coupling, you miss this diversification opportunity and cripple your model.
Refactoring toward an abstraction should be only done when complexity becomes unmanageable or your model explicitly calls for it. Doing it preventively will only harm your code and introduce tons of accidental complexity.
You would be surprised by how many times your brain tricks you in thinking everything will be a mess if you don’t apply DRY.
You are so used to the practice that when you give up on it you are positively but genuinely surprised that everything works perfectly.
You won’t touch duplicated code again and duplication itself will be the last of your problems in the codebase.
It’s a mindset change, it requires time. Take yours, be patient.
Fight the need for sharing code among different classes.
You don’t need a custom shared library for manipulating collections of objects (PHP devs, I’m looking at you).
Replicate every pattern because the next time you will need it, it just won’t be for the same use case as before. A similar one, maybe, but not the same.
After you switch to this duplication mindset, that one rare time when something actually needs to be kept in one single place instead of being duplicated you will know it. You will feel it.
Only in that moment you will start abstracting toward a different model. You will see consistency boundaries that will kindly suggest whether to keep things together or not.
This is the true DRY you are looking for.