Remix.run Logo
lg5689 3 hours 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)`

mdavid626 41 minutes ago | parent | next [-]

Of course, in theory this is true. In practice people tend to avoid ANY duplication no matter what. Especially junior developers, as if duplication would be the root of all evil.

jihadjihad 38 minutes ago | parent | next [-]

> as if duplication would be the root of all evil

And instead it gets replaced with the actual root of all evil, complexity.

ttoinou a minute ago | parent | next [-]

We still need a way to track that there’s some common pattern in the code. So that when we update one pattern we wonder about the others places in code with the same pattern. Avoiding duplication doesn’t solve that

Akronymus 19 minutes ago | parent | prev | next [-]

To be more specific, incidental complexity.

Many problems have tons of inherent complexity already.

mdavid626 19 minutes ago | parent | prev [-]

Exactly!

wellpast 2 minutes ago | parent | prev | next [-]

Definitely the hallmark of junior. Obsession with code deduplication as the highest pri when it’s quite low among others.

the_af 32 minutes ago | parent | prev [-]

This is something I've seen repeated time and time again as a criticism of (misused) abstraction and DRY, yet I've never seen ONCE -- and this is not hyperbole, I mean it literally -- a junior making an abstraction with any thought to reuse, generalizing anything, or caring about not repeating code. Most juniors I've worked with are content to just churn new code without paying attention to the codebase at all. This all before the AI deluge, mind you.

Very similar with patterns. I've often read people protesting that juniors overuse design patterns, yet I've seldom seen a junior (mis)use anything more complex than a singleton, and when they use any pattern, it's usually forced upon them by an opinionated Java framework.

robotresearcher 4 minutes ago | parent | next [-]

In the early 2000s I often saw juniors and students make staggeringly deep class hierarchies. The equivalent of:

Shape::Polygon::ConvexPolygon::FourSidedConvexPolygon::Square::BlueSquare...

"Intro to OOP" lectures/articles made a deep impression on some people in not quite the right way :)

dasil003 15 minutes ago | parent | prev [-]

This smells more like the fluidity of what people mean by “junior” more than anything else. Journeymen engineers in their over-engineering phase, or even very “senior” expert programmers can suffer over fitting the product to their own mental model. The most senior judgment is to understand when an abstraction makes sense at a customer level, because that defines the durability of a business-logic abstraction.

the_af 13 minutes ago | parent [-]

I do agree this happens with the senior overengineering phase, but the comment I replied to mentioned "especially juniors" and I've heard this trope specifically about juniors, with the implication they want to apply what they learned in college, but this hasn't been my experience at all.

alberto467 12 minutes ago | parent | prev | next [-]

Code duplication differs from single source of truth applied to data in the sense that data is data but two pieces of code may functionally be the same (they do the same thing) but they might be semantically different in their usage (they’re advertised to achieve different things), in that case coupling them together with deduplication and forcing them to do the same thing doesn’t really make sense, and may make the codebase more difficult to work on in the future (especially in companies where different teams have responsibilities over different parts).

jonahx an hour ago | parent | prev | next [-]

> I believe that "single source of truth" is a principle that should always be followed

Fundamentally, the article addresses cases where it's not clear yet how many sources of truth there will be. Are the two spots in the code using the same algorithm, or slightly different versions? More importantly, will they change for the same sorts of reasons?

The title adage (correctly, imo) argues that making two different things the same will cause you more pain than making two same things different via duplication. In the latter thing case, the "damage" is just having to make the same changes twice, or doing a refactor to introduce the abstraction. In the former case, you have to keep adding to your abstraction, or undo it. Most crucially, it breaks "locality", which is the only property you really care about when making changes. I just want to make this change and not worry about side effects to unrelated parts of the system.

stanmancan 19 minutes ago | parent [-]

The issue with not having a single source of truth is not the fact that you have to update code in 2-3 places, it’s that you have to know to update code in 2-3 places.

Accidental divergence is the problem, not intentional.

jackbucks 19 minutes ago | parent | prev | next [-]

I have always believed what the article more or less states. But you have to remember, the primary and maybe only source of duplication in software is situational dependency (the other word escapes me for this). If there was a universal tree of software functions that could be accessed over a network no function would ever be duplicated and every function would be reused from a central tree. When you put 2+2 inside a method or function body you just duplicated code. or any code inside a method or function body.

This is why we have to have programs that duplicate code by doing anything like adding two numbers together or complex logic that is easy to create bugs when someone wrote it 40 years ago better. Because code reuse is mostly done on a very small scale.

Given thats the case when you start on a new React project as an example you are not reusing application code you are duplicating the react framework so you can duplicate every other web app in every sense except maybe the visual.

There is no such thing as full reuse and until we get to a universal network invocable function tree that can be extended only when its truly unique we never will. Maybe AI will do this. People cannot.

At the end of the day code duplication needs to exist to optimize for local correctness (or incorrectness) and speed and abstractions goal is not to provide pure reuse. Its to provide a place to "put your logic" that may be similar and has access to typical state that some kind of widget might typically need.

fpoling 42 minutes ago | parent | prev [-]

With LLMs the cost of duplication is much lower and LLMs

cluckindan 39 minutes ago | parent [-]

> and LLMs

… sometimes duplicate things unnecessarily.

at_compile_time 33 minutes ago | parent [-]

or stop midsentence

storus 14 minutes ago | parent [-]

When you run out of tokens, you run out of tokens!

sscaryterry 8 minutes ago | parent [-]

The struggle is real.

robotresearcher a few seconds ago | parent [-]

Would you like me to outline some concrete steps for dealing with the struggle?