Had a colleague work under a 'team lead'. Needed to take a form with variable amount of rows of input data - max 50 - and take data, parse it, and store it. Took 20-30 lines of code. Next day "I don't trust loops, these need to be unlooped". Really? This was all in writing and stated out loud in a meeting with witnesses, and everyone agreed. "Loops can be tricky - they don't always work like you think" (something like that). So a 30 line block of code with a loop around it became 1200+ lines with 'v1, v2, v3.... v50', with 'ifs' around each one to check if that row number was also submitted.
The code to generate the form was, of course, a loop that spat out holders for 50 rows. THAT was OK, because someone else's team wrote that a while back (really??) and ... it was already done and in production. The lead could not put their stamp on it.
Very very very weird. Having half a dozen other people all nod their head suggesting that a 30 line loop is fraught with danger, and the correct answer is copy/paste 50 times. Felt like gaslighting, to my recollection. Worked in same dept, just not on same project together, but enough of this was heard/pickedup across the dept.
And... my colleague and I aren't there any more, and to my knowledge, that team lead is still there.
Sounds like a real-life example of the Asch experiments.
I was in a situation in the early 2000s where the team that would maintain our application after we were gone (to another project or product or company) were not skilled enough to follow certain things, and we were asked to change a number of things to make it easier for them. In that case, the leader of their team was self-aware and honest and communicative, which is the rare and exotic thing, but we did have to re-architect some things and even change the programming language in one area to suit their capabilities. Sometimes that's a business need, and it matters.
My senior engineer advised me against using Java .sort() because “we didn’t write it so we couldn’t be sure it would do the same thing every time.”
A quick search however does say that Java's .sort() is stable.
I guess the author just distrusts smaller things, leaving me to distrust the author’s larger things.
Well, assuming that the language doesn't have any quirks in this area - e.g. in Java your statements aren't equivalent for a Boolean x.
Reading "if true == false" or "if false == false", it becomes much clearer what we're testing here and I understand it instantly.
I agree that when you read it, it's clearer. And yet I still prefer "if(isGreen == false)" for reasons of clarity in another sense.
The "!" being right next to the "(" makes it easier to miss the "!" when scanning quickly through the code, hence reading the logic the wrong way round and seeing "(isGreen" instead of "(!isGreen". And that's enough of a risk to ignore the readability advantage of "(!".
(Edit: To be clear, I don't suggest "== true" for the opposite cases, as the lack of a "!" in those means the risk is gone)
if (x == true)
which always seem to come with some argument how it is "more clear".I have started to ask people straight away to change to
if ((x == true) == true)
which following the same argument should be even more clear.That said, if x is data read from elsewhere that just happens to be boolean, I can write code like that in Python.
if !is_nil(foo)This is a technique called loop unrolling. It is done for performance reasons. This is something we used to do at a company working on games for the old feature phones (think Nokia 30/40/60 series stuff). The devices were very limited, there is no direct control over J2ME garbage collection, etc... so loops could very noticeably slow down games.
We initially wrote code with loops, then would performance test and manually unroll when it was necessary. Eventually this became very burdensome and we eventually... wrote code to unroll the loops for us and that code of course had loops in it because it was build code that wouldn't ship.
There are other performance situations where this technique applies.
This may not have been the situation there, but I think it's important that rather than assume stupidity from the outside that we try to ask why.
The loop unrolling was just one example of how we would go about preventing an undesirable sweep.
As another example a large global game object array would be created when a game was started. As objects were created and deleted they would really just update pre-created objects in that array.
This allowed us to prevent garbage collection, while simultaneously making sure we didn't run out of memory.
The Nokia 1618 (a series 40 device) has a heap limit of 1024KB. Many S20 and S30 devices were even further memory constrained.
The only right choice in that situation.
I was delighted, but the old-timers were quite suspicious of this experimental technology.
FWIW this was... 2005-ish.
DRY deserves to be listed with other code smells that may indicate a missing abstraction (and there are many), but there is never a reason to blindly extract chunks of code based purely on repetition. That's not a "first step toward good programming", it's a step in the wrong direction.
As a Haskeller, when I do this it's about getting certain guarantees about the semantics of related workflows and knowing they must behave the same in X, Y, and Z.
This aids in reasoning about inevitable production issues.
I find boring code easy to modify but hard to reason about from a higher level and that it typically requires nastier solutions to maintain backwards compatibility.
That last point is contradicted by this posts example though, so it has me reflecting on things.
DRY is a tool, not a design goal. I think part of the Rails issue is a combination of the early Rails hype/philosophy, and the fact that DRY as a concept is so easy to "get", that everyone gets it but often fail the next step of "why". Without the why, you often can't figure out the right when/where so it gets applied everywhere.
It feels to me like another oblique angle of Goodhart's Law; eg: "A rule of thumb that becomes a required practice ceases to be a good rule of thumb".
As a result, rules of thumb like DRY are drummed into new developers. The overall effect of that is probably better code quality in general, but yes probably more instances of them being over-used.
But if Rails has the problem of folks over-using DRY, what are other languages communities doing? Just not doing so well at telling people about DRY in the first place?
Another generic statement: copypaste (as I understand you mean the opposite of extracting common code) between specs goes against single responsibility. Rather than `setupUser()` you open a connection, create a user fixture, write it to the db, and then paste that across all the specs. Doing quite a lot.
I can imagine a spec with let's say 20 cases. Arrangement of each takes about 6 lines to load something, change some state the test subject depends on, the usual stuff, like in the above example.
A week from now, 10 cases need an extra line of setup, which you dutifully paste across the specs which require them. You put it somewhere in the middle, as it needs an id from the first step of 6.
This happens once or twice. The commonality of the original 6 copy pasted all over the place is hashed up, interspersed with calls specific to each test. The linking factor between those 6 lines is now obscured and requiring careful analysis if only those 6 need to change.
This can be avoided if you extract the common bits out early on. Rule of three is your friend if you don't want to rush it.
I have seen this working in finance. I worked at a startup with a quant, and my job became waiting for him to go home at 6 so I could clean up his code and make it maintainable the next day. Now I don't blame him- his background was operations research and he was a professor prior, without any real software background. But, he would get legit mad at me for messing with his code. We had a really tense relationship for awhile. I would occasionally break things, but he didn't really have tests until much later, so it was hard to detect and there were often subtle side effects.
But anyway, I think for awhile he thought I was just a pain in the ass, until one day about 9 months after we started the project, and he wanted to run some experiments using a specific universe of securities, and just apply a few constraints to them, and I set this up for him in about 5 lines of code, and all of a sudden, I could just see the light bulb finally turn on for him as to why I was doing all of these things. After that day we became a lot more friendly.
You can’t adopt DRY or SPOT or anything else if you aren’t free to refactor and you aren’t free to refactor without some tests.
> learning the acronyms like DRY, and just following them
Following DRY is the hard part. As the author points out, to DRY something up you need to pick the right level of abstraction. This requires experience to do well.
While there are certainly some DRY proponents that treat it like that, most discussions I've seen advocating for DRY treat it as a rule of thumb. There are always exceptions, but DRY will steer you in the right direction more often then not.
I'm curious what languages and frameworks you work with. I suspect this is something that varies from one programming subculture to another. In my experience, the only codebases where I've consistently seen underuse of abstraction have been PHP and C, and in those cases it has been because the code was written by entrepreneurs or engineers who were not software professionals. In Java and Scala I've seen plenty of code that used too much abstraction but almost no code that used too little. In C++ and Python I've seen it go both ways.
In my book, what programmers need first of all is the willingness to rewrite their code. I've been trying to hit the right balance for twenty years, but even now I frequently have to backtrack because the decision to add or not add a layer of abstraction turns out to be wrong. Biasing somebody towards or away from abstraction just changes the kinds of mistakes they make without making them better at cleaning them up.
This is why best practices are needed, and why they are over-rated. Where they are used, they are often over-used.
For what it's worth, 90% of the code bases I've worked on overused DRY. Two pieces of code that do the same thing but that shouldn't be coupled should be repeated, otherwise you end up with a million "if" statements for all the separate cases this code will need to handle as it grows, as well as uncertainty about whether changes will have unintended consequences.
People not able to factor out functions or structure their code in a readable way. Variables are called v1, v2, v3. Unit testing seen as a waste of time. CI seen as a fun toy. They lack the experience to even notice the difference.
Maybe I'm becoming a curmudgeon, but I think many people would be well served by just googling "<my programming language> best practices", learning the acronyms like DRY, and just following them. And when you have gained some experience, sure, then you should question the wisdom and not follow it blindly.