DRY is Overrated
2026-02-20
Programmers spend enormous mental energy making their code DRY — Don’t Repeat Yourself. It’s practically a religious commandment. Spot duplication, eliminate it, parameterize the difference, feel virtuous.
But DRY has a dirty secret. Every time you eliminate repetition through parameterization, you trade one kind of complexity for another. The code gets shorter but harder to read. The function that used to do one clear thing now does seventeen subtly different things depending on which flags you pass it. You’ve optimized for the machine’s memory at the expense of the programmer’s mind.
What if repetition isn’t always the enemy?
Copy/paste code has a bad reputation, but it has a virtue that’s rarely acknowledged: it’s local. You can read it, understand it, and modify it without tracing through layers of abstraction. Each chunk is self-contained. The cost is inconsistency — when you fix a bug in one copy, you might forget the others.
This is exactly where LLMs could change the calculus.
Tools like git and diff are brilliant at spotting textual differences between chunks of code. But they don’t understand intent. They can’t tell you “these three functions are doing the same thing with a subtle variation in the error-handling path” or “this copy/pasted block has drifted — the original got a security fix but this one didn’t.”
LLMs can.
Instead of forcing programmers to DRY up their code preemptively — collapsing it into parameterized abstractions before they even understand the variation — what if we used LLMs after the fact, as consistency checkers? Let programmers write clear, local, readable code. Let them copy and paste when it aids clarity. Then run an LLM over the codebase periodically: “Hey, these four chunks look like they’re supposed to do the same thing. Here’s where they’ve diverged. Is that intentional?”
That closes the loop diff can’t close. It separates two concerns that DRY conflates: noticing duplication and deciding what to do about it. Sometimes the right answer is to consolidate. Sometimes the right answer is to leave the copies in place but ensure they stay in sync.
The real problem DRY was solving was maintainability — bugs propagating through inconsistent copies. LLMs might be able to solve that problem without imposing the readability tax that heavy parameterization demands.
We’ve been paying that tax for decades. It’s worth asking whether we still have to.
Further Reading and Inspiration
Paul Bassett’s largely overlooked book Framing Software Reuse: Lessons from the Real World (1997) made an early and rigorous case that reuse is harder than it looks and that the mechanisms we reach for — inheritance, parameterization, shared libraries — often create more coupling than they eliminate. His concept of frames as a unit of reuse deserves far more attention than it ever received. The book is out of print but still findable. Amazon CA
The NiCaD clone detector from the University of Saskatchewan is one of the more serious academic tools for finding near-miss code clones — similar but not identical code that has likely drifted from a common ancestor. It’s a reminder that the problem of detecting semantic duplication predates LLMs, and that researchers have been chipping at it for a long time. LLMs may finally make it practical at scale. NiCaD paper (PDF)
Lisp programmers have had a partial answer to this for decades in the form of macros — the ability to abstract over syntax, not just values. Rather than parameterizing behavior at runtime, you generate the code you need at compile time, keeping each generated instance readable and local while maintaining a single authoritative source of truth. This was once a Lisp-exclusive superpower. It no longer is. The Ohm parsing toolkit (ohmjs.org) brings similar expressive power to JavaScript and other ecosystems, and is worth exploring for anyone interested in building the kind of semantic tooling that could make LLM-assisted consistency checking practical.
See Also
Email: ptcomputingsimplicity@gmail.com
Substack: paultarvydas.substack.com
Videos: https://www.youtube.com/@programmingsimplicity2980
Discord: https://discord.gg/65YZUh6Jpq
Leanpub: [WIP] https://leanpub.com/u/paul-tarvydas
Twitter: @paul_tarvydas
Bluesky: @paultarvydas.bsky.social
Mastodon: @paultarvydas
(earlier) Blog: guitarvydas.github.io
References: https://guitarvydas.github.io/2024/01/06/References.html


I remember an old post from this blog:
Author: Martin Sústrik, 250 Bpm blog, 7th Nov 2016, "The Cost of Abstraction", URL https://web.archive.org/web/20191121115100/http://250bpm.com/blog:86
The author notes that, every time we write a subroutine or a function, we avoid the code duplication (DRY), but we create a new abstraction. The following problems must be considered, before appling DRY:
_ an abstraction could be hard to understand, posing a cognitive load on the developer which reads the code written by another one.
_ the consensus between the developers about the abstraction can be hard to reach.