Most active commenters
  • wruza(5)
  • dllthomas(4)
  • Aeolun(4)
  • thfuran(3)
  • mewpmewp2(3)
  • hinkley(3)
  • dustingetz(3)

←back to thread

361 points mmphosis | 85 comments | | HN request time: 1.311s | source | bottom
1. leetrout ◴[] No.42165704[source]
> It's better to have some wonky parameterization than it is to have multiple implementations of nearly the same thing. Improving the parameters will be easier than to consolidate four different implementations if this situation comes up again.

Hard disagree. If you cant decompose to avoid "wonky parameters" then keep them separate. Big smell is boolean flags (avoid altogether when you can) and more than one enum parameter.

IME "heavy" function signatures are always making things harder to maintain.

replies(17): >>42165868 #>>42165902 #>>42166004 #>>42166217 #>>42166363 #>>42166370 #>>42166579 #>>42166774 #>>42167282 #>>42167534 #>>42167823 #>>42168263 #>>42168489 #>>42168888 #>>42169453 #>>42169755 #>>42171152 #
2. thfuran ◴[] No.42165868[source]
I think it's especially bad advice with the "copy paste once is okay". You absolutely do not want multiple (even just two) copies of what's meant to be exactly the same functionality, since now they can accidentally evolve separately. But coupling together things that only happen to be mostly similar even at the expense of complicating their implementation and interface just makes things harder to reason about and work with.
replies(7): >>42166007 #>>42166141 #>>42166159 #>>42166278 #>>42166385 #>>42166712 #>>42187622 #
3. gwbas1c ◴[] No.42165902[source]
In those situations, you really have multiple functions intertwined into a single function. Refactor to give each caller its own version of the function, and then refactor so that there isn't copy & paste with the similarities.
4. bloopernova ◴[] No.42166004[source]
Can you recommend any refactoring tutorials or books that teach those kinds of lessons?
replies(2): >>42166079 #>>42166206 #
5. atoav ◴[] No.42166007[source]
My experience is totally different. Sure the popular beginners advice is to never repeat yourself, but in many cases that can actually be a viable operation, especially when you are okay with functions drifting apart or the cases they handle are allowed to differ.

And that happens.

The beginners problem lies in the reasons why that happens — e.g. very often the reason is that someone didn't really think about their argument and return data types, how functions access needed context data, how to return when functions can error in multiple ways etc, so if you find yourself reimplementing the same thing twice because of that — sure thing, you shouldn't — what you should do is go back and think better about how data is supposed to flow.

But if you have a data flow that you are very confident with and you need to do two things that just differ slightly just copy and paste it into two distinct functions, as this is what you want to have in some cases.

Dogmatism gets you only so far in programming.

replies(2): >>42167672 #>>42167872 #
6. leetrout ◴[] No.42166079[source]
Not specifically this, per se, but I HIGHLY recommend "A Philosophy of Software Design" by Dr. John Ousterhout

https://web.stanford.edu/~ouster/cgi-bin/book.php

replies(1): >>42166776 #
7. jajko ◴[] No.42166141[source]
The problem is, such decisions are taken in the beginning of the project when you are far from full picture. Then comes rest of the app lifecycle - decade(s) of changes, bugfixes, replatformings, data/os/cluster migrations and so on.

I've seen, and even currently work on stuff that has beautiful but hard-to-grok abstractions all over the place (typical result of work of unsupervised brilliant juniors, technical debt in gigatons down the line but its almost always other people's problem). The thing is, that code has seen 10 major projects, absorbed other stuff, meaning and structure of data changed few times, other systems kept evolving etc.

Now all those abstractions are proper hell to navigate and perform any meaningful change. Of course another typical brilliant 5-second-attention-span junior result is complete lack of documentation. So you see stuff happening, but no idea why or why not, what does it mean down the line in other systems, why such choices were made and so on.

These days, I've had enough of any-design-patterns-at-all-costs kool aid and over-engineered cathedrals for rather trivial stuff (I think its mostly down to the anxious ego issue but thats for another discussion), I am more than happy to copy&paste stuff even 20x - if it makes sense at that place. And it does surprisingly often. Yes its very uncool and I won't brag about it on my next job interview, but it keeps things refreshingly and boringly stable and surprisingly also easier to change and test consequences, and somehow that's the priority #1 for most of the companies.

8. ninkendo ◴[] No.42166159[source]
Every time you consider copy pasting, you should be asking yourself “if the stuff I’m pasting needs to change, will I want both of these places to change?” It requires some guessing the future, but usually it’s not hard to answer the question.

IME if something should be an independent function or module, I rarely get to the point of considering copy/pasting it in the first place. If I want to copy/paste it’s usually because the two places currently only incidentally need the same code now, and my gut usually tells me that it will no longer be the case if I have to make any sort of change.

replies(2): >>42166595 #>>42167550 #
9. jprete ◴[] No.42166206[source]
Not the GP but I think a foundational skill is naming things. If you can't give a simple name to a function/class/etc., it's probably not well-defined. It should be adjusted to make it easier to name, usually by moving responsibilities out of (or into) the code structure until it represents one concept that you can clearly state as a name.
replies(1): >>42166451 #
10. zombiwoof ◴[] No.42166217[source]
Super rock hard agree with you and disagree with the author

I have seen so many terrible projects with methods with endless arguments/paramters, nested object parameters the signatures are fucking insane

The biggest stench to me in any project is when I see a majority of methods all have > 6 arguments

To quote Shoresy: so dumb

replies(1): >>42168543 #
11. charles_f ◴[] No.42166278[source]
That's not entirely true. The difference between intentional and accidental repetition is that the first occurs because the rule is the same in both repetitions, and should be the same ; whereas the second happens to be the same for now. In not repeating yourself in the second case you actually risk changing an operation that should remain the same, as a side effect of changing the common function to alter the behaviour of the first.

That's why DRY is a smell (indicates that something might be wrong) and not a rule.

12. arccy ◴[] No.42166363[source]
+1, have 2 implementations that each have an independent branch point? if you combine them you have a function with 2 bool parameters, and 4 possible states to test, 2 of which you might never need
replies(4): >>42167501 #>>42168511 #>>42170578 #>>42187714 #
13. Kinrany ◴[] No.42166370[source]
The monstrosities with dozens of flags do not happen because of the first wonky parameter. Inlining a function or refactoring it when the third use case comes around and invalidates assumptions isn't hard.
14. chipdart ◴[] No.42166385[source]
> I think it's especially bad advice with the "copy paste once is okay". You absolutely do not want multiple (even just two) copies of what's meant to be exactly the same functionality, since now they can accidentally evolve separately.

Hard disagree. Your type of misconception is the root cause of most broken and unmaintainable projects, and the root of most technical debt and accidental complexity.

People who follow that simplistic logic of "code can accidentally evolve separately" are completely oblivious to the fact that there is seemingly duplicate code which is only incidentally duplicate, but at its core should clearly be and remain completely decoupled.

More to the point, refactoring two member functions that are mostly the same is far simpler than refactoring N classes and interfaces registered in dependency injection systems required to DRY up code.

I lost count I had to stop shortsighted junior developers who completely lost track of what they were doing and with a straight face were citing DRY to justify adding three classes and a interface to implement a strategy pattern because by that they would avoid adding a duplicate method. Absurd.

People would far better if instead of mindlessly parrot DRY they looked at what they are doing and understood that premature abstractions cause far more problems than the ones they solve (if any).

Newbie, inexperienced developers write complex code. Experienced, seasoned developers write simple code. Knowing the importance of having duplicate code is a key factor.

replies(5): >>42166615 #>>42167259 #>>42167267 #>>42168379 #>>42169272 #
15. gozzoo ◴[] No.42166451{3}[source]
This! Coming up with meaningfull names helps you undrestand the problem and define the solution. I advise junior devs: if you don't know how to name a variable give it simple 1-letter name: a, b, x, y. When you look at the code it is immediately clear how well they understands the problem. One should be careful to avoid the naming paralasys though.
16. marcosdumay ◴[] No.42166579[source]
It depends. In fact the entire discussion is wrong, and neither rule has any real world value.

People are all talking about the format of the code, while what defines if it's a good architecture or not is the semantics. Just evaluating that heuristic (yours or the article's) will lead you into writing worse code.

replies(1): >>42167299 #
17. mewpmewp2 ◴[] No.42166595{3}[source]
Early in my career I started out really DRY, it in my experience and not just the code I wrote led to various issues down the line with unmaintainable edge cases. Especially if many teams are working on those things. It becomes really hard to support at some point. Now I feel much better making things DRY when it is really obvious that it should be.
replies(1): >>42167806 #
18. l33t7332273 ◴[] No.42166615{3}[source]
> Newbie, inexperienced developers write complex code. Experienced, seasoned developers write simple code

This is a really inaccurate generalization. Maybe you could say something about excess complexity, but all problems have some level of irreducible complexity that code fundamentally had to reflect.

replies(2): >>42167156 #>>42167460 #
19. ikrenji ◴[] No.42166712[source]
DRY fanaticism is just as bad as not thinking about DRY at all
20. srvaroa ◴[] No.42166774[source]
KISS > DRY
replies(1): >>42167198 #
21. mdaniel ◴[] No.42166776{3}[source]
I wish I could upvote this a million times

But, I'll also point out that just like reading about exercise, merely reading the book doesn't help unless one is willing to practice and -- much, much more difficult -- get buy-in from the team. Because software engineering is usually a team sport and if one person is reading these kinds of books and trying to put them into practice, and the other members of the team are happy choosing chaos, it's going to be the outlier who gets voted off the island

22. necovek ◴[] No.42167156{4}[source]
Nope, it is not inaccurate — but you are not wrong either.

Obviously, code will reflect the complexity of the problem.

But incidentally, most problems we solve with code are not that hard, yet most code is extremely complex — a lot more complex than the complexity inherent to the problem. And that's where you can tell an experienced, seasoned (and smart) developer who'd write code that's only complex where it needs to be, from an inexperienced one where code will be complex so it appears "smart".

replies(1): >>42174599 #
23. deprecative ◴[] No.42167198[source]
DRY for the sake of DRY is like not drinking water when you're thirsty.
24. stouset ◴[] No.42167259{3}[source]
All walks of developers write overly-complex code because they don’t know how to abstract so they either overdo it, under-do it, or just do it badly.

Writing good abstractions is hard and takes practice. Unfortunately the current zeitgeist has (IMO) swung too hard the wrong way with guiding mantras like “explicitness” which is misinterpreted to mean inline all the logic and expose all the details everywhere all the time and “worse is better” which is misinterpreted to justify straight up bad designs / implementations in the name of not overthinking things, instead of good-but-imperfect ones.

The knee-jerk response against abstraction has led to the majority of even seasoned, experienced developers to write overly complex code because they’ve spent a career failing to learn how to abstract. I’d rather us as an industry figure out what makes a quality abstraction and give guidance to junior developers so they learn how to do so responsibly instead of throwing up our hands and acting like it’s impossible. This despite literally all of computing having been built upon a tower of countless abstractions that let us conveniently forget the fact that we’re actually juggling electrons around on rocks.

25. twic ◴[] No.42167267{3}[source]
What thfuran said was:

> You absolutely do not want multiple (even just two) copies of what's meant to be exactly the same functionality, since now they can accidentally evolve separately. But coupling together things that only happen to be mostly similar even at the expense of complicating their implementation and interface just makes things harder to reason about and work with.

So, if things are fundamentally the same, do not duplicate, but if they are fundamentally different, do not unify. This is absolutely correct.

To which you replied:

> People who follow that simplistic logic of "code can accidentally evolve separately" are completely oblivious to the fact that there is seemingly duplicate code which is only incidentally duplicate, but at its core should clearly be and remain completely decoupled.

Despite the fact that this is exactly what the comment you replied to says.

Then you go on a clearly very deeply felt rant about overcomplication via dependency injection and architecture astronautics and so on. Preach it! But this is also nothing to do with what thfuran wrote.

> Newbie, inexperienced developers write complex code. Experienced, seasoned developers write simple code.

Sounds like the kind of overgeneralisation that overconfident mid-career developers make to me.

replies(2): >>42167782 #>>42168986 #
26. AlphaSite ◴[] No.42167282[source]
Yep. Not all code that looks alike is alike.

Similarity can be fleeting.

27. KerrAvon ◴[] No.42167299[source]
This is really the issue with the article -- it's the CS equivalent of pop-psych feel-good advice like "write a page every day and you'll have a novel before you know it." It doesn't solve your actual problems. It doesn't solve anyone's. You're not actually better off in the long run if every line in your source is a separate commit, unless you have the world's most basic program.

This "it's more important to wrap your code at 80 columns than to understand how the cache hierarchy works" stuff is becoming worryingly endemic. Teamscale has built an entire business around fooling nontechnical managers into believing this shit is not only worthwhile, but should be enforced by tooling, and middle managers at FAANGs, who should know better, are starting to buy in.

replies(2): >>42168375 #>>42168585 #
28. ChrisMarshallNY ◴[] No.42167460{4}[source]
Don't look at the code I just wrote (populating a user list with avatars, downloaded via background threads). It might cause trauma.

The last couple of days have been annoying, but I got it to work; just not as easily as I wanted. The platform, itself, has limitations, and I needed to find these, by banging into them, and coding around them, which is ugly.

29. hinkley ◴[] No.42167501[source]
It’s difficult to convince people that once you consider the testing pyramid, it’s not just 2 + 2 + 2 < 2 x 2 x 2 but also 2 + 2 < 2 x 2
replies(1): >>42168010 #
30. hinkley ◴[] No.42167534[source]
The itch that Aspect Oriented Programming was trying to address was that some functionality only needs to differ by what happens in the preamble or the afterward.

And that can be simulated in code you own by splitting the meat of a set of requirements into one or two bodies, and then doing setup, tear down, or a step in the middle differently in different contexts. So now you have a set of similar tasks with a set of subtasks that intersect or are a superset of the other.

31. hinkley ◴[] No.42167550{3}[source]
And usually the answer stops becoming a guess at 3. I’ve certainly had enough experiences where we had 2 and 3 in the backlog and no matter how we tried, #3 always required as much or more work than #2 because we guessed wrong and it would have been faster to slam out #2 and let #3 be the expensive one.
32. wruza ◴[] No.42167672{3}[source]
I think that it’s our tooling sucks, not us. Cause we only have functions and duplicated code, but there’s no named-common-block idea, which one could insert, edit and

1) see how it differs from the original immediately next time

2) other devs would see that it’s not just code, but a part of a common block, and follow ideas from it

3) changes to the original block would be merge-compatible downwards (and actually pending)

4) can eject code from this hierarchy in case it completely diverges and cannot be maintained as a part of it anymore

Instead we generate this thread over and over again but no one can define “good {structure,design,circumstances}” etc. It’s all at the “feeling” level and doing so or so in the clueless beginning makes it hard to change later.

replies(2): >>42170174 #>>42171430 #
33. deely3 ◴[] No.42167782{4}[source]
The issue is that you actually never really know is things are fundamentally the same. To know it you have to know the future.
replies(4): >>42168392 #>>42168533 #>>42168831 #>>42169889 #
34. dllthomas ◴[] No.42167806{4}[source]
> I started out really DRY

When you say "DRY" here, would you say you had familiarity with the original definition, or merely what you (quite understandably) inferred from the acronym? Because I think the formulation in The Pragmatic Programmer is pretty spot on in speaking about not repeating "pieces of information", whereas I find in practice most people are reacting to superficial similarity (which may or may not reflect a deeper connection).

replies(1): >>42168241 #
35. cpeterso ◴[] No.42167823[source]
These types of lookalike functions are like homonyms: they might be “spelled” the same, but they have different meanings and should not be conflated.
36. dllthomas ◴[] No.42167872{3}[source]
I think a part of the problem is that in addition to being a well regarded principle with a good pedigree, "DRY" is both catchy and (unlike SOLID or similar) seems self explanatory. The natural interpretation, however, doesn't really match what was written in The Pragmatic Programmer, where it doesn't speak of duplicate code but rather duplicate "pieces of information". If "you are okay with functions drifting apart or the cases they handle are allowed to differ" then the two functions really don't represent the same piece of information, and collapsing them may be better or worse but it is no more DRY by that definition.

I've tried to counter-meme with the joke that collapsing superficially similar code isn't improving it, but compressing it, and that we should refer to such activity as "Huffman coding".

It's also worth noting that the focus on syntax can also miss cases where DRY would recommend a change; if you are saying "there is a button here" in HTML and also in CSS and also in JS, your code isn't DRY even if those three look nothing alike (though whether the steps necessary to collapse those will very much depend on context).

replies(2): >>42170038 #>>42171545 #
37. silvestrov ◴[] No.42168010{3}[source]
"The greatest shortcoming of the human race is our inability to understand the exponential function”.

https://en.wikipedia.org/wiki/Albert_Allen_Bartlett

38. mewpmewp2 ◴[] No.42168241{5}[source]
Looking at the definition, I do believe I wasn't referring to the original definition. I didn't actually know that original definition was specifically limited to the information/knowledge part. I have to assume there's industry wide misunderstanding on this term?

To avoid the confusion, it seems like DRY would be better named something like "Single source of truth". Because I do agree with that.

replies(1): >>42169323 #
39. urbandw311er ◴[] No.42168263[source]
Why have we started “hard” disagreeing with each other recently? What’s wrong with just disagreeing?
replies(2): >>42168342 #>>42168907 #
40. stoperaticless ◴[] No.42168342[source]
It indicates importance of the topic and hardness of disgreement.

Tabs vs spaces - people disagree but usually can adapt to the team if needed.

Use java1.4 for green-field web app - hard disagreement for many, looking for new job is more attractive option.

41. stoperaticless ◴[] No.42168375{3}[source]
Whats wrong with tooling enforcing it?

I mean, where you wrap is not important, and is best left to tooling (brain cycles and meeting time can be used for more important things)

42. dustingetz ◴[] No.42168379{3}[source]
root cause of dysfunction is executive management, or really customer and market structure (e.g. govt procurement as an extreme example). Full stop

fwiw i agree that copy paste is fine

replies(1): >>42171273 #
43. dustingetz ◴[] No.42168392{5}[source]
or study abstract algebra (but you’re now a researcher, because programming isn’t yet solved)
44. Aeolun ◴[] No.42168489[source]
Having it all in one tested function means it’s much easier to keep in line. Woe be the one that decides to change a common section in something coopied all over the codebase.

Modifying those boolean flags within the context of your tests is practically free. Trying to merge 4 files into one is… not.

replies(1): >>42168515 #
45. Aeolun ◴[] No.42168511[source]
There’s ways to write this that still keep the entrypoint to a single function. Having different function names as your parameters doesn’t make them any less so.
46. tasuki ◴[] No.42168515[source]
Have four public api functions, which call a private function underneath to avoid the duplication. Everyone is happy.
47. Aeolun ◴[] No.42168533{5}[source]
I think this is what the original post that people took issue with said? By the time you write the same thing for the third time you are not predicting the future any more, you have practical evidence.
replies(1): >>42188887 #
48. Aeolun ◴[] No.42168543[source]
It’s funny, because the biggest stench to me is seeing a project with thousands of nested functions all doing nearly nothing.

Probably one of those ‘truth is in the middle’ kind of situations.

49. thfuran ◴[] No.42168585{3}[source]
Cluttering up git line annotations and code reviews with people's dev envs fighting over where to wrap lines or whether there's a space after parens or whatever is a waste of everyone's time and an impediment to seeing the actual code changes. That's why tooling should enforce a format, not because there's particular importance to the exact enforced format.
50. Ma8ee ◴[] No.42168831{5}[source]
Not the future, but the domain.
51. fenomas ◴[] No.42168888[source]
Hugely agree. Every junior on my team has heard me say: "copy-paste is free; abstractions are expensive." When you move two bits of logic behind a common interface you tell the world that they're the same type of thing, and future editors will tend to maintain that promise - if the two things diverge further, someone will handle that by adding more parameters to the shared interface.

So when deciding whether to merge two similar functions, to me the question to ask yourself is "are future changes to one of these functions almost certain to affect the other one as well?" If not, just leave the functions separate no matter how similar they are.

replies(2): >>42171291 #>>42174117 #
52. internet101010 ◴[] No.42168907[source]
Difference between the two is that hard disagree means you won't be able to change their mind.
replies(1): >>42170577 #
53. djmips ◴[] No.42168986{4}[source]
To be fair thfuran was hard to decipher and should be refactored to be more clear.
54. brigandish ◴[] No.42169272{3}[source]
If someone writes a strategy pattern to fix duplication, all power to them, it's a well understood, easy to use pattern that fixes several problems.

> adding three classes and a interface to implement a strategy pattern

Sounds like the language used is the problem here, not the intent. Hasn't Java (et al) made this easier yet?

55. dllthomas ◴[] No.42169323{6}[source]
> I have to assume there's industry wide misunderstanding on this term?

The "misunderstanding" is at least as prevalent as the original, yes. I wasn't trying to say the original is "correct" - language is determined by usage - just wondering which you were discussing.

> To avoid the confusion, it seems like DRY would be better named something like "Single source of truth".

It could probably do with a better name, but "single source of truth" is usually about the information operated on by the program, rather than information embodied in the program.

replies(1): >>42170685 #
56. hansvm ◴[] No.42169453[source]
I mostly agree in practice, but I'd walk both ideas back slightly: Things which should always be the same should have a common name, and things which might differ should have separate names. Doing so gives you a strong foundation where developers making local changes are unlikely to break the global program (related ideas include preferring total functions (reasonable outputs for all inputs allowed by the type system) when possible, constraining type signatures to make that viable if it otherwise isn't, and giving names to things which are harder to misuse when that isn't practical (like `index_of_assume_sorted` instead of `index_of`)).

Connecting that idea back to the discussion:

1. IME, usually when code looks similar there exists a nice abstraction (a nice "name" future people will understand) for the similar bits. Allowing duplication to grow when you could have properly named things will eventually slow down development.

2. Functions with many parameters are rarely that kind of nice abstraction. The commonality is something much more contained, and functions with large parameter counts should usually be relegated to "entrypoints" or other locations where you're actually merging a thousand different concerns.

3. Bad abstractions are much more expensive than duplication. I have zero problems with committing duplicated code when there aren't any obvious solutions and letting a better plan materialize later.

57. spease ◴[] No.42169755[source]
It depends. Is it truly common functionality that, if improved upon, should apply to all dependent code?

Or is it just getting from point A to point B that happens to be the same in two places right this instant?

58. strken ◴[] No.42169889{5}[source]
"Know the future" is part of a software engineer's job description, at least insofar as "know" means "make informed predictions about".

Consider the case of making API calls to a third party. You, today, are writing a function that calls the remote API with some credentials, reauthenticates on auth failure, handles backoff when rate limited, and generates structured logs for outgoing calls.

You need to add a second API call. You're not sure whether to copy the existing code or create an abstraction. What do you do?

Well, in this case, you have a crystal ball! This is a common abstraction that can be identified in other code as well as your own. You don't know the future with 100% confidence, but it's your job to be able to make a pretty good guess using partial information.

59. wruza ◴[] No.42170038{4}[source]
The book assumes that you should know better, that’s the problem. You may understand it correctly and do your best, but remain unsure if that “piece of information” is the same with that one or not, cause it’s open for interpretation.
replies(1): >>42170125 #
60. dllthomas ◴[] No.42170125{5}[source]
Uncertainty as to the line between "one piece of information" and "two pieces of information" may be a problem. I don't think it makes sense to say it's "the problem" when most people don't know that DRY is formulated in those terms in the first place.

Personally, I don't think the ambiguity is actually much of a problem; often it's not ambiguous, and when it is it's usually the case that multiple ways of organizing things are reasonably appropriate and other concerns should dominate (they may need to anyway).

replies(1): >>42170513 #
61. skydhash ◴[] No.42170174{4}[source]
Smalltalk?
replies(1): >>42170551 #
62. wruza ◴[] No.42170513{6}[source]
I read your second paragraph as vagueness is fine, which sort of makes DRY not a helpful principle but a handwavy problem statement with no clear anything.

As in most vague problems, two extreme solutions (join vs dup) are a wrong way to think about it. I have some ideas on how to turn this into a spectrum in a nearby comment.

I think it is important because DRY-flavored problem is basically the thing you meet in the code most. At least that is my experience, as a guy who hates typing out and rediscovering knowledge from slightly different code blocks or tangled multi-path procedures and refactoring these — either in hope that nothing breaks in multiple places, or that you won’t forget to update that one semi-copy.

I’m programming for a very long time and seemingly no one ever even tried to address this in any sensible way.

63. wruza ◴[] No.42170551{5}[source]
Sadly I can’t just go and develop systems in smalltalk eco, too different boots to wear. So there’s no reason to even go and learn about how it does that or a similar thing, cause I not gonna switch or implement it myself in my editor. I’m sure (and confidently so) that I’d like to see exactly the described in editors/ides and that would make my coding life much easier.
64. eonmist ◴[] No.42170577{3}[source]
Or "should not" change their mind. If I hard disagree, then I should not change my mind, because I see no valid reason, and both my experience and reasoning are solid to the degree I am certain the arguments presented can not develop into a valid reason to change my mind. "Hard disagree" may signify being certain. I then am responsible, for my own sake and wellbeing, of being right in relation to reality, or reality will simply hard disagree.
65. cma ◴[] No.42170578[source]
A very common one is two booleans with one combination of them being an invalid state (e.g. never are both bools true in a valid state but all can be false or a mixture). Use an enum instead that represents only the three valid cases.
66. mewpmewp2 ◴[] No.42170685{7}[source]
You mean it's databases rather than what is in code?

If so, then that's also news to me. I'd have thought that e.g. something like input validation code that can be reused both in backend and client would go under single source of truth. Which I would always prefer not to be repeated, but frequently hard to do unless you have same language in backend and frontend or codegen.

67. mrighele ◴[] No.42171152[source]
A wonky parametrization is probably sign that you are refactoring at the wrong level. If you have something like

function doStuff(flag: boolean) { // do some stuff if (flag) { // do stuff a } else { // do stuff b } // more stuff }

you may want to do two implementations that are something like

function doStuffA() { doSomething(); doStuffSpecificForA(); doSomethingElse(); }

and

function doStuffB() { doSomething(); doStuffSpecificForB(); doSomethingElse(); }

68. karmakurtisaani ◴[] No.42171273{4}[source]
It's, however, unhelpful to point this out, since developers cannot fix it. We need to find ways to live with this dysfunction.
replies(1): >>42177787 #
69. Jensson ◴[] No.42171291[source]
Absolutely, its always easy to detangle the mess of inexperienced programmers who copied things everywhere, the nightmare are the medium level programmers who puts everything behind big interfaces and just adds more interfaces with every change.
replies(1): >>42171546 #
70. rileymat2 ◴[] No.42171430{4}[source]
Without the encapsulation of a function, won’t the code around the common block depend on the details of the block in ways that cause coupling that make the common block hard to change without detailed analysis of all usages.

I like what you are saying, i think, but am stuck on this internal coupling.

replies(1): >>42191382 #
71. atoav ◴[] No.42171545{4}[source]
Now this is a principle I can totally get behind. If the same information lives in multiple places in your codebase, you are definitly doing it wrong, unless that same information is just coincidentally the same and used for different purposes in different places
72. Gud ◴[] No.42171546{3}[source]
Indeed, this was me. Now I don’t care if I have three functions doing the same thing slightly differently.

Much better than having some advanced mega functions I don’t understand how it’s working anyway

73. chambored ◴[] No.42174117[source]
I’m only a few years in the industry, and in my CS program, we were constantly told something along the lines of “any time you have to copy paste, look for an opportunity to abstract”. I’ve been running into problems lately where my attempts at abstractions have made things significantly more complicated. Only when I hit the limits of the abstraction I realize the cost of maintaining similar functionality in multiple places was less. I’m going to try your approach in future.
replies(4): >>42174755 #>>42178106 #>>42206175 #>>42206176 #
74. TheCoelacanth ◴[] No.42174599{5}[source]
I think inexperienced developers write complex code because it's difficult to write simple code and they don't know how yet, not because they're trying to make it complex.
replies(2): >>42180359 #>>42180503 #
75. nzach ◴[] No.42174755{3}[source]
I think the reasoning for DRY was kind of lost in translation.

“any time you have to copy paste, look for an opportunity to abstract” assumes that having an abstraction is always better, but I don't think that is the case.

In my opinion the reasoning as to why "code duplication is a code smell" is that if you have to copy and paste code around you are probably missing an useful abstraction for your code. And I think "useful" is the most important thing to keep in mind.

Sure, every time I copy and paste code I know that exist an abstraction I could create to eliminate this duplication. Generally this is pretty easy. The hard part is to understand when this new abstraction will help you to deliver the features the business need.

76. dustingetz ◴[] No.42177787{5}[source]
it is in fact helpful because it reveals that the problem cannot in fact be fixed at the developer layer, and having that knowledge is the first step down a road towards an actual solution rather than endless bike shedding about whether it is okay to copy paste a function body.
77. ◴[] No.42178106{3}[source]
78. necovek ◴[] No.42180359{6}[source]
Yes, I was not trying to imply they do it on purpose, but I can see how it could be read that way.
79. chipdart ◴[] No.42180503{6}[source]
> I think inexperienced developers write complex code because it's difficult to write simple code and they don't know how yet, not because they're trying to make it complex.

From what I've been seeing, inexperienced developers write complex code because they are trained with a bias towards accidentally complex code (i.e., how else would you show off design patterns), they have no experience in dealing with the tradeoffs of writing accidentally complex code, and they do not understand the problems they create for themselves and others by adding complexity where they do not need it.

I'd frame accidental complexity in the same class as dead code: inexperienced developers might be oblivious to the risk presented by codd that serves no purpose, but experienced developers know very well the ticking time bomb nature of it.

80. somethingsome ◴[] No.42187622[source]
I write research code, doing that feels very different than web code for example.

In research it is absolutely OK to copy paste a number x of times, because you don't know a priori what will work the way you want.

Usually, I write an algorithm to solve my problem, then I copy paste the function and change it a bit with another idea, and set a switch to choose between them. Then I copy paste another time as the ideas are flowing, and add one more switch.. Etc..

At some point, when I feel that there is too much duplicated code, I abstract the parts of the functions that are similar and never change, so that I can focus only on the changes of ideas, and no more on the mechanic of the methods.

As the code converges toward something I like, I PRUNE the code and remove all not used functions.

But this process can take weeks, and I can go to another issue in the main time, this is because I don't know in advance what is the right thing to do, so I get a code with several parts duplicated, and when I come back to them, I can choose which version I want to use, if something start to feel smelly, I prune it, etc.. Iteratively.

What I wanted to say, is that duplication of code is really dependent on the kind of code I'm doing.

If I'm doing an app, it's way easier to determine which code to keep and wich code to remove and which code to duplicate. But not all fields are the same.

At some period of my life, I always made clean code for research, you loose too many ideas and hidden behind the abstractions, you are not able anymore to work with your code. When you get a new idea, it requires to go through all the abstractions, which is insane in a very rapidly evolving code.

81. somethingsome ◴[] No.42187714[source]
Combinatorial explosion of states is a nightmare, IME it means that the abstraction behind is not the right one.

You really don't want to have a function that branches a lot inside. It's very difficult to test.

When you think of adding a flag, run in your head 2^n, this will give you the least number of tests needed. Do you really want to write all of them?

82. thfuran ◴[] No.42188887{6}[source]
But a thing that you wrote the same a few times isn't something that's definitively required to be the same, it's something that happens to be the same right now. You can often clean things up by factoring out that duplication, but needing to add a bunch of parameters to the resulting function is probably a sign that you're trying to combine things that aren't the same and shouldn't be coupled together.

Where I'm saying you absolutely shouldn't copy paste is where there's a business or technical requirement for something to be calculated/processed/displayed exactly a certain way in several contexts. You don't want to let those drift apart accidentally, though you certainly might decouple them later if that requirement changes.

83. wruza ◴[] No.42191382{5}[source]
It will share nuance with non-hygienic macros, yes. The difference here is that (1) unlike macros which hide what’s going on, the code is always expanded and can be patched locally with the visual indication of an edit, and (2) the changes to the origin block aren’t automatically propagated, you simply see +-patch clutter everywhere, which is actionable but not mandatory.

If you want to patch the origin without cluttering other locations, just move it away from there and put another copy into where it was, and edit.

The key idea is to still have the same copied blocks of code. Code will be there physically repeated at each location. You can erase “block <name> {“ parts from code and nothing will change.

But instead of being lost in the trees these blocks get tagged, so you can track their state and analyze and make decisions in a convenient systemic way. It’s an analysis tool, not a footgun. No change propagates automatically, so coupling problem is not a bigger problem that you would have already with duplicated code approach.

You can even gradually block-ize existing code. See a common snippet again? Wrap it into “block <myname> {…}” and start devtime-tracking it together with similar snippets. Don’t change anything, just take it into real account.

84. jhanschoo ◴[] No.42206175{3}[source]
Surely there is a parallel with standardized testing asking the most needlessly ornate prose of its students and then most writing having more value the pialner it is written.
85. jhanschoo ◴[] No.42206176{3}[source]
Surely there is a parallel with standardized testing asking the most needlessly ornate prose of its students and then most writing having more value the plainer it is written.