You've seen the developer. Maybe you are the developer.
They discover DRY — ✨ Don't Repeat Yourself ✨ — and something switches in their brain. A p...
For further actions, you may consider blocking this person and/or reporting abuse
Thanks for this balanced perspective. One aspect I'd like to add is that unifying implementation doesn't necessarily mean to also unify the API. For the name formatting example you could do:
Avoids duplication and is still easy to change, e.g.:
Usually it's not all or nothing. I think it's often best to try find a middle ground - avoiding duplication of logic as much as reasonable possible without trying to create the ultimate abstraction.
Yeah I get what you mean, and I think that’s the healthy version of DRY most people eventually land on.
The problem usually isn’t sharing code, it’s when we start forcing shared structure where only part of it is actually shared. That’s when APIs get split from implementations and everything starts feeling indirect.
Your example is actually a good one because it keeps the API clear while still reusing the core logic. That’s the sweet spot.
Where I usually get cautious is when it starts looking like this:
At first it looks fine, but then every domain starts bending around this generic “getEntities” shape, and suddenly the abstraction is dictating how features are expressed instead of the other way around.
I’m fine with reuse when it’s just “this is the same logic, let’s not duplicate it.” But I try to avoid turning that into a framework layer unless I’ve actually seen the differences emerge in practice.
Great read - a thoughtful reminder that sometimes intentional duplication improves clarity and reduces risky coupling. The practical examples made the trade-offs clear; thanks for challenging the DRY-first mindset.
Appreciate that ⭐️
Yeah that’s pretty much it — once you’ve been burned a couple times by “smart” abstractions, you stop trusting similarity as a reason to unify things 😄
Great insight! As a junior dev, I tend to try to abstract functions looking similar. But.. It mostly turned out to be increase of complexity😂
And of course, I also think duplication is better than too much abstraction. Duplicated code is normally, at least, easy to understand. But too-much-abstracted code is hard to even read.
Haha, same story for a lot of us 😆
I think most developers go through a phase where we discover DRY and start abstracting everything that looks remotely similar. Then a few months later we're adding more parameters, more conditionals, and more overrides than the duplicate code ever had.
I've found that duplicate code is usually easier to deal with than a wrong abstraction. At least the duplication is obvious and doesn't force unrelated things to evolve together.
This is such a good breakdown. DRY is one of those principles that sounds simple until you realise the wrong abstraction can be way more painful than a little duplication. The “duplicate knowledge vs duplicate shape” point is huge. Do you usually wait until the third repeated pattern before abstracting?
Thanks! And yeah, I generally follow the "third time" rule. The first time, I just write it. The second time, I notice the pattern. By the third time, I usually have enough examples to tell whether it's actually the same knowledge being repeated or just similar-looking code.
I've been burned more times by abstracting too early than by leaving a bit of duplication around for a while. It's surprisingly common for two things to start out looking identical and then head in completely different directions a few months later 😅
The sendNotification example is so real. I've inherited that exact function before, except it had grown to take a config object because someone got tired of adding parameters. At that point you're not really sharing logic anymore, you're just hiding the fact that these are three different things.
The "wait for the third time" rule is good but I'd add: even when you do abstract, check if the things you're unifying actually change together. If email and SMS notifications evolve independently, keeping them separate isn't duplication, it's just accurate modeling.
Yeah, that’s exactly the failure mode, once a function turns into a “config object sink”, it usually means we’ve stopped modeling anything and just started hiding complexity behind a single entry point.
I really like your addition too. The “change together” check is honestly the part that matters more than the “third time” rule. Repetition alone isn’t enough — what really tells you whether abstraction makes sense is whether the reasons for change are actually shared.
If email and SMS evolve for different business reasons, keeping them separate isn’t duplication at all, it’s just honest modeling of reality. Trying to force them together usually just delays the pain.
Good, it's long text but it's very usefull. Thanks