Top
Best
New

Posted by rafaepta 2 hours ago

Code duplication is far cheaper than the wrong abstraction (2016)(sandimetz.com)
212 points | 145 comments
dofm 1 hour ago|
No it's not. This has always been a needlessly iconoclastic rather than sensible suggestion.

At the very least it is not once you're working at the wrong kind of scale.

Once you have an awkward number of customers (more than five and less than a hundred), maintaining duplicated code that should have been abstracted and modularised will only seem cheap if you don't mind that you burn through even junior employees at a pace.

And in the LLM era the wrong kind of scale appears in different ways; code generated and duplicated without proper abstraction and then maintained by an LLM that cannot be trusted to do the same modification each time it encounters a pattern or to have enough of an overview to slowly rescue duplicated code through good abstractions.

I would go as far as to say that any abstraction you can maintain (that is in active maintenance, I mean) is better than code duplication once you are past a de minimis threshold.

coldtea 1 hour ago||
Hardly iconoclastic, it's a very sensible suggestion.

It would be iconoclastic if the common sense basic approach would be to start with abstraction. It's not, the common sense default is to write possibly duplicate behavior until you actually discover several cases to abstract away, until you bevalop a sensible idea of which functionality unites them and which doesn't carry over all of them.

>Once you have an awkward number of customers (more than five and less than a hundred), maintaining duplicated code that should have been abstracted and modularised will only seem cheap if you don't mind that you burn through even junior employees at a pace

Maintaining the wrong abstraction, or, god help, abstractions, would be even worse.

dofm 1 hour ago|||
> Maintaining the wrong abstraction, or, god help, abstractions, would be even worse.

Hard disagree. When you've had to chase through a change in untold and actually unknown numbers of duplications of code in different permutations and fix them because they are all on fire simultaneously, you'd disagree too. A bad abstraction would at least have had one fire in one place.

SkiFire13 3 minutes ago|||
> A bad abstraction would at least have had one fire in one place

That's true only for "good" abstractions. Bad abstractions will often require you to change code in all the places using it, requiring you to understand how all of them work and what are their requirements, _all at the same time_.

swader999 9 minutes ago||||
The article isn't saying don't dry, it's saying don't force dry. Very big difference and you get ideal maintainability when you ease off a bit but still use it.
davidee 1 hour ago||||
Good faith question: would it?

Wouldn't most large codebases with poor abstractions just have engineers engineer around them with their own solutions? In a large enough codebase you'd have both the bad abstractions and all the not-quite-duplicate implementations ignoring the bad abstraction?

I'm using bad here loosely, it could be buggy, incorrect, incomplete, insufficient and more; while being owned by someone or some team that's a challenge to work with for various reasons (overloaded, under-resourced, overbearing, etc., etc.).

dofm 52 minutes ago|||
> Wouldn't most large codebases with poor abstractions just have engineers engineer around them with their own solutions?

Obviously, yes. But it is my experience that this happens more slowly and that API invocations that break when the abstraction is changed are much easier to identify than broader duplicated patterns of code that span many lines and subtly diverge.

And even then those divergences are better because each wrapper around the abstraction is documenting the problem with it. But the abstraction can generally be replaced by one with the same API surface.

(Even if you take into account the fact that any API behaviour ultimately gets relied upon even if undocumented. Which is true.)

To be fair my experience is that of a freelancer and contractor who arrives trying to fix things that have been through many such hands. And I think if these developers had it drummed into their head that any attempt at abstraction would be better than copy and paste, these situations would be more knowable.

jcgrillo 21 minutes ago|||
> engineers engineer around them with their own solutions

When that happens there's a major engineering leadership failure currently in progress, even if engineering leadership isn't aware of it.

grayclhn 17 minutes ago||||
IME a bad abstraction results in the same thing, just with a lot of wasted effort coming up with the abstraction first, and a lot more resistance to fixing it because people are too emotionally invested. I’d rather have something clearly chosen for expedience and that no one likes.
coldtea 48 minutes ago||||
>A bad abstraction would at least have had one fire in one place.

On the contrary: that's precisely what a bad abstraction would not offer.

Instead it would spread its assumptions to different parts of the system, as every caller, sub-service, etc. would have to change shape to fit in that abstraction's box, however unnatural it is (and we know it would be unnatural, because we already said it's a bad abstraction).

Abstraction is not the same as encapsulation.

dofm 33 minutes ago||
> instead it would spread its assumptions to different parts of the system,

But so does duplication, in practice, and it diverges more as it does.

coldtea 15 minutes ago||
Duplication is just code doing the same thing in several places, and as such it's much easier to make DRY (and much easier after you have N copies to see what should be shared and what should not), compared to re-architecting the whole system to remove a bad abstraction.
rpdillon 59 minutes ago||||
In your mind, what's the cost of the wrong abstraction?
dofm 43 minutes ago||
The major risk/cost is breakage if you must change it but cannot maintain its whole surface even with a shim, right?

But any abstraction ends up with a signature and a name that can quickly be found in code.

The risk of a long-lived duplication losing its shape and being hard to find is much greater. Especially if the code is going through multiple hands.

I once had to pick up a project — a working, fully functional website. I could see, pretty clearly, the work of several people. All but one of them terrible.

The one was a diligent developer who was fully wrong in their abstraction (in fact significantly) but was consistent in how they used it.

The rest had simply worked around that code, copied and re-copied their own modified duplications and let things lose any shape. The result was error-prone stuff.

Clearly either the budget (or the client's capriciousness — a separate issue and arguably the bigger one) scared away the one guy, who I actually wanted to talk to but could not track down. He possibly had the origin story, and I wanted to know why his particular abstraction, which was at odds with the framework, was there. It was good code in the wrong shape, and it clearly used to do more, and that is interesting.

All the expedient people who had decided to avoid his code and just patch in duplicated pieces around it were the problem. There was no form to their solution at all. And that had clearly happened over some time (because you could see several different code styles)

rubyn00bie 33 minutes ago||
I am confused by this comment. The root problem was the wrong abstraction was implemented. Then it was duplicated. Had there been no abstraction, it would not have been duplicated so readily? Am I missing something?
dofm 32 minutes ago||
I will reword it slightly, I typed too fast.
rubyn00bie 38 minutes ago|||
The same problem exists, and I think is unfathomably worse, when the wrong abstraction is used throughout a code base.

Abstractions are a form of coupling, and coupling can be good, if the components are truly interdependent, and have a well defined domain. The problem with most abstractions, and I’ve seen this time and time again, is that they become brittle, are over used, and the cost of maintaining them grows exponentially with the size of the code base. With the reason for the cost ballooning being the system has disparate components that look interrelated but are absolutely not. Once you give someone a hammer they tend to assume everything is a nail.

The biggest problem, IMHO, is that abstractions are often used where a pattern would be more effective, easier to maintain, and easier to iterate on. And the primary difference between a pattern and an abstraction really comes down to coupling. Patterns remain decoupled, abstractions are tightly coupled.

And to be clear, I will and do use abstractions, when and where they make sense. But only after clear patterns emerge, and it’s been proven that components are truly coupled.

I will gladly die on the hill, that abstractions are measurably worse than duplication an overwhelming amount of the time. They’re often nothing more than a form of premature optimization.

zingar 21 minutes ago||
What’s the difference between a pattern and an abstraction?
shinycode 1 hour ago||||
At work there’s been a huge number of duplication in the start of the company and no solid abstraction. So no tests as well. We introduced tests in the current architecture but rewriting code has a huge cost to make sure there is no regression. When we talk about a saas it’s non-trivial with many customers relying on this tool daily as part of their workflow, regressions because of rewrite could be really painful for them. So we must give a greater budget to take the time to make sure nothing major breaks. So there is a debt that is compounding over time because code is added. Duplication is bad and weird/purist abstraction could make the architecture so rigid that rewriting things could generate hard to understand and catch bugs. It’s hard to find a good balance and it depends on the kind of business and scale of project. Hard to make that a generic advice.
ghosty141 38 minutes ago|||
I think all these comments here are kinda talking past each other.

It all depends on the amount of duplication and the complexity of the abstraction. Like you said, no generic advice is possible that clearly separates it into "abstract here" and "duplicatehere".

In your example it sounds like we aren't talking about 2-3 places where duplicate code existed that just needed to be refactored into separate units. It sounds more like a complete disregard for abstraction to move on quickly.

If you see duplicate code and have a good understanding how to solve that then it's totally a good thing. The real problem comes in if you add abstractions without knowing wether they will hold up. And this is where the blogpost comes in. In my opinion 2 duplicates are fine, at 3 you should start thinking or implementing an abstraction if you have a good understanding of the code and usecases.

chairmansteve 49 minutes ago|||
"It’s hard to find a good balance and it depends on the kind of business and scale of project".

Exactly. The abstraction purists are not working in the messy, dead line driven real world.

pfannl 12 minutes ago||||
The real rule is probably: duplicate until the abstraction stops looking like a horoscope.
bluefirebrand 1 hour ago|||
Yeah, "Write Everything Twice" is a pretty common and sensible direction for any codebase
marcosdumay 32 minutes ago|||
It's sensible if you have strict control of your duplications. You do have strict control of what is duplicated and where, right?

Write everything twice quickly becomes write everything 4 times once a new change appears, just as quickly as it becomes write everything 8 times, and so on.

I'm afraid there's no sensible soundbite developers can follow blindly.

coldtea 12 minutes ago||
>Write everything twice quickly becomes write everything 4 times once a new change appears, just as quickly as it becomes write everything 8 times, and so on.

That's a good problem to have. Getting to 4 or 8 or 12, and then pruning it to 1 or maybe 2 or 3 clearly different cases, is better than shoehorning multiple cases into the wrong abstraction, having everything that speaks with them coupled to that and dancing around their assumptions, and then having to untangle that.

Duplicated code is by definition LESS coupled.

cwmoore 1 hour ago|||
Yeah, ~"Write Everything Twice"~ “Copy and Paste Working Code” is a pretty common and sensible direction for any codebase
lanstin 27 minutes ago||
In C I used to make it so my standard per-file and per lib code could be cut and pasted to other files/libs without modification. (E.g. every file had a mLocal variable that was file-visibility symbols, every module had a #module define for logging, there was always a mLocal.stats member, etc. ) I think some of this duplicate vs. abstract depends on your languages expressiveness - Rust or Lisp with good compile type power make it possible to squeeze out a lot of duplication that in less expressive languages are just idioms - here’s the five lines to make a syscall, or here’s the skeleton of parsing a portable network buffer into a native object.

Having a lot of if/else in your code is definitely a cost. My weakness isn’t so much the libraries and APIs, but the actual binary - once I have a service that does A very well, and I run into needing A’ I mostly just add in a config line “op_mode = A|A’” and have the else/if chains in the server driving code. Moreso for CLIs that I use myself than production services, but I have added tunables for consistency and replication to datastores to allow new use cases and expand my footprint in the data center.

fny 1 hour ago|||
Code duplication is cheaper than the wrong abstraction. If you have a good abstraction, you should run with it.

If you haven't figured out a good abstraction at 5-100 customers, God help you.

feoren 53 minutes ago|||
A good abstraction? As in one? I'd go so far as to say the process of discovering and refining abstractions is the most important part of software engineering. A large project has dozens of abstractions, and some of them are "wrong" at any time, as you discover over time. None are ever perfect. If you wait to stop duplicating code until you have the "right" abstraction, you are just putting off the hard part of developing software and taking on tech debt.

Half of your abstractions are wrong. The hard part is knowing which half.

lanstin 25 minutes ago|||
I once worked at a place with abstractions I found to be beautifully perfect. The people that wrote the base framework had done similar things two or so times previously and got it right the third time. You couldn’t write slow or hard to operate code there without really trying hard.
meerita 45 minutes ago|||
Good abstraction does one single thing and does it well. Bad abstraction starts from the premise of becoming a dumping ground. If that is the case, the best and ideal scenario is splitting the abstraction into many ones to make the job better.
stymaar 44 minutes ago||||
> Code duplication is cheaper than the wrong abstraction

This is tautological though, it's like saying “starving is much better than eating the wrong food” (for instance: eating quick lime).

Of course you'll always find a way to do things wrong in a way that is costlier than not doing anything.

blauditore 12 minutes ago||
Sure, but obviously that sentence implies that wrong abstractions are fairly common.
enos_feedler 52 minutes ago||||
What if there is no good abstraction for the entire stack of software on each of computers? What if we built a common one because we had to? What if now we get to all make our own with natural language?
dofm 1 hour ago||||
I disagree.

But also it's very possible to not realise you needed an abstraction until it catches fire in multiple places.

And quite often it's not you that got the codebase to a hundred customers, is it? Sometimes it is a sequence of fresh-faced young developers who didn't have the authority to say "this duplication is bullshit" and were instead compelled to repeat it.

I think a lot of these discussions happen in nice little blog-post vacuums of progressive thinking, where people can go "mmm, object oriented coding obscures intent and clarity, mmm", blog posts with "an X is a Y", "the unreasonable effectiveness of foobar" etc.

In the real world, every duplication that works sticks for good; there is rarely budget to electively replace code that isn't broken. Until one day it doesn't work. And then… how many times is it actually duplicated? How many of the duplicates diverged? How many of these do we no longer need?

chairmansteve 54 minutes ago||
> I disagree.

So... the wrong abstraction, no matter how bad, is better than code duplication?

dofm 39 minutes ago||
If you read my original comment I said pretty much this, yes.

> I would go as far as to say that any abstraction you can maintain (that is in active maintenance, I mean) is better than code duplication once you are past a de minimis threshold.

I appear to be in a solid minority thinking this. But I'm OK with it. I'm probably not going to write a blog post.

locknitpicker 28 minutes ago|||
> If you haven't figured out a good abstraction at 5-100 customers, God help you.

This blend of opinion is very naive. Every single project is a business requirement away from having the wrong abstraction in place.

https://xkcd.com/1425/

ubertaco 10 minutes ago|||
I'd recommend clicking through the headline to watch the talk. Metz talks a lot about types of similarity: similarity by coincidence vs similarity due to an actual semantic or functional equivalence.

Code that is coincidentally similar very often diverges in either the short or long term, and DRYing it up aggressively tends to result in functions that have many boolean parameters that each trigger disjoint sets of behavior - which is a bit of a nightmare to maintain due to the high cognitive overhead of remembering how all the interleaved-but-actually-unrelated behaviors should work.

This outcome is low-cohesion code.

It's a useful concept to be aware of - worth clicking through to the actual content of the talk rather than just the headline.

mytydev 1 hour ago|||
It sounds to me like you are describing a good abstraction. This article does not claim that code duplication is better than any abstraction. It claims that code duplication is better than the wrong abstraction. I'm sure this author would agree that a good abstraction is better than code duplication.
dofm 1 hour ago||
I'm afraid this comment reads in a rather gnomic way.

Of course it's a truism if you just say any abstraction that works is a good abstraction.

That is not what I am saying at all. Bullshit abstractions at least let you control the problem. Duplication doesn't.

vlunkr 58 minutes ago||
But it’s never going to be 1:1 duplication is it? Sometimes it’s better to copy code as a template for something new, rather than try to immediately force a new abstraction.

I agree with you that it’s a truism, but it’s useful advice for people who have a habit of trying too hard to DRY their code. IIRC the author comes from the Ruby world, where DRY was a big thing, and this talk was part of the pendulum swinging back away from this DRY obsession that sometimes just resulted in convoluted code.

ChrisMarshallNY 58 minutes ago|||
In my experience, the answer is always "It Depends." That's about the only thing that I can hang "always" on.

It really depends on the exact type of code we're working with, and what our objectives are.

In my case, I often use object inheritance. It's a damn cheap way to DRY. However, when people hear "inheritance," they often think "polymorphism." There's a really big difference between the two, but popular culture has jammed them into one ball, and it's not worth the agita, to try to explain the difference.

But if you are doing optimization, long stacks can be your enemy, and inheritance tends to have long, windy stacks.

In these cases, the copy/pasta method may well be the best approach.

Like I said, "It Depends."

agumonkey 1 hour ago|||
You seem to have experience, I dont mind factoring / unifying logic, when done sensibly with enough history in the trenches. It pains me more whenever a young dev comes in and barks "we must merge these two things!" repeatedly without planning for more than two cases and starting to add more and more boolean variables. Crystal makers. Then the obvious issue comes, the two variants weren't that close and now there's one god class trying to handle all forces in one big state.

I agree that LLMs are naturally anti abstraction machines.. I'm often trying to find way to reverse that.

dofm 1 hour ago||
> I agree that LLMs are naturally anti abstraction machines.. I'm often trying to find way to reverse that.

I am a bit of an LLM cynic but I am trying to learn it all, and I have to say I have spent most time trying to work out: how do you explain how a brown-field codebase actually works, in such a way that the LLM won't pervert it through misunderstanding.

It does encourage you towards the "conventional" coding standard for any new project, because you want to use a pattern that it will have seen in its training set.

But for example there are differences of opinion in how wordpress plugins (which have a very complex control flow) should be structured. LLMs are incredible at knowing how WP works, actually, but what is difficult is explaining how your methodology for a large plugin is going to work.

It is a battle — but a useful one because it can be used for, er, studying the comparative belief systems of the LLMs.

wonnage 51 minutes ago||
They don’t have a useful belief system, one of the rookie mistakes of using LLMs is asking them what you “should” do
dofm 35 minutes ago||
Absolutely. I think the bit I still struggle with is finding a way to get them to join my team (which is a team of one very tired person).

A story I like is that in the now lost era of handwriting recognition on PDAs, Jef Raskin concluded that the easiest way to solve the problem was to change handwriting so as to meet the algorithm in the middle.

That is, to find a noticeable simplification of handwriting that people could learn quickly and that eliminated hard-to-process quirks.

I feel I am there with the LLM at the moment, trying to work out what the common ground is.

mawadev 1 hour ago|||
I think you applied this idea into the era of LLMs but consider an abstraction that takes in multiple god structs for branches it may or may not call in the case you are looking at and has a lot of if conditions that explode in combinatory complexity across a deep call chain. Now the bottle neck is that you need to call this function 144 times a second. That is where you start to have clusters of hot code paths where the latency stacks depending on the angle the god structs come in. Not sure what LLMs do here, I don't vibe code
dofm 1 hour ago||
I am applying it to LLMs on the basis of twenty years of seeing smaller programming shops tie themselves in knots by using duplication to avoid developing an abstraction that would help them because they were unsure of it.

Everyone always thinks duplication is fine when you can bill the modifications by the hour. But they never think to understand that the reason they've had so many employees is that they've turned their change process into firefighting all the different versions of the same code and all these young developers burn out from the sheer anxiety of not knowing where all the little fires are.

I once had to rescue a site that had become a victim of its own popularity, that was written by subcontractors who clearly believed that duplication is better than the wrong abstraction.

Until one day, along came a change — MySQL 4 to MySQL 5 — and a significant duplicated query no longer worked due to its new, proper strictness.

The problem was compounded; not only was the broken pattern in hundreds of places where it had sat, stable and predictable, but the pattern was broken because it, itself, was avoidance of another abstraction that would solve it.

They quit: they said they couldn't and wouldn't fix it. It had always worked how they had done it, and it would have to stay on MySQL 4 (which the hosting provider refused to accommodate).

I don't think it helped that they were severely misguided in their understanding of SQL, but the code had become beholden to duplication and then crippled by a new problem in the duplicated pattern.

I had to first find all the contexts in which that pattern appeared (which required me to spend half a day on a bespoke script) and then work out a new pattern and as few variations of it as possible to fix the duplicated code in each place, because there was no proper budget to rewrite the whole thing. And then I sat at my desk, for days, working through each one, figuring out how to change it to fit the slightly different expression of the pattern.

Even a total bullshit abstraction would have saved that client both time and money. And this is only one of dozens of times I've seen small firms simply duplicate and change code that would later become unmaintainable because of a straw breaking a camel's back.

Capricorn2481 1 hour ago||
Again, this is the opposite of what the author argues for, which is waiting for a couple instances before committing to an abstraction. Not duplicating a SQL query across hundreds of places.

I would be curious if the previous coders you're talking about actually cited duplication as a good thing. You seem to be implying they are. But almost every instance I've seen of massive code duplication was just from bad programmers shooting from the hip, not from some ideological stance.

dofm 1 hour ago||
> Again, this is the opposite of what the author argues for, which is waiting for a couple instances before committing to an abstraction. Not duplicating a SQL query across hundreds of places.

Right. But this is a hypothetical, in-a-vacuum situation.

In the real world, your two, three duplicates are in production.

"We really should now de-duplicate this"

"There is not the time or budget, just copy it again; we'll replace all this one day".

nfw2 1 hour ago|||
Over-engineering and "abstraction hell" are very much not iconoclastic concepts
Capricorn2481 1 hour ago|||
> I would go as far as to say that any abstraction you can maintain (that is in active maintenance, I mean) is better than code duplication once you are passed a de minimis threshold.

Pretty much everyone arguing for duplication has argued what you are saying, which is wait to see a few instances of it before committing to an abstraction. No one is saying duplicate everything 100 times. So I don't think this discussion was ever iconoclastic.

dofm 1 hour ago||
The point is it sounds all smart and sophisticated and principled in the abstract environment of a code discussion in a blog post.

In the real world, duplication happens in an emergent way, there isn't the time each time to judge whether it's really time to just quietly abstract that code, you may not get the permission, budget or window to do it, and if you don't stop the rot really early you are locked into the pattern.

Thaxll 46 minutes ago|||
So you centralize 3 liners?
dofm 21 minutes ago||
I said "beyond a de minimis threshold".

But in one of the scenarios I mention earlier, I earned a chunk of money once fixing an issue that emerged in a subcontractor's four or five line duplication that had ended up rippled through a long-lived codebase. A ground truth (MySQL version) changed, and the pattern broke everywhere, including places where it had evolved.

So I tend towards thinking, yes, any three-line pattern that is likely to appear everywhere should, perhaps, be centralised.

It's certainly worthy of serious consideration. Usually pretty easy to maintain the surface of such an abstraction.

thinkloop 40 minutes ago|||
The key lesson is that duplicate code is not necessarily "code duplication" - it was always really about abstraction duplication. If two unrelated variables happen to momentarily share a value, it doesn't mean that value should be made common between them, they are fundamentally different things. It would be a confusing lie and error-prone if the code implied they were the same and that efforts should be made for them to be in sync.
dofm 34 minutes ago||
I guess any blog post can remain true if you can optionally take one of the key terms and redefine it so it can also mean the opposite?
jimmypk 38 minutes ago|||
[flagged]
tracerbulletx 1 hour ago||
Huh? If anything having lots of customers makes the argument for duplication stronger. The issue is almost always once you get huge and 5 product teams are trying to achieve 5 different goals by using the same overwrought abstraction instead of just copying and decoupling. The abstractions that are actually stable end up becoming libraries or platform team owned systems that no one ever really touches.
irishloop 1 hour ago||
Too many abstractions are bad. Too many code duplication is bad.

Part of being a good engineer is finding the right balance.

I know engineers who would gladly duplicate code all over the code base to avoid creating a new abstraction.

I know engineers who create polymorphic abstractions for a single caller with a very obvious set of parameters.

So much of wisdom is in finding balance and not being dogmatic about rules.

lokar 1 hour ago|
I feel like the balance has shifted over the last 30 years, and is speeding up. Semi-automatic and fully automatic re-factoring has made dealing with duplicated code much faster, cheaper and safer. Changing abstraction is still high risk.
chuckadams 56 minutes ago|||
I have regularly watched agents forget to update one duplicated pattern after changing it somewhere else. If it's within a single file or related class, it'll catch it, but if it's off in some other package in the monorepo, it's a crapshoot.
heisenbit 1 hour ago|||
Changing abstraction is a high risk unlike agents refactoring scores of almost identical code.
lokar 1 hour ago||
I thought this discussion was limited to situations where you care about code quality
lg5689 1 hour ago||
I believe that "single source of truth" is a principle that should always be followed. If there's duplicated code where it'd be a bug if they diverge, then you should refactor. It creates a long-distance coupling in your code that may be invisible to future developers until a bug emerges.

But with that in mind, I mostly agree with the article: if it's not a violation of "single source of truth", then abstractions are just a convenience. If it starts being inconvenient, then it's not doing its job and there's no reason to use it. It's a serious code smell if a function needs several flags for custom behavior; that means it's probably the wrong abstraction or violating the single responsibility principle. If there is a legit need for lots of customization, an often-good way to handle is to take a function/functor as an argument for the customization. E.g., rather than `solve(f:double -> double, max_iters = 99, x_abs_tol = 1e-15, x_rel_tol = 1e-15, ...)` you can do `solve(f:double -> double, stopping_criteria: StoppingCriteriaClass)`

bhouston 1 hour ago||
I used to struggle with abstractions back in my OOP days but since moving pretty much to a purely functional approach I find that code duplication is rare. Just have a function and call it in two parts. The main abstraction issue is then data structures but with TypeScript interfaces being duck typing essentially I run into few problems there as well.

So code duplication because of abstraction issues is rare. Code duplication because of siloed developers is so much more common.

kccqzy 5 minutes ago||
Developers do not really have to be siloed to experience code duplication. When the team size grows past a certain point such that each person is not aware of what every one else is working on, code duplication is quite inevitable. This is the case even if everyone writes functional style code. In fact this just happened last month at work: I wrote a new functional and pure helper function and placed it at the beginning of the file; a week later a colleague told me a similar helper function with substantially the same functionality with a different signature had been written and placed near the end of the same file.
ikety 1 hour ago|||
For hobby, I use functional languages, and I find the techniques are the important bits to remember. Most modern languages let you easily stand on functional programming theory. You don't need to know Haskell. Everyone's brain works differently, but the idea of small, simple and occasionally flexible parts building a whole works for me. As opposed to the large complex do it all shape shifting machine.
platz 1 hour ago||
what exactly is 'calling a function in two parts'
saghm 1 hour ago|||
I assume they mean to call the function from two (or more) parts of the code (i.e locations). It's not immediately apparent why this is meaningfully different than what would be possible in Java though, since ostensibly a function is the same as a method by just moving the callee to the list of parameters. (There are some things in a Java method that you can do that don't translate to most functional languages, like invoking the version of the method from a superclass, but there's nothing forcing you to do any of those from the language perspective, so it seems a bit strange to claim that the language itself is the issue rather than maybe the specific patterns that were chosen, maybe by their coworkers or just not common in the ecosystem).
bhouston 29 minutes ago||
You can do functional in any language. I haven’t designed a new class in years in TypeScript and I’ve been more productive as a result.
bhouston 30 minutes ago||||
Calling a function from two locations is what I meant.

Basically since moving to a functional approach in typescript I find I do not fight abstractions as I used to when I used classes and inheritance.

lysium 1 hour ago||||
I read it as „calling it from two places“
odo1242 1 hour ago|||
I believe they’re referring to callbacks / dependency injection / higher order functions to customize the behavior of a function?
bhouston 28 minutes ago||
Mostly just function calling to reduce duplicate code. Dependency injection does start to get abstraction costs again. I use it when necessary but it is annoying and costly when I do.
strongpigeon 1 hour ago||
Echoing the article, anyone who has experienced both will agree: it’s far easier to work with an under engineered code base than an over engineered one.
Rendello 1 hour ago||
Two talks come to mind here: Mike Acton's Data-Oriented Design and C++ [1] and Brian Cantrill's The Complexity of Simplicity [2].

Mike's talk argues that code solutions need not be modelled on the real world, and that different data creates different problems, which need different solutions. I can't do the talk justice, but it's had a big impact on me.

Brian's talk is about abstraction generally, and how it's difficult to find the "right" abstraction.

1. https://www.youtube.com/watch?v=rX0ItVEVjHc

2. https://www.youtube.com/watch?v=Cum5uN2634o

saghm 1 hour ago|
> Mike's talk argues that code solutions need not be modelled on the real world, and that different data creates different problems, which need different solutions.

I've always found it odd when even fairly smart engineers sometimes prioritize real-world metaphors over the actual needs of the codebase. Years ago when I was only a few years out of school, I was implementing a connection pool in Rust, and the most reasonable way to implement it was to have the connection hold a weak reference to the pool so that it could get checked back in automatically when dropped. My manager (an extremely experienced engineer) didn't like this idea because "a library holds library books, not the other way around". I didn't feel like this was a compelling reason to design things differently, but he refused to engage with the issue in any way other than through the lens of that metaphor. Eventually the impasse was solved by one of the other managers in my department suggested that while library books don't contain libraries, they do have the name of the library stamped in the back as a reference to where they should be returned, and I guess my manager found this to be a reasonable extension of the analogy. If I were more experienced, maybe I would have recognized that I could find a way to engage with the analogy like the other manager did without ceding the point, but even today I still feel that it was completely bizarre to insist on that as the canonical way to frame things rather than just considering the ramifications of the abstraction in the code and the experience of using the library based on it.

znkr 1 hour ago||
+1 The worst code I had to maintain was code that tried to follow DRY (without the trying to understand what the original intention of that principle was). The only way out of that mess was widespread code duplication.
agentifysh 1 hour ago||
i recall very early in my career i did exactly this. i took what worked duplicated it—my reasoning being that it was far safer to reuse what has been battle tested and leave refactoring at a later stage

it wasn't received well and senior developer told me that 'good developers know exactly what patterns to use all the time before writing any piece of code and that he will clean up my mess'

long story short his refactoring caused what was otherwise a stable system into a complete mess and it reminded me of Nassim Taleb's book

nicoburns 1 hour ago|
It's definitely an "it depends" thing. It's easy to overabstract. On the other hand, I've also met junior developers who just didn't know how to use function parameters.
cryo32 2 hours ago||
You can do both with microservices!
mohamedkoubaa 51 minutes ago||
Please, stop it
zephen 1 hour ago|||
But wait! There's more!

For $19.95, you can replace your single single point of failure with multiple single points of failure!

flawn 1 hour ago||
Or for 100$, get a 5x increase on all failure points - maximum vibes, maximum excitement.
DJBunnies 1 hour ago||
Except 9/10 times microservices end up wildly dependent on each other, yielding a distributed monolith. Better to use service oriented architecture and just ship the monolith, you can test easier and skip the extra layers of serialization / deserialization.
loevborg 1 hour ago||
I think you missed GP's point
zephen 12 minutes ago||
Poe's Law FTW!
time4tea 25 minutes ago|
You dont know immediately if something that superficially seems the same actually is.

Copy and paste once is fine, twice, not so much.

Often I've seen two totally different things exist in one bit of code, no overlap!

Premature generification is bad, and leads the developer to believe that two things are the same, making it harder to see they are not.

Also, can make it much harder to see that a different abstraction would give a cleaner outcome....

More comments...