5 ms·
The point is that they were never actually common in the first place, only superficially similar. You're saying we should look for duplications, abstract them,
by hannasanarion 3y ago
The point is that they were never actually common in the first place, only superficially similar.
You're saying we should look for duplications, abstract them, and then every time a change needs to be made to the abstraction to suit only one of the use cases, refactor the codebase to de-abstract and re-duplicate, undoing the work we did in the name of DRY in the first place.
That is a lot more work and a lot more confusion and a lot more headache for maintainers and reviewers than copy-pasting the thing the first time, having realized that the duplication was incidental, not structural.
Let's take this line of reasoning to its extreme:
I notice that there's a section of my code that's repeated twice where we add one to a value, so I abstract it into a function called add1(x:int). Some time later, at places where add1 is used we sometimes need to actually add a value other than one, so we need to make a decision: do we refactor everything and re-duplicate, or do we stick the DRY principle and make our abstraction more accomodating? The path of least resistance is to stick to DRY because it's a smaller and more comprehensible commit, so we add an optional arg, add1(x: int, operand?: int). Some time later one of the callers to this function needs to pass a vector instead of a single value, so we need our add1 function to have polymorphism and conditional logic in it now, and potentially more arguments. Sooner or later we have a frankenfunction that's hundreds of lines long and branches a bazillion ways and might as well be a turing machine in itself.
Dogmatic adherence to DRY leads to madness.
- cratermoon 3y ago> You're saying ... refactor the codebase to de-abstract and re-duplicate, undoing the work we did in the name of DRY in the first place. That's the exact opposite of what I'm advocating for, but perhaps I didn't express myself well. > Sooner or later we have a frankenfunction that's hundreds of lines long and branches a bazillion ways and might as well be a turing machine in itself. Yeah, that's not a good abstraction, and not at all what I meant.
- seadan83 3y agoTo some extent I agree, though I don't think DRY means to remove all similar looking lines of code and put that behind a procedure. Generic code vs abstractions are different. Instead, any given task (which already is an abstraction) should exist in only one place. That is DRY, I would paraphrase it to mean any given abstraction should be done in one place (and combine with SRP to say further that one place should only do that one abstraction) If one place can be updated independently of another, it argues it is not the same task to begin with. DRY'ing that code is a misnomer IMHO, instead that code is being put behind a procedure and is being made generic (and not necessarily more abstract. Abstracting hides details, putting a block of code behind a procedure with full parameterization is not hiding details, it's just a procedure [and let us hark back to the days of procedural programming and ways that can become mess]) DRY and SRP (single responsibility principle, AKA the DnD principle) need to be considered together.
- cratermoon 3y ago> I don't think DRY means to remove all similar looking lines of code and put that behind a procedure. Applying DRY primarily to structural duplication never occurred to me, and only this discussion brought this way of thinking to my attention. It's always been about semantic duplication to me. Often, but not necessarily, semantically duplicate code has structurally duplicate lines of code. But now I think I understand why some junior programmers I consulted for denied that their system was rampant with the duplication I was seeing. To them, the code was different because it looked different; that it all was doing more or less the same thing, but with different inputs, seemed lost on them. I have a vague recollection of one of them saying something about "parameterizing" the code, and then dismissing it. I'm going to have to dig through my notes from that gig to see if I can better clarify to myself the implications of the focus on only structural duplication and why it might lead a programmer to overlook very obvious opportunities for removing semantic duplication, or not understand how to fix it even if they do see it. ETA: I looked waaaay back to the ur-discussion on the c2 wiki and found this: "It's okay to have mechanical, textual duplication (the equivalent of caching values: a repeatable, automatic derivation of one source file from some meta-level description), as long as the authoritative source is well known." https://wiki.c2.com/?DontRepeatYourself https://wiki.c2.com/?DontRepeatYourself
- dllthomas 3y ago"Every piece of knowledge must have a single, unambiguous, authoritative representation within a system". What piece of knowledge does your add1 function represent? I don't think you're strawman is actually DRY (which is a problem - damp strawmen can mildew). I do agree that there are sometimes tradeoffs that can make a less DRY approach a better one, but not all deduplication is "DRY".
- hannasanarion 3y agoA critical word here is "knowledge". Every element of data, core capability, or logical object should have a single authoritative source. Having multiple db connections or ui controllers would, in fact, be a horrible nightmare, obviously. But not all code is knowledge, some of it's just boring work that does something to some local stuff and it doesn't necessarily need to be sharable with other parts of the code base, just because the logic looks kinda similar.
- dllthomas 3y agoRight. My quote was the original formulation of DRY as a principle, from The Pragmatic Programmer, and I think it's a good principle. The common (mis?)understanding of DRY as primarily syntactic both overshoots and undershoots. As many here have discussed, it can lead to combining things you shouldn't (I jokingly call this "Huffman coding"), but it can also fail to recommend combining knowledge when it is represented differently. If I'm saying "there is a button here" in my HTML and in my CSS and in my JS, that's three places for that piece of knowledge even if those three places don't look anything alike. Changing the CSS to "here is what my buttons look like" and the JS to "here is how my buttons behave" would be DRYer.