News for hackers. Stuff that matters.
Re:I don’t buy “duplication is cheaper than the wrong abstra... by lvncelot on Tuesday August 29, 2023 @09:00AM (#37307146)
> Except in very minor cases, duplication is virtually always worth fixing.

I disagree with the severity of this, and would posit that there are duplications that can't be "fixed" by an abstraction.

There are many instances I've encountered where two pieces of code coincided to look similar at a certain point in time. As the codebase evolved, so did the two pieces of code, their usage and their dependencies, until the similarity was almost gone. An early abstraction that would've grouped those coincidentally similar pieces of code would then have to stretch to cover both evolutions.

A "wrong abstraction" in that case isn't an ill-fitting abstraction where a better one was available, it's any (even the best possible) abstraction in a situation that has no fitting generalization, at all.

Re:I don’t buy “duplication is cheaper than the wrong abstra... by awkward on Tuesday August 29, 2023 @09:40AM (#37307770)
A good example of this is operations type stuff, like the pile of shell scripts or terraform files or whatever that get used to deploy your app. These scripts benefit greatly from a one to one relationship between the thing you're creating and the written text describing it. Not having a situation where changing one thing breaks everything else is a huge help there.
Re:I don’t buy “duplication is cheaper than the wrong abstra... by peeters on Tuesday August 29, 2023 @09:12AM (#37307343)
I try to think about whether two concepts are innately similar or incidentally similar. Computing compounding interest for a home equity loan and a mortgage might be innately similar. A desired change to one will probably make a desired change to the other. Computing growth of a fruit fly population and computing compounding interesting for a loan might be incidentally similar. Until you change your "computeExponentialGrowth" function to now handle occasional decimations from environmental sources, and anyone looking at the code wonders what the heck that looks like for a loan.
Re:I don’t buy “duplication is cheaper than the wrong abstra... by HWR_14 on Tuesday August 29, 2023 @09:36AM (#37307718)
As interest rates go back up, paying off (part of) a mortgage early might come back.
Re:I don’t buy “duplication is cheaper than the wrong abstra... by AnimalMuppet on Tuesday August 29, 2023 @09:15AM (#37307388)
For a loan, maybe it looks like payments on the principal?

But your overall point is very correct. Don't make an abstraction because of coincidence.

Re:I don’t buy “duplication is cheaper than the wrong abstra... by adammarples on Tuesday August 29, 2023 @12:16PM (#37310097)
If you've got your abstractions correct, then the exponential growth term and the decimation term will be partial differentials which will compose together nicely
Re:I don’t buy “duplication is cheaper than the wrong abstra... by lukeramsden on Tuesday August 29, 2023 @09:32AM (#37307639)
> There are many instances I've encountered where two pieces of code coincided to look similar at a certain point in time. As the codebase evolved, so did the two pieces of code, their usage and their dependencies, until the similarity was almost gone

https://connascence.io/

Re:I don’t buy “duplication is cheaper than the wrong abstra... by __alias on Tuesday August 29, 2023 @09:10AM (#37307321)
I buy into the same belief as you here, but I guess you could easily argue that you could create a suitable fitting abstraction earlier on with the understanding that you can "detach" them once the point that they're fundamentally different comes
Re:I don’t buy “duplication is cheaper than the wrong abstra... by consilient on Tuesday August 29, 2023 @09:22AM (#37307502)
The point of abstraction is to reduce the number of concepts in play. If you're still tracking which old concept is "really" being used every time, you haven't actually abstracted over anything, you're just naming things badly.
Re:I don’t buy “duplication is cheaper than the wrong abstra... by capableweb on Tuesday August 29, 2023 @12:16PM (#37310091)
> The point of abstraction is to reduce the number of concepts in play.

I'm not sure I agree with this. For me, the point of abstraction is divide the number of concepts between the layers you introduce, effectively to hide concepts from the layers where you don't want to have to care about them. Often times, abstractions adds the total number of concepts at play, but hides them beneath/above the layers.

Re:I don’t buy “duplication is cheaper than the wrong abstra... by fluoridation on Tuesday August 29, 2023 @09:24AM (#37307534)
The problem is that there's an impetus to continue working on top of established facilities, because it's usually incrementally less work than reworking a piece of code into something else. Plus it's difficult to recognize ahead of time when something is about to become a problem, rather than fix something that's already a problem.
Re:I don’t buy “duplication is cheaper than the wrong abstra... by AnimalMuppet on Tuesday August 29, 2023 @09:13AM (#37307360)
In that situation, the correct thing to do is, when the two pieces drift away from each other, to recognize that they are no longer the same abstraction and to break the connection. That may be painful - you have to look at everywhere that abstraction is used and figure out which thing it really is, and change the code to reflect it.

But if that's going to happen, then in the early days, a little duplication was probably better.

Re:I don’t buy “duplication is cheaper than the wrong abstra... by Retric on Tuesday August 29, 2023 @09:39AM (#37307755)
Yea, figuring out what’s going to happen seems hard but mostly comes down to why different bits of code are similar. Often what you want is to abstract a portion of the shared code rather than all of it.
Re:I don’t buy “duplication is cheaper than the wrong abstra... by MilStdJunkie on Tuesday August 29, 2023 @10:42AM (#37308679)
I might have to say some unkind things here, but statements like:

  instead of “duplication is cheaper than the wrong  abstraction”, I would say “duplication is cheaper than confusing code littered with conditional logic”.
seems like it's looking at this problem from an extremely narrow context.

The truth is that the phrase "wrong abstraction" is (more or less) unquantifiable, which makes the original phrase, as employed, sort of like a koan. It addresses the very human tendency to see patterns in noise, and our ability to "transmit" such hallucinations to other humans via natural language and other means.

The closest I can get to - given my at-best-apprentice status as a formal programmer - is the quantitative test I developed for CCS (conditional content systems), where the abstraction lies in the SNS[1], and the de-duplication mechanism is applicability[2]. Since each applicability statement carries its own overhead, there's a limit on how much "abstraction" the model can take before it's using quantitatively more keystrokes than duplication.

The test goes like this: take the flat text procedures for ALL the configurations, and add it together. Now, take the conditionalized, applicability-laden procedure that unifies the procedure, and measure its file size. If the latter is LARGER than the former, then you're using the wrong SNS/applicability model for rolling up this content.

Thing is, this is inevitable if you throw enough dissimilar configurations at a CCS, because each configuration has its own overhead, and eventually that outpaces the content itself.

You can address this in a bunch of ways - like adding a containing pseudo-product that has all the configurations inside of it - but the actual real Product Management might not let you build on the applicability like that, because the Product itself isn't sold that way. Any other abstraction isn't available to you, because in the end this is natural language, which - unlike structured language - resists first order abstractions really well. This is one of those instances where, yes, the abstraction of the SNS/Applicability is worse - quantifiably - than duplication. All that complexity would be better handled via version control fork/branch relationships - far outside of the realm of natural language.

[1] standard numbering system, a sort of numeric designator of functional systems, the primary way that content is designated as semi-independent modules.

[2] conditional "chunks" that turn on and off depending on the applicability statement

Re:I don’t buy “duplication is cheaper than the wrong abstra... by feoren on Tuesday August 29, 2023 @12:16PM (#37310108)
It'd be wonderful if we could measure the utility of software engineering choices by counting keystrokes or measuring file sizes or putting them in a turbo encabulator and seeing which one has more modial interaction with its magneto-reluctance. Unfortunately, reality is just too complicated, with far too many tradeoffs to be balanced. I'd recommend deep thought and discussion about the domain over looking at a graph of your codebase's sinusoidal repleneration.

> All that complexity would be better handled via version control fork/branch relationships

Probably not.

Re:I don’t buy “duplication is cheaper than the wrong abstra... by MilStdJunkie on Tuesday August 29, 2023 @01:21PM (#37311016)
Holy smokes, my turbo-sarcasmo detector just broke! But yeah, that's more or less the TLDR of my point. The phrase "wrong abstraction" does some heavy lifting, but it's not a bad concept, even if largely a qualitative one. No one should use a single metric to toss ginormous architecture decisions - they're tools to inform educated judgement, not replace it.

Re: fork/branch shenanigans, no, you're right, that's not an optimal way to handle variance . . in a normal programming language. In the context of natural language, it's not the same kettle of fish, because, well, lots of reasons, probably the most prominent being the "messy unidirectionality" of NL that's all mish mished with its extremely complex grammar vs constructed languages. Chopping up giant documents into tiny pieces a la CCS[1] systems has made this a stew of problems, but for some reason Leadership is fond of the idea. It's not unlikely that specialized on-prem LLMs are going to nuke the CCS concept from orbit in the next five years, except for those cases where the CCS is a contractual requirement for doing the work.

[1] component content systems

Re:I don’t buy “duplication is cheaper than the wrong abstra... by mostlylurks on Tuesday August 29, 2023 @11:54AM (#37309769)
> An early abstraction that would've grouped those coincidentally similar pieces of code would then have to stretch to cover both evolutions.

This seems to be the underlying assumption behind most uses of the "duplication is cheaper than the wrong abstraction" quote, but the assumption is simply incorrect. You should almost never try to expand abstractions in this manner. If you don't treat the abstractions relating to the thing you want to change in your codebase as "the" place where you need to make your change, and instead eagerly make new abstractions and throw old ones away as required, you won't really run into this problem.

In fact, this predominant mindset where creating abstractions is strongly discouraged leads to the very problem that mindset is based on, as it will simply encourage junior developers and the like to modify the existing abstraction, creating the aforementioned kind of mess where abstractions become complicated through repeated modification, instead of creating new abstractions when appropriate, because creating abstractions has a stigma attached to it.

Additionally, if someone has made a "wrong" abstraction based on something silly like two pieces of code simply being similar in terms of their structure and those use cases start to drift apart, you should feel eager to simply split apart the abstraction, be it into bare implementations or two new abstractions, or any other combination. Abstractions are cheap as long as you don't give them special significance.

Re:I don’t buy “duplication is cheaper than the wrong abstra... by sweezyjeezy on Tuesday August 29, 2023 @12:17PM (#37310116)
I think there's a middle ground here. The original quote does not mean DRY=bad, abstraction=bad. The point is there is a non-zero cost to these things. A bad abstraction can, as you say, accumulate to something terrible through inertia or inexperience. A bad abstraction, even if caught early, was probably not worthwhile - I mean, it took time just to make the original one right? This does not mean that we should be scared of abstraction in general, but in my opinion abstractions that are purely for the sake of reducing duplication should be viewed with an extra level of apprehension.
Re:I don’t buy “duplication is cheaper than the wrong abstra... by jameshart on Tuesday August 29, 2023 @12:26PM (#37310256)
When an abstraction evolves to a point where it needs to be split into two separate implementations to meet diverging needs…

you will need to replace that abstraction with duplication.

Which is the right thing to do because that duplication is cheaper than maintaining the wrong abstraction.

I think this post makes the mistake of thinking that the only way in which duplication comes up is that it is discovered in the codebase, and we have the choice of abstracting it away or keeping it.

On the contrary, duplication can - and should - be consciously introduced to fix bad abstractions when we find them in the codebase.

Re:I don’t buy “duplication is cheaper than the wrong abstra... by cratermoon on Tuesday August 29, 2023 @12:30PM (#37310318)
> When an abstraction evolves to a point where it needs to be split into two separate implementations to meet diverging needs… you will need to replace that abstraction with duplication.

Hard disagree. When the formerly common parts of an abstraction evolve to no longer be common, then that duplication no longer exists. There now exists two abstractions, one for each of the diverging needs. There may be some leftover commonality that can be abstracted out, but it's no longer the original abstraction.

Re:I don’t buy “duplication is cheaper than the wrong abstra... by hannasanarion on Tuesday August 29, 2023 @12:47PM (#37310544)
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.

Re:I don’t buy “duplication is cheaper than the wrong abstra... by cratermoon on Tuesday August 29, 2023 @01:04PM (#37310795)
> 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.

Re:I don’t buy “duplication is cheaper than the wrong abstra... by seadan83 on Tuesday August 29, 2023 @03:11PM (#37312430)
To 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.

Re:I don’t buy “duplication is cheaper than the wrong abstra... by cratermoon on Thursday August 31, 2023 @12:36AM (#37332512)
> 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.

Re:I don’t buy “duplication is cheaper than the wrong abstra... by dllthomas on Wednesday August 30, 2023 @02:51AM (#37318529)
"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".

Re:I don’t buy “duplication is cheaper than the wrong abstra... by hannasanarion on Wednesday August 30, 2023 @06:55PM (#37330211)
A 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.

Re:I don’t buy “duplication is cheaper than the wrong abstra... by dllthomas on Wednesday August 30, 2023 @08:42PM (#37331094)
Right. 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.

Re:I don’t buy “duplication is cheaper than the wrong abstra... by ajuc on Tuesday August 29, 2023 @01:28PM (#37311119)
In many cases you cannot see the correct abstraction without introducing the duplication back. When working with particularly messy code I often do sort of https://en.wikipedia.org/wiki/Karnaugh_map of important variable states to see what actually happens before I can refactor it.

This is basically introducing the duplication back.

Whether you keep the duplicated code or refactor it in a different way is another question, what matters for the "duplication is cheaper than wrong abstraction" to be true is just the fact that by introducing abstraction early you wasted time refactoring one way and back. Refactoring isn't free. So in fact leaving the duplication there would have been cheaper - Q.E.D.

It doesn't mean you should never risk it, but it does mean you should think hard before you do it.

Re:I don’t buy “duplication is cheaper than the wrong abstra... by TOGoS on Tuesday August 29, 2023 @12:55PM (#37310662)
> You should almost never try to expand abstractions in this manner

But somebody on your team /will/.

> you should feel eager to simply split apart the abstraction

Sure, but it's going to be a lot more work at this point than if we had avoided the mess in the first place.

Re:I don’t buy “duplication is cheaper than the wrong abstra... by mdiesel on Tuesday August 29, 2023 @11:59AM (#37309839)
Equality doesn't necessarily mean Equivalence.
Re:I don’t buy “duplication is cheaper than the wrong abstra... by feoren on Tuesday August 29, 2023 @12:03PM (#37309898)
You're absolutely right that it's important to look beyond how two modules superficially look right now, and look instead at how they change. However, if you've always defined your abstractions based on what their consumers need rather than what their implementations have, then you shouldn't ever need to stretch them. They're not trying to "cover" both cases, they're trying to solve a problem that both cases have. Your two cases are not implementations of the abstraction, they are consumers of it. If one case grows to not have that problem, it just stops asking for that abstraction. If it grows to have more problems, it just asks for more abstractions. The original abstraction, if based on a common need, doesn't have to change.

That's not to say abstractions never change -- they do. But they change because your understanding of the sub-problem they're solving has changed, not because their implementations or consumers have changed.

Re:I don’t buy “duplication is cheaper than the wrong abstra... by crabbone on Tuesday August 29, 2023 @12:04PM (#37309916)
So... you kept modifying the two similar pieces of code until they became dissimilar. Why do you think that you wouldn't be able to modify the abstraction if you saw that it doesn't fit anymore?
Re:I don’t buy “duplication is cheaper than the wrong abstra... by convolvatron on Tuesday August 29, 2023 @12:54PM (#37310647)
I think part of the issue here is that a fair number of programmers work in shops where they have very limited agency. They are tasked with making the minimum defensible change to add a feature or fix a bug. They are not allowed to change the tests or suggest refactoring. So those things just don't occur.
Re:I don’t buy “duplication is cheaper than the wrong abstra... by crabbone on Wednesday August 30, 2023 @05:19AM (#37319407)
I see, but wouldn't this lack of agency, or, more precisely the inability to escalate the problem to someone with more edit rights be the actual issue?

I could see this also happening in situations where such problems arise at component interface boundaries, where the pressure not to change comes not as an organizational policy but rather inability to influence external components (eg. the OS offers a poor abstraction -- the user-space program developer wouldn't be changing how OS works to rectify things). But, this is again sort of an administrative problem, because, ideally, the user-space program developer should be able to convince the OS developer to change the interface if it's found to be not a good abstraction...

But, yes, I can see how in practice that'd be a very difficult thing to do.

Re:I don’t buy “duplication is cheaper than the wrong abstra... by convolvatron on Wednesday August 30, 2023 @12:22PM (#37324394)
I guess I was trying to claim that in a lot of places there isn't such a person.

yeah - if an application company runs up against a poorly designed OS interface - they usually aren't aware, or just back away slowly. they don't have the scope or mandate to pursue it.

that kind of behavior often extends to library dependencies, and even internal interfaces that the company should ostensibly own.

its not so much an administrative problem as a desire to limit spending and time on software and do a kind of agile mvp glue job over an unbounded number of external dependencies. that often leads to an unmaintainable hairball. but if the alternative is to hire a bunch of really experienced developers and let them 'do the right thing' for 5 years...

even if you do, there is a still a good chance that the output isn't gonna be that great. software people lost a lot of credibility with that model. we've probably swung too far in the other direction

Re:I don’t buy “duplication is cheaper than the wrong abstra... by ilyt on Tuesday August 29, 2023 @12:10PM (#37310010)
> There are many instances I've encountered where two pieces of code coincided to look similar at a certain point in time. As the codebase evolved, so did the two pieces of code, their usage and their dependencies, until the similarity was almost gone. An early abstraction that would've grouped those coincidentally similar pieces of code would then have to stretch to cover both evolutions.

Then you split that abstraction again. It's very cheap and very quick.

Many people talk about the issue like it was an absolute in the code, but that's wrong approach. If you end up writing 4 functions that are the same, by all means, merge it into one.

If then you need to add a parameter only this code path uses and rest doesn't care about, by all means split it back. Moving blocks of code around is cheap.

Re:I don’t buy “duplication is cheaper than the wrong abstra... by oxfordmale on Tuesday August 29, 2023 @01:57PM (#37311499)
Splitting the abstraction is never cheap and quick, mostly because of politics. With duplicated code you often can assign a single responsible owner to each duplication.

However, once abstracted, the code may suddenly be used by a number of different teams. You will need to get this work on their roadmap, increasing the friction to get this done. In many companies, this will also end up in endless discussions about the new approach.

Re:I don’t buy “duplication is cheaper than the wrong abstra... by esafak on Tuesday August 29, 2023 @02:31PM (#37311921)
This is a good point. Following Conway's Law, a team may choose to duplicate code or do thing theoretically sub-optimally simply to avoid having to deal with other teams.
Re:I don’t buy “duplication is cheaper than the wrong abstra... by yellowapple on Tuesday August 29, 2023 @02:46PM (#37312114)
Solution there would be to make the abstraction "opt-in", such that a team can elect to duplicate or abstract as desired. Also helps if the "main" abstraction is itself composed from smaller abstractions, from which downstream teams could then pick-and-choose rather than having to either fully abstract or fully duplicate.
Re:I don’t buy “duplication is cheaper than the wrong abstra... by jrumbut on Tuesday August 29, 2023 @02:32PM (#37311933)
I think the key here is the oft repeated but often poorly understood maxim to favor composition ("has a") over inheritance ("is a").

If you have a mixin (or other means of composition) that you use in several places and one diverges, it's easy to remove it. If you use inheritance, it's going to be more painful.

A language that offers OOP via prototypes instead of classes like JS can (sometimes) give you the best of both worlds, but it will confuse a lot of devs who aren't familiar with that kind of OO design.

Re:I don’t buy “duplication is cheaper than the wrong abstra... by BWStearns on Tuesday August 29, 2023 @12:10PM (#37310013)
Agreed. Abstractions also tend to be more resistant to change, both from a technical level, and a social level.

At a technical level an abstraction will have more call sites to worry about in different contexts, the more wrong the initial abstraction the harder it will be to change.

The social level is maybe even more problematic. Abstractions seem more important than calling code and will experience more friction in code review. This change friction can also increase with the "wrongness" of the initial abstraction. The starting point makes less sense so a reviewer needs to work more to understand the context. If the abstraction is gnarly enough then it's possible that the reason for the abstraction is almost obscured. Even someone who knows _how_ it works might have lost the forest through the trees and push back on changes that simplify it or improve it if the change is a sufficiently large departure from the initial state. In this case you can often see small incremental changes get added easier but this just makes the shared code a bit gnarlier for next time.

Re:I don’t buy “duplication is cheaper than the wrong abstra... by ljm on Tuesday August 29, 2023 @01:48PM (#37311391)
This is my beef with naively applied DDD, separation of concerns, and design patterns.

Usually what happens is the 'clean' code ideal comes first, and then the implementation is squeezed into it. This then informs the organisation (or architecture) of the rest of the codebase and your software design has become a matter of putting pegs into the right-shaped holes.

I have never found that kind of highly abstracted code easier to work with than some simple procedural alternative that is easy to delete and easy to refactor, so long as effort was put into writing it well.

Of course, the patterns have a purpose and do help when used nicely - a lot of code you write will fall into some of those patterns even without you explicitly mentioning it. It's just...doing it for the sake of it is a problem.

Re:I don’t buy “duplication is cheaper than the wrong abstra... by evilduck on Tuesday August 29, 2023 @07:20PM (#37315490)
We call those architecture astronauts.

The pile of abstractions stacks to the moon but when you chase down what's actually happening a 60 file repo ends up holding like 12 lines of actual programming.

Re:I don’t buy “duplication is cheaper than the wrong abstra... by tetha on Tuesday August 29, 2023 @06:18PM (#37314871)
> At a technical level an abstraction will have more call sites to worry about in different contexts, the more wrong the initial abstraction the harder it will be to change.

As I recently called it, infrastructure and systems lose agility as they gain dependency and move down the stack.

If you have like 1 customer and they have good retries, honestly: fuck everything. Deploy master, in fact, deploy every keystroke to prod. It'll be fine.

At the same time, about 30k - 40k FTEs of our B2B customers depend on one of my Postgres instances during business hours and about twice of that during different holiday seasons. Honestly? Nothing touches the system-level settings of these database systems unless we have pondered a change for 2 weeks. And even then we will schedule an approved change over 4 weeks across applicable postgres clusters. The carnage a bad change at this level can cause is ridiculous enough to not be.

Re:I don’t buy “duplication is cheaper than the wrong abstra... by CuriouslyC on Tuesday August 29, 2023 @12:11PM (#37310036)
Duplication can sometimes be useful, for instance if you have many small variations on a central process. Trying to make one process with all the edge cases baked in leads to overly-complex, hard to reason about, expensive software.

In my experience, the right way to handle this sort of situation is to create a functional mini-DSL for the process that handles all the implementation details, then create a "default" process which serves as a template. If a process needs slightly different logic, just copy the template, update the DSL to support any new logic, and update the template with the new DSL statements. This approach lets you give semantic meaning to implementation details, and you can see where all the different custom logic is at a glace by looking at all the template copies. As long as the template is only calling out to DSL actions with no internal logic of its own and process flow is correctly encapsulated in the DSL, you should never need to update templates to change behavior, only update the DSL.

Re:I don’t buy “duplication is cheaper than the wrong abstra... by tracker1 on Tuesday August 29, 2023 @12:18PM (#37310135)
This is generally my approach to data ingress/egress (ETL)... I'd rather have a hundred similar, small scripts for each data source than try to create one complex (monstrosity) application to handle them all.
Re:I don’t buy “duplication is cheaper than the wrong abstra... by crazygringo on Tuesday August 29, 2023 @12:53PM (#37310625)
> is to create a functional mini-DSL

Exactly. Is there a formal term for this?

Instead of one gigantic function with 50 parameters, you have 100 "template" functions, that all make use 60 different "helper" functions (what you're calling the DSL).

Instead of castles-of-logic abstraction, it's nuts-and-bolts or grass-roots abstractions. I've never come across a name for this development style.

But it generally works extremely well when building processes for tens/hundreds of data formats or customers or what have you.

Re:I don’t buy “duplication is cheaper than the wrong abstra... by consilient on Tuesday August 29, 2023 @02:27PM (#37311863)
> I've never come across a name for this development style.

Libraries designed like this are sometimes called "combinator libraries".

Re:I don’t buy “duplication is cheaper than the wrong abstra... by code_biologist on Tuesday August 29, 2023 @02:30PM (#37311904)
Embedded DSLs is the term I’ve seen in the Haskell, Scheme and Ruby communities.
Re:I don’t buy “duplication is cheaper than the wrong abstra... by fiddlerwoaroof on Tuesday August 29, 2023 @03:39PM (#37312827)
This sounds like what lispers call something like “language driven design” or “growing a language”
Re:I don’t buy “duplication is cheaper than the wrong abstra... by Kalabasa on Wednesday August 30, 2023 @12:08AM (#37317551)
Builder pattern is a similar concept
Re:I don’t buy “duplication is cheaper than the wrong abstra... by augustk on Tuesday August 29, 2023 @01:43PM (#37311317)
DSL = Domain-specific language (I guess).

Always a good idea to expand an abbreviation the first time it's used.

Re:I don’t buy “duplication is cheaper than the wrong abstra... by amalcon on Tuesday August 29, 2023 @04:02PM (#37313130)
This way of doing things (which I agree is often the correct way) is the reason for Greenspun's Tenth Rule: https://en.wikipedia.org/wiki/Greenspun%27s_tenth_rule

Though it's less true today and in languages that are not C or Fortran. Even something like C++ or Java has the template method pattern, which gets you 80% of the way there. Dynamic languages like Python or Ruby tend to have pretty reasonable facilities for building DSLs, as do more modern languages like Scala and Rust.

Re:I don’t buy “duplication is cheaper than the wrong abstra... by kiitos on Tuesday August 29, 2023 @08:17PM (#37315989)
So, to maintain your project, it's not sufficient for me to know language X -- I also have to learn a bunch of domain-specific sub-languages, which any developer on the project may have implemented in response to an arbitrary problem, which almost certainly has no kind of formal specification or stability guarantee, and which can change over time in any way without warning? No sir.
Re:I don’t buy “duplication is cheaper than the wrong abstra... by CuriouslyC on Tuesday August 29, 2023 @10:20PM (#37316894)
"So, to maintain your project, it's not sufficient for me to know language X -- I also have to learn a bunch of functions, and understand the business processes that are used to create the abstractions, and trust code from my coworkers with just unit tests and type checking? No sir."
Re:I don’t buy “duplication is cheaper than the wrong abstra... by kiitos on Wednesday August 30, 2023 @09:12AM (#37321597)
It seems like you're equivocating language-level concepts like syntax, semantics, grammar, etc. with program-level concepts like types, functions, names, etc. But these are two categorically different things.
Re:I don’t buy “duplication is cheaper than the wrong abstra... by capableweb on Tuesday August 29, 2023 @12:14PM (#37310076)
As a FYI, just as it's OK to abstract away duplication in code, it's OK to do the opposite, remove abstraction and add duplication.

So in your particular case, it could have been possible to abstract away the code at that point in time and once they diverge, remove the abstraction and duplicate, then adjust one of the duplicates (which no longer is a proper duplicate really).

But, might be more work than it's worth. YMMV.

Re:I don’t buy “duplication is cheaper than the wrong abstra... by patrick451 on Tuesday August 29, 2023 @06:47PM (#37315148)
> As a FYI, just as it's OK to abstract away duplication in code, it's OK to do the opposite, remove abstraction and add duplication.

> So in your particular case, it could have been possible to abstract away the code at that point in time and once they diverge, remove the abstraction and duplicate, then adjust one of the duplicates (which no longer is a proper duplicate really).

This sounds nice in theory, but the reality is that the effort required to make these two kinds of changes is not symmetric. It's about 10 times easier to get a PR approved and merged that combines similar looking code into a function than vise versa. If you any suspicion at all that an abstraction you're making may need to be removed and duplicated in the future, you're better of just never abstracting in the first place.

It sucks pushing a change which unwinds an abstraction like that through code review. It's usually a lot easier to just never abstract it in the first place.

Re:I don’t buy “duplication is cheaper than the wrong abstra... by codegeek on Tuesday August 29, 2023 @12:29PM (#37310301)
Also, you become a better programmer if you write duplicate code and then learn how to abstract it for cases that make sense. I also don't believe that dupe code is always a bad thing. Like everything else in software engineering, IT DEPENDS.
Re:I don’t buy “duplication is cheaper than the wrong abstra... by rdedev on Tuesday August 29, 2023 @01:02PM (#37310765)
You got a good point about code evolution. Has anyone taken a look at it from a biological perspective? Seems like such problems can occur in genetics and nature might have come up with some tricks we can use
Re:I don’t buy “duplication is cheaper than the wrong abstra... by bena on Tuesday August 29, 2023 @01:06PM (#37310815)
The answer, as always, is "sometimes".

Sometimes duplication is cheaper than the wrong abstraction.

And

Sometimes it's better to abstract away a duplication rather than let it lie.

And that's the mark of becoming a master at the craft. Being able to recognize all of these various slight permutations of state and what to do about them.

Re:I don’t buy “duplication is cheaper than the wrong abstra... by rightbyte on Tuesday August 29, 2023 @03:29PM (#37312687)
Rule of thumbs really need to be told like this. Or they will be missused. Either by newbies that doesn't know any better or unpleasant programmers that will show their dogmatic beliefs down your throat with the common wisdom as excuse.
Re:I don’t buy “duplication is cheaper than the wrong abstra... by bheadmaster on Tuesday August 29, 2023 @01:23PM (#37311056)
There's a very good quote on a programming blog [0] that I enjoyed reading:

    Repeat yourself to avoid creating dependencies, but don’t repeat yourself to manage them.
[0] https://programmingisterrible.com/post/139222674273/write-co...
Re:I don’t buy “duplication is cheaper than the wrong abstra... by msluyter on Tuesday August 29, 2023 @02:12PM (#37311698)
I think one example where duplication > abstraction is in tests. I personally find tests that have a ton of extra helper classes/functions to do stuff like set up fixtures or do assertions to be painful to deal with. Taken to an extreme you end up with a mini test framework that obscures the actual test cases and is as hard to understand as the code in question.

I'm not against shared test fixtures or some utility functions, but IMHO, it's better to have some duplication but clearer tests.

Re:I don’t buy “duplication is cheaper than the wrong abstra... by abcdaiojjdfoj on Tuesday August 29, 2023 @02:25PM (#37311848)
I like it when you have nice, composable utility functions. Ideally each test contains a short preamble setting up the appropriate context for the test to run. The preamble elucidates what the tests are actually testing. It can also serve as documentation on how to use those functions.

There will probably be some duplication across tests, but if the utility functions are idempotent/composable, they're usually pretty easy to read/understand and equally mechanical to write/update.

Re:I don’t buy “duplication is cheaper than the wrong abstra... by echelon on Tuesday August 29, 2023 @02:23PM (#37311818)
Fully agree.

I would add that you should duplicate the common, cross-cutting setup (eg. faked/mocked dependencies that don't matter), but make the test conditions themselves explicit.

You get a feel for the correct granularity the more tests you write within the codebase. If you try to be too clever in saving boilerplate, you'll cause pain for future modifications and maintainers. Sometimes fixing "clever" tests takes longer than the code change itself.

Re:I don’t buy “duplication is cheaper than the wrong abstra... by ezekg on Tuesday August 29, 2023 @03:27PM (#37312656)
> I personally find tests that have a ton of extra helper classes/functions to do stuff like set up fixtures or do assertions to be painful to deal with.

I think it depends on the context. For example, I typically agree, but when I was writing authz tests [0], I ended up writing a DSL so that 1) I'd more more inclined to write the thousands and thousands of tests, and 2) I'd be able to focus on the actual authz assertion and not on verbose setup.

I couldn't imagine writing those policy tests without that abstraction. I would have lost my mind with all of the repetition, and would have almost assuredly made mistakes.

[0]: https://github.com/keygen-sh/keygen-api/blob/master/spec/pol...

Re:I don’t buy “duplication is cheaper than the wrong abstra... by HumanOstrich on Tuesday August 29, 2023 @06:38PM (#37315072)
Thank you for the link. This is inspiring. Do you have any resources you could link to that would explain some or all of the style for these tests?
Re:I don’t buy “duplication is cheaper than the wrong abstra... by ezekg on Tuesday August 29, 2023 @11:30PM (#37317333)
Honestly, I don't have many resources to provide. I read a lot of policy tests via GitHub search (e.g. path:spec/policies/*/*.rb), but couldn't find anything that looked like what I wanted. I wrote the DSL as-needed in order to fully test my app's authz while migrating from Pundit to ActionPolicy (while also introducing fine-grained permissions).

It's not the prettiest when you actually look beneath the covers [0], but it does what I wanted -- providing an easy way to write exhaustive authz tests. Without the DSL, I probably wouldn't have written the tests. The PR for said migration was massive [1], and was a prerequisite to going open source [2].

[0]: https://github.com/keygen-sh/keygen-api/blob/master/spec/sup...

[1]: https://github.com/keygen-sh/keygen-api/pull/647

[2]: https://github.com/keygen-sh/keygen-api/issues/644

Re:I don’t buy “duplication is cheaper than the wrong abstra... by HumanOstrich on Wednesday August 30, 2023 @01:03AM (#37317880)
Thanks! I'll dig around in the pull request and issue as well.
Re:I don’t buy “duplication is cheaper than the wrong abstra... by yellowapple on Tuesday August 29, 2023 @02:22PM (#37311807)
> An early abstraction that would've grouped those coincidentally similar pieces of code would then have to stretch to cover both evolutions.

In that case, my takeaway would be that it ain't the abstraction itself that's wrong, but the unwillingness to get rid of it (or decompose it) when it no longer serves its purpose.

Re:I don’t buy “duplication is cheaper than the wrong abstra... by bcrosby95 on Tuesday August 29, 2023 @02:22PM (#37311813)
Given a long enough timeline, every abstraction turns wrong.

The answer isn't to not abstract, the answer is to tear it out when it turns wrong. That was actually the original point of the popular article that streamlined this view - that we shouldn't be afraid of tearing them out, not that we shouldn't make them in the first place. Most people just read headlines though.

Re:I don’t buy “duplication is cheaper than the wrong abstra... by lolinder on Tuesday August 29, 2023 @04:00PM (#37313099)
The resistance to tearing out a bad abstraction isn't just cultural: combining two different functions into one is a lossy operation, which makes splitting an abstraction harder than creating it in the first place.

While the functions are distinct the call sites are self-documenting. You know which calls are for which purpose because the names are different. After combining them to deduplicate the code, you've lost that information, and to disentangle the abstraction now requires you to infer and reintroduce that lost information.

It's not that it can't be done, but there is real friction that doesn't just exist in people's heads.

Re:I don’t buy “duplication is cheaper than the wrong abstra... by abathur on Tuesday August 29, 2023 @05:59PM (#37314706)
I think the difficulty of making the right decisions without this lost information is well-observed.

I wrote a short post in roughly this idea space last year: https://t-ravis.com/post/doc/what_functions_and_why_function...

It feels like the same thread you're describing, but I guess it's pulling on the other end of it. It's thinking about how to name things in a way that makes it easier to see that the implementations might diverge later, and simplify actually doing so (by preserving more of this intentional context).

Re:I don’t buy “duplication is cheaper than the wrong abstra... by kiitos on Tuesday August 29, 2023 @08:08PM (#37315919)
Tearing out an abstraction requires a lot of knowledge about the abstraction and how it is used throughout the system. Over time, statistically zero maintainers will have that level of knowledge about any non-trivial system.

In contrast, duplicated code may be annoying, but it is usually simple to understand and maintain by anyone with knowledge of the project and the programming language.

Leaky abstractions are way way way worse than no abstraction at all.

Re:I don’t buy “duplication is cheaper than the wrong abstra... by stev-0 on Thursday August 31, 2023 @01:45AM (#37332923)
> Given a long enough timeline, every abstraction turns wrong.

This is bullshit. I think what you mean is that even a good abstraction can be used inappropriately.

You shouldn’t compound that with the fact that sometimes people create abstractions that are just bad.

Re:I don’t buy “duplication is cheaper than the wrong abstra... by Gibbon1 on Tuesday August 29, 2023 @03:28PM (#37312677)
My problem always is often when writing a function to remove duplication brings up the question of where to put it. If its only called inside one module doesn't matter really. But if not you've created a dependency. Which is bad.

I think how much you hate that may depend on your language and the program. Some big enterprise Java monolith is a garbage dump of thousands of small files. So who cares. In C without name spaces and the need for headers you care more.

Re:I don’t buy “duplication is cheaper than the wrong abstra... by schwartzworld on Tuesday August 29, 2023 @06:03PM (#37314734)
The problem is that "duplication is cheaper than the wrong abstraction" is basically an excuse that lazy devs use not to engineer their code.

The other one I hear a lot is "it's not realistic to reach 100% test coverage / type safety" when submitted code with `any` all over it and zero tests.

Re:I don’t buy “duplication is cheaper than the wrong abstra... by seadan83 on Tuesday August 29, 2023 @08:58PM (#37316291)
I think this is an example that highlights abstract vs generic code. An abstraction should have hidden those evolutions entirely, which potentially means there would have been two code paths behind the abstraction. Moving that logic to a generic procedure with full parameterization I wouldn't call an abstraction (it's code that has been made generic). Generic code is more complex. DRY is not about making everything that can be generic, generic - it's about making sure a single thing is done in one place (and only that one place, DRY & SRP go together).
Re:I don’t buy “duplication is cheaper than the wrong abstra... by devoutsalsa on Wednesday August 30, 2023 @07:45AM (#37320563)
One of the biggest problems with deduplication is you can end up with shared code that's full of corner case handling for different situations. Then your nice shared example becomes a tangled rats nest you can't unravel.