5 ms·
One of the #1 issues I’ve seen with DRY over the years seems to stem from a misunderstanding of what it means. DRY is not just about code duplication, it’s abo
by haswell 2y ago
One of the #1 issues I’ve seen with DRY over the years seems to stem from a misunderstanding of what it means.
DRY is not just about code duplication, it’s about information/knowledge duplication, and code happens to be one representation of information.
Hyper focusing on code duplication quickly gets into premature optimization territory, and can result in DRYing things that don’t make sense. Focusing on information duplication leaves some leeway for the code and helps identify which parts of the code actually need DRY.
The difference is important, and later editions of the Pragmatic Programmer call this out specifically. But the concept of DRY often gets a bit twisted in my experience.
- HanClinto 2y agoI feel like I hear de-duplication of information / knowledge often referred to as "Single Source of Truth"
- derefr 2y agoI think the best way to understand DRY is by thinking about the practical problem it solves: you don't want footguns in the codebase where you could change something in one place, but forget to change the same thing in other places (or forget to change the complementary logic/data in other components.) The goal of DRY as a refactoring, is first-and-foremost to obviate such developer errors. And therefore — if you want to be conservative about applying this "best practice" — then you could do that by just never thinking "DRY" until a developer does in fact trip over some particular duplication in your codebase and causes a problem.
- rezonant 2y ago> you don't want footguns in the codebase where you could change something in one place, but forget to change the same thing in other places This. Ironically the example on TFA is vulnerable to this issue. Each of the deadline setting methods has a copy of the validation ensuring that the date is in the future. If it's discovered that we need to ensure deadlines are set no later than the project deadline (since that wouldn't generally make sense), it's awfully easy to only update one and miss the others, especially after code has been added and these implementations are no longer visually near each other. I'm not saying that this means the code must be DRY'ed, but it is a risk from the beginning of the project, so one that needs to be weighed during initial implementation.
- hot_gril 2y agoThe Two Generals Problem is mentioned a lot in databases and networking, and you can take some liberties to extend it to human orgs.
- sham1 2y ago> The Two Generals Problem is mentioned a lot in databases and networking, and you can take some liberties to extend it to human orgs. In fact, the name probably already gives some hint as to what sorts of human orgs this sort of principle would be applicable in. And, well, the vast majority of orgs require some sort of coordination.
- schneems 2y agoSomeone “yes and”-ed a comment of mine awhile ago to teach me DRY SPOT. Don’t repeat yourself - Single Point of Truth. I.e. what you said. Couple logic that needs to be coupled. Decouple logic that shouldn’t be coupled.
- joe_fishfish 2y agoThis is a more insightful comment than the comment at the top, and also more useful than the blog post.
- tetha 2y agoThis is why some advice from Sandy Metz really stuck with me. It is not a problem to /have/ the same code 2, 3 or even 4 times in a code base. In fact, sometimes just straight up copy-paste driven development can be a valid development technique. Initially that statement horrified me, but by now I understand that just straight up copy-pasting some existing code can be one of these techniques that require some discipline to not overdo, but it's legit. And in quite a few cases, these same pieces of code just start developing in different directions and then they aren't the same code anymore. However, if you have to /change/ the same code in the same way in multiple places, then you have a problem. If you have to fix the same bug in multiple places in similar or same ways, or have to introduce a feature in multiple places in similar way - then you have a problem. Once that happens, you should try to extract the common thing into a central thing and fix that central thing once. It feels weird to work like that at first, but I've found that often it results in simpler code and pretty effective abstractions, because it reacts to the actual change a code base experiences.
- progmetaldev 2y agoI think another big part of deciding to use DRY is the complexity of what you're repeating. Copying and pasting lots of business rules means having to make complex edits whenever that logic needs to change. Having simple rules and a small amount of surface area for data reduces the initial need to have DRY code, and it's easier to take the initial risk of using duplicate code. At least in my experience, it's easier to start with duplicates of simple logic/data, and use DRY for more complex logic/data. The difficult areas are still those where the logic and/or data fall between simple and complex, or are expected to change often, but unknown whether they will change together or diverge quickly.
- nostrademons 2y agoThe challenge is that if you're not careful, you can end up copy-pasting the same bit of code hundreds of time before realizing it has to be changed. I once worked in a year-old startup of ~5 developers that found it had written the same line of code (not even copy-pasted, it was only one line of code so the devs had just written it out) 110 times. A bug was then discovered in that line of code, and it had to be fixed in 110 places, with no guarantee that we'd even found all of them. This was a very non-obvious instance of DRY, too, because it was only one line of code and the devs believed it was so simple that it couldn't possibly be wrong. But that's why you sometimes need to be aware of what you're writing even on the token level. That's why we have principles like "3 strikes and then you refactor". 3 times fixing a bug isn't too onerous; even 4-6 is pretty manageable. Once you get to 20+, there starts to be a strong disincentive to fixing the bug, and even if you want to, you aren't sure you got every instance.
- bojanz 2y agoCouldn't agree more. There's a great decade-old blog post by Mathias Verraes which illustrates this well, I keep coming back to it: https://verraes.net/2014/08/dry-is-about-knowledge/ https://verraes.net/2014/08/dry-is-about-knowledge/
- pineapple_sauce 2y agoHow is applying DRY entering premature optimization territory (maybe relative to LOC?)? I argue it is instead: premature abstraction. Optimization is specialization (which is the opposite of DRY): to enable DRY you likely need to generalize the problem (i.e. abstract) such that you remove duplication.
- haswell 2y agoI've always seen "Premature Optimization" as an umbrella that covers a variety of cross-cutting concerns, ranging from: - Performance - Code structure / abstraction - Data structure - Team organization / org structure I'd argue that DRY (and a focus on abstractions more generally) are optimizations of the codebase. Not all optimizations are optimizing the same thing.
- hot_gril 2y agoYeah, it's like reminding people that code can change, so it's ok to have known flaws day 1. Something forgotten too often. One thing that really goes against the usual programming grain is DBMSes. We're taught to always decouple/abstract things, but I'm convinced that it's impossible to abstract away your DBMS in most applications. It's just too big of an interface, and performance considerations leak right through it. It's always one of the selling points of an ORM, "you can switch databases later," and then nobody actually switches.
- BeetleB 2y agoIndeed - the acronym comes from The Pragmatic Programmer, and the author defined it in this way. Every blog post I've read criticizing/cautioning against DRY were not doing DRY as originally defined. DRY is almost always a good thing to do. Coupling superficially similar code is definitely not a good thing to do.
- haswell 2y agoYeah, here's the quote from the later editions addressing this: > Let’s get something out of the way up-front. In the first edition of this book we did a poor job of explaining just what we meant by Don’t Repeat Yourself. Many people took it to refer to code only: they thought that DRY means “don’t copy-and-paste lines of source.” That is part of DRY, but it’s a tiny and fairly trivial part. > DRY is about the duplication of knowledge, of intent. It’s about expressing the same thing in two different places, possibly in two totally different ways. > Here’s the acid test: when some single facet of the code has to change, do you find yourself making that change in multiple places, and in multiple different formats? Do you have to change code and documentation, or a database schema and a structure that holds it, or...? If so, your code isn’t DRY.
- dllthomas 2y ago> Coupling superficially similar code is definitely not a good thing to do. I've taken to calling that activity (removing syntactic redundancy that is only coincidental) "Huffman coding".
- drewcoo 2y ago> misunderstanding of what it means And in response, people will complain that they're being dismissed with "you're doing it wrong!" Because that happens with everything in programmer-land.
- haswell 2y agoThe easy response to someone feeling this way is to point them to the origin of DRY: The Pragmatic Programmer. In the book, the authors explicitly call out that many people took the wrong idea from the original writing. They clarify that DRY is not about code, it's about what they call "knowledge", and that code is just one expression of it. People can still disagree, but the original intent behind DRY is very well articulated.
- hot_gril 2y agoYeah, applies to databases and documentation especially. Databases have the ol' 3NF, you also want to avoid copying data from one source of truth to another in a multi-service environment, and sometimes I intentionally avoid writing docs because I want the code or API spec (with its comments) to be the only documentation.
- Cthulhu_ 2y agoIt's a good distinction to make. In the example given, while the code itself looks and does the same - comparing a date to the current date - they represent two different business logic processes, which can change over time. I mean if there's more instances of this (the DRY "rule" usually says that you deduplicate if there's 3 or more instances) you could refactor it into a utility like "isBeforeNow", but that doesn't add that much value.