6 ms·
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
by lg5689 3mo 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)`
- jonahx 3mo ago> 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 3mo agoThe 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.
- jonahx 3mo agoYes, this is true. And is a bigger problem on large teams. One mitigation is a comment by the original author at both sites that there may be a coupling in the future. But, again, the point is that you don't know yet whether you have a single source of truth or not. It's a question of the relative badness of duplication vs premature abstraction in cases where the code may diverge or converge in the future. There is no generic answer. But as a heuristic, based on my personal experience, I have always found premature abstractions to be more painful to work with. Even more so when someone else has authored them.
- ytoawwhra92 3mo agoFor pure logic I find refactoring to enable divergence much easier than implementing convergence.
- usrusr 3mo agoNot only easier finding call sites than finding copies, also more intuitive to start looking. "Which callers will be affected by the change?" is the most natural question to ask. "Which places should have this same change applied?", not so much.
- Maxion 3mo agoA lot of the time in my experience this comes down to coders thinking the logic is the same and abstracting something to a central source, when from a business perspective the rules are similar but actually different. So many times I've had to untangle these types of abstractions when business asks for changes to case X but not Case Y. OR worse, business asks for changes to case X, but it also affects Case Y due to abstractions. Business see X/Y as different things so did not even think to mention that the new suggested behavior is to only affect case X, but to coders they're the same.
- ketozhang 3mo agoThis assumes the bug exists in both places which might not be true at all even if they both are dependent on the same duplicated code. If you only spot the bug in path A and not path B, why fix the bug for B?
- kread 3mo agoI totally agree with you. If "single source of truth" was possible in every situation, I wouldn't have been confused about first name and last name. When someone asks me first name, I always get confused whether I say first name in Korean or first name in English. I think there are two sources.
- fpoling 3mo agoWith LLMs the cost of duplication is much lower and LLMs
- cluckindan 3mo ago> and LLMs … sometimes duplicate things unnecessarily.
- at_compile_time 3mo agoor stop midsentence
- storus 3mo agoWhen you run out of tokens, you run out of tokens!
- sscaryterry 3mo agoThe struggle is real.
- robotresearcher 3mo agoWould you like me to outline some concrete steps for dealing with the struggle?
- lossyalgo 3mo agoWe would love to, but we ran out of tokens.
- mdavid626 3mo agoOf 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 3mo ago> as if duplication would be the root of all evil And instead it gets replaced with the actual root of all evil, complexity.
- mdavid626 3mo agoExactly!
- kimtan21 3mo ago[dead]
- Akronymus 3mo agoTo be more specific, incidental complexity. Many problems have tons of inherent complexity already.
- ttoinou 3mo agoWe 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 3mo agoMy metric for that is "does that code MEAN the same thing" or "does it just look the same". Has worked quite well for me so far. I frequently find myself making a copy of some code rather than adding a parameter (most commonly done with code that would get some flag added)
- jackbucks 3mo agoI 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.
- nnoremap 3mo agohttps://en.wikipedia.org/wiki/The_Library_of_Babel https://en.wikipedia.org/wiki/The_Library_of_Babel
- pocksuppet 3mo ago> universal network invocable function tree https://www.wikifunctions.org/ https://www.wikifunctions.org/ btw
- alberto467 3mo agoCode 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).
- threethirtytwo 3mo ago[flagged]
- dang 3mo agoYou crossed into personal attack here. Please don't do that on HN. https://news.ycombinator.com/newsguidelines.html https://news.ycombinator.com/newsguidelines.html Edit: could you please not post flamebait generally? You've been doing it in other places with this account as well, and we end up banning such accounts.
- thrownthatway 3mo ago[dead]
- QuadmasterXLII 3mo agoOne killer life hack I’ve found is, if extreme duress pushes software into two sources of truth, add a ci test that wont merge into main till the sources match. The canonical case of this actually being the best solution is pyproject.toml / requirements.txt synchronization, but I suspect it has broader applicability. A precondition is that things have already gone off the rails far enough that single source of truth is unattainable, this is more harm reduction than cure
- uberex 3mo agoI know it is just an example but I'd generate one of those files from the other in that case.
- QuadmasterXLII 3mo agoThat’s the obvious correct solution, I and many others have tried to make it work for a very long time. The python tooling is or at least was F’d enough that pure generate one from the other is a steady stream of disasters. What works well is to generate one from the other and check the generated one into source control, and then verify that the checked in generated copy stays up to date using a CI job. But that’s very similar to the “two sources of truth, verified sync” approach
- infinitebit 3mo agoi don’t think anything in the article advocates for not prioritizing “single source of truth”, as in, if we know that there are multiple sources of truth for something, it should absolutely be deduped. the article is more saying “be a bit more skeptical of any two pieces of code actually representing the same thing” and “be more willing to break apart an abstraction that is trying to represent multiple truths.”
- jamiejquinn 3mo ago> it'd be a bug if they diverge That's a very nice rule of thumb. I've often overabstracted when two pieces of code look similar at one point in time and then they diverge.
- shhshahja 3mo agoIf you knew in advance which source of truth is important to isolate you don’t have this problem. The problem is not knowing which of the hundreds or thousands of potential truth sources is worth abstracting. The only real way of finding out is not abstracting them and seeing how it works out. If the problems in SWE boiled down to solve(f -> MagicallyNoProblemAnymore) we wouldn’t have this discussion.
- janpmz 3mo ago> If they diverge This is the key, if they are very similar but used by different consumers the chance that they will diverge in the future is very high. And once they do they will break the abstraction.
- tcfhgj 3mo agoYou can still duplicate then Ctrl+c, Ctrl+v
- namelosw 3mo ago> I believe that "single source of truth" is a principle that should always be followed Theoretically and conceptually I agree. But in practice there are a lot of programming languages aren’t as expressive. People prefer codebases with duplications rather than visitor patterns everywhere. In essence, visitor pattern is a tool to solve multi-dimensional abstraction problems, just like type classes in Haskell or CLOS in Common Lisp. But it’s so verbose and non-straightforward so more often than not it’s not worth it even conceptually it’s a legit case for “single source of truth”.
- gf000 3mo agoVisitor pattern is there due to a very simply reason. You have n datatypes with m functions. FP languages makes adding a new row to this nm table easy, OOP languages makes adding a new column easy (that is, without changing every* use site as well). Visitor pattern makes the row addition case possible for OOP languages, that's it.