DEV Community

Cover image for DRY Is a Lie: Confusion by Design
Jigar Gosar
Jigar Gosar

Posted on

DRY Is a Lie: Confusion by Design

The hidden cost of abstraction in modern software culture

TL;DR: Abstraction isn’t free. DRY isn’t sacred. And “clean code” isn’t always readable. We’ve built a culture that worships design principles without questioning their cost. It’s time we did.

🧱 The Gospel of Clean Code

When you write duplicate lines of code, your brain reflexively itches to extract them into an abstraction—not because the code demands it, but because the culture does.

You extract a function—or a class—and then try to pigeonhole it into another use case, forcing reusability where it wasn’t meant to fit.

And just like that, your local reasoning—perfectly at home in its corner—is marooned in the frozen tundra of remote abstractions.

Tracing indirection turns your mind into a stack of context switches, each deeper than the last.

But hey—it’s DRY. SOLID. Reusable.

Right?

Until it breaks your brain.

🧨 The Lie Beneath DRY

DRY—Don’t Repeat Yourself—was never meant to mean “never write the same line twice.” It was about not duplicating knowledge. Don’t let the same business rule live in two places.

But we turned it into a reflex. A dogma. A purity test.

And that’s when DRY becomes a lie.

We avoid repetition—and trade it for something worse: indirection, entanglement, and fragile abstractions.

🧩 The Hidden Cost of Abstraction

Abstraction is powerful—but it’s not free. Every time you extract something, you’re making a bet:

  • That the duplication is real, not just superficial
  • That the abstraction will hold up under future change
  • That the people reading your code will understand what you’ve hidden

When those bets don’t pay off, the cost is brutal:

  • Cognitive load: You’re jumping between files, tracing layers, decoding generic names—just to understand what’s happening.
  • Rigidity: Your abstraction locks you into a structure that resists change.
  • Fear: No one wants to touch the “shared” thing because it’s used in 12 places and no one remembers why.

But at least it’s DRY.

📚 The Cultural Blind Spot

We’ve built an entire culture around abstraction, and almost no vocabulary for its cost.

We have bookshelves full of Clean Code, Design Patterns, and SOLID Principles. We have workshops on “how to write reusable components” and “how to architect for scale.”

But where are the books titled:

  • The Cost of Abstraction?
  • Refactoring to Duplication?
  • The Art of Intentional Repetition?

They don’t exist—because we’ve treated abstraction as a virtue, not a tradeoff. We’ve made avoiding duplication a rule—and reasoning an afterthought. And we’ve confused “reusable” with “good.”

🧘‍♂️ Local Reasoning Over Abstraction

Here’s a radical idea: what if we made local reasoning our highest design virtue? Not reusability. Not elegance. Not DRYness. Just code you can understand without chasing it across files and layers.

Because the real cost of abstraction isn’t in the code—it’s in your head. It’s the number of things you have to remember just to answer: “What does this actually do?”

Repetition isn’t the enemy. Indirection is.

Because the truth is: duplication is easy to fix. Bad abstractions are hard to unwind.

🔄 The Alternatives We Ignore

There are principles that push back against abstraction dogma. But they’re rarely taught with the same reverence:

  • AHA (Avoid Hasty Abstractions): Don’t abstract until duplication becomes painful.
  • YAGNI (You Aren’t Gonna Need It): Don’t build for a future that may never come.
  • Rule of Three: Duplicate once, maybe twice. Abstract on the third time—if it still makes sense.

These aren’t anti-design. They’re pro-timing. They recognize that the cost of a wrong abstraction is higher than the cost of a little duplication.

🧨 The Callout

So here’s the challenge: Next time you reach for that abstraction—pause. Ask yourself:

  • Am I solving a real problem, or just avoiding repetition?
  • Will this abstraction make the code easier to change—or harder?
  • Am I doing this for understanding, or for comfort?

And if the answer isn’t clear—don’t abstract. Repeat yourself. On purpose. With pride.

Because sometimes, the cleanest code is the code that’s just… repeated.

If this idea of local reasoning struck a nerve—good. You’re not alone. In a follow-up post, we’ll dive deeper into the real complexity we forgot to measure: not code complexity, but cognitive complexity. Because the hardest part of software isn’t writing it—it’s thinking about it.

Footnote: Acronyms like WTFW (Why The Framework Works) and GRR (Generalized Refactor Regret) are real-ish, at least emotionally.

Top comments (11)

Collapse
 
xwero profile image
david duymelinck • Edited

I think the main rule to DRY code is, when changes are needed will it be for all the cases or are there exceptions. Once you know there are exceptions, don't DRY the code.

I wouldn't go that far as throwing clean code and design patterns on the same pile as DRY. The abstractions there have another goal.

The rule of three does not make sense. If you copy it once you used the code two times.

Collapse
 
jigargosar profile image
Jigar Gosar • Edited

I hear you, it not just about DRY, It's about abstractions and unnecessary and confusing indirections. I just wanted to have a click baity title :)

Collapse
 
xwero profile image
david duymelinck

I agree about the cognitive load. That I why I prefer modules with all the relevant files together over the Core/Domain/Infrastructure separation.

About the rigidity, if you use the patterns and principles correct, the code is less rigid.
For the fear, if you don't know why it is needed you need to find out. Leaving something in just because is the worst thing you can do for your code.

The best practices are a way to reduce confusion, but you don't need the enterprise level code to achieve patterns all the time. For example, you don't need to use a dependency injection layer, explicitly adding the dependencies works too.

Thread Thread
 
jigargosar profile image
Jigar Gosar

Exactly, you hit the mark. THis post is about highlighting the cultural dogma. Where not enough importance is given to the cost of cognitive load of indirection caused by applying design patterns. And about AHA, avoiding hasty abstractions.

Collapse
 
whitecolor profile image
Alex

You are trying to discuss "abstraction", but do not give a definition of what you are discussing. Abstraction is not about being DRY, it is not about getting rid of duplication, it is not the essence of it. Read and think about what it really is. It aims to reduce complexity and cognitive load by omitting unimportant details, and if it doesn't, it's just the wrong abstraction, and the wrong things are wrong, obviously.

Collapse
 
jigargosar profile image
Jigar Gosar

I want to thank you for taking the time to read the entire post and offer your critique. I'm so grateful for your feedback. I (naively) thought that I made my point crystal clear, but perhaps I should have addressed your objections more directly. I appreciate the time you took to critique the post, and I also appreciate the feedback. Thanks again.

Collapse
 
whitecolor profile image
Alex • Edited

Probably you wanted to give a warning against creating the wrong abstractions in pursuit of being DRY and writing less code, but it sounds like abstraction can be bad on its own. Correct/right abstraction is never bad, it decouples problem's essense from a concrete execution/implementation context, the thing is that most of those who write code don't understand what it really means. Good abstractions are lacking in most of the code outhere.

Thread Thread
 
jigargosar profile image
Jigar Gosar

Thanks for the feedback, I thought it was already covered in section:

The Alternatives We Ignore`

Also this post is about cultural dogma, as mentioned before, abstractions are not bad, but its cost is understated.

Thanks, much appreciated. Let me know about your objection in any particular part of the post.

Collapse
 
dirkbj profile image
Dirk Johnson

Great article - lots to think about here. And great comments as well.

A comment; you state:

Rule of Three: Duplicate once, maybe twice. Abstract on the third time—if it still makes sense.

I think it would be important to distinguish between abstraction and refactoring. I think if you are defining functionality, refactoring into a function and using that function rather than redefining would be useful even where it occurs limitedly.

Abstraction, to me, is more about concepts, patterns, and models than functions.

In my pursuit to reduce complexity and cognitive overhead, I have sometimes been surprised how often that path has lead me to realize that writing some custom code is often less complex than including 10 different extensions from external sources, or not worrying about the perfect abstraction but making it work simply and moving on.

Collapse
 
jigargosar profile image
Jigar Gosar

True that! I have spent almost two decades where I was very adamant about following SOLID and DRY and other design principles. Ultimately, I created a mess of abstractions, indirection, dependency injection abstract classes, and the like.

The eye opener for me was working in the Elm programming language, and this post is partly inspired by The life of a file.

Some comments may only be visible to logged-in visitors. Sign in to view all comments.