News for hackers. Stuff that matters.
Re:Goodbye, Clean Code by Stratoscope on Saturday January 11, 2020 @10:35PM (#22024294)
The Rule of 3 is a great rule, except when it isn't.

I had a colleague some time ago who wrote a couple of data importers for FAA airspace boundaries. There were two data feeds we cared about, "class airspace" and "special use airspace". These airspace feeds have nearly identical formats, with altitudes, detailed boundary definitions, and such. There are a few minor differences between the two, for example different instructions for when a special use airspace may be active. But they are about 95% the same.

The developer wrote completely separate data definitions and code for the two. The data definitions mostly looked the same and used the same names for corresponding fields. And the code was also nearly the same between the two (in fact exactly the same for most of it).

It was clear that one importer was written first, and then the code and data structures were copied and pasted and updated in minor ways to create the second.

Because the data structures were unique for each (even if they looked very similar in the source code), this impacted all the downstream code that used this data. If you saw a field called FAA_AIRSPACE_MIN_ALTITUDE, you had be sure to not confuse the class airspace vs. special use airspace, because each of these had a field of the same name, the compiler wouldn't catch you if you used the wrong one, and you may have the wrong offset into the data structure.

I asked the developer and they told me, "I have this philosophy that says when you have only two of something, it's better to just copy and paste the code, but of course when you get to the third one you want to start to think about refactoring and combining them."

Yep, the Rule of 3.

In this case there were only ever going to be two. And the two were nearly the same with only minor differences.

But because of blind obedience to the Rule of 3, there were many thousands of lines of code duplicated, both in the importer and in its downstream clients.

I still like the Rule of 3 as a general principle, and I have espoused it myself. But I think it is best applied in cases where the similarities are less clear, where it seems that there may be something that could be refactored and combined, but it's not yet clear what the similarities are.

I think it is a very bad rule in a case like this, where it should be obvious from the beginning that there are many more similarities than differences.

Re:Goodbye, Clean Code by gameswithgo on Sunday January 12, 2020 @08:51AM (#22026254)
Every single rule or advice in programming is good until it isn't. OOP is good until it isn't, function programming is good until it isn't, premature optimization is the root of all evil until it is the root of all good.

For some reasons humans have this deep need to try and boil things down to bulleted lists which in the domain of programming are just incredibly not useful.

Re:Goodbye, Clean Code by bjornjajajaja on Sunday January 12, 2020 @07:34PM (#22030870)
This is because programming is an art. It has fundamental components (objects, functions, templates, iterators, etc) like in visual design (point, line, shape, value, etc).

I think engineers should read the old and the new C++ books and master that language to know the evolution of all these paradigms and how to use them. There’s so much wisdom in the “Effective C++” series and Gang of Four and “C++ Templates: The complete guide“ to name a few.

Problem is in this “start up culture” to bang things out and get them working the art is left behind. Just like many other arts.

Re:Goodbye, Clean Code by hermitdev on Sunday January 12, 2020 @09:43PM (#22031419)
I was part of an uncredited team interviewed by Meyers for "Effective Modern C++". Always thought ir was somewhat ironic. At the firm (declined acknowledgments because they shun media attention) we werent even using a C++11 compiler on either Linux or Windows at the time. Yet, at least two of the patterns, I recognize as being at least a partial contributor to.

Myself, I lost track of C++ standards changes with C++17, and Ive not been using C++ for the last several years.

I still love the power and speed, but right now I'm dping more ETL work, and Python is a better and more productive language for that.

Re:Goodbye, Clean Code by TravHatesMe on Sunday January 12, 2020 @12:58PM (#22027787)
I think that you have a point but I often find myself citing guidelines or rules when I am evaluating code decisions or questioning code design. Maybe it depends on your interpretation of the phrases, some sayings should be followed religiously but others applied with discretion.
Re:Goodbye, Clean Code by akoncius on Sunday January 12, 2020 @01:04PM (#22027833)
well said. for a while I started treating everything as a soft rule, more like guideline. it gets easier then :)
Re:Goodbye, Clean Code by Smoosh on Sunday January 12, 2020 @05:48PM (#22030181)
Consider them to be heuristics, not rules.
Re:Goodbye, Clean Code by bcrosby95 on Saturday January 11, 2020 @11:13PM (#22024423)
The rule of 3 usually is in reference to small scoped abstractions, not whole modules or subsystems. We're talking about extracting a short function, not significant and potentially thorny chunks of code.

But I guess no one explicitly spells this out, so I could see where someone could become confused.

Re:Goodbye, Clean Code by valand on Sunday January 12, 2020 @01:15AM (#22024793)
Premature abstraction. Rule of 3 helps. But I found better principle for it:

Any abstraction MUST be designed to be as close as possible to be language-primitive-like. Language primitives are reliable, predictable, and non-breaking. If they do, they don't affect business logic written on top of it. If parameters are added, defaults are provided. They don't just abstract, they enable developers to express business logic more elegantly.

The challenge is to pick the part of the code abstractable to be primitive-like first and make it a top priority.

This is why language features like Rust async, Go channel-based comm, ES6, C++ smart pointer was such hype in their time and is used up until now. It also applies to enabling tools such as React, tokio, wasm-bindgen, express, TypeScript, jquery (even this which is not a thing anymore).

Re:Goodbye, Clean Code by pvorb on Sunday January 12, 2020 @03:14AM (#22025142)
I find abstractable parts in code by thinking about potential names for it. If there is no good name for a potential common function, it's probably not a good idea to extract the section into a function. Maybe it can be extracted into two separate functions with good names?
Re:Goodbye, Clean Code by konschubert on Sunday January 12, 2020 @05:10AM (#22025497)
This is a proxy for having a well-defined purpose for a function.
Re:Goodbye, Clean Code by pvorb on Sunday January 12, 2020 @08:23AM (#22026169)
Yes, absolutely, but it's one that's easier to teach juniors.
Re:Goodbye, Clean Code by aj7 on Sunday January 12, 2020 @12:55PM (#22027768)
Like.
Re:Goodbye, Clean Code by Stratoscope on Saturday January 11, 2020 @11:22PM (#22024461)
Yes, exactly, and it is such a good rule to go by so much of the time. But like many rules, you need judgment to know when to apply it.
Re:Goodbye, Clean Code by hyperpallium on Saturday January 11, 2020 @11:25PM (#22024474)
Rules are a poor substitute for actual thought.
Re:Goodbye, Clean Code by thunderbong on Sunday January 12, 2020 @12:11AM (#22024616)
> Rules are a poor substitute for actual thought.

This should be the guiding principle of life!

Re:Goodbye, Clean Code by HomeDeLaPot on Sunday January 12, 2020 @12:15AM (#22024628)
The guiding principle... a rule, so to speak!
Re:Goodbye, Clean Code by NegativeLatency on Sunday January 12, 2020 @02:03AM (#22024956)
Everything in moderation, even moderation itself.
Re:Goodbye, Clean Code by speedplane on Sunday January 12, 2020 @05:32AM (#22025580)
> Everything in moderation, even moderation itself.

This was my guiding principle in life, and I thought I was pretty clever for coming up with it, but later found out that someone far more clever got a lock on the phrase in history: https://www.goodreads.com/quotes/22688-everything-in-moderat...

Re:Goodbye, Clean Code by a1369209993 on Sunday January 12, 2020 @06:02PM (#22030303)
No, no, no; it's "Everything in moderation, especially moderation.". :)
Re:Goodbye, Clean Code by Stratoscope on Sunday January 12, 2020 @03:49AM (#22025234)
Really? I'm sure you know that all generalities are false.
Re:Goodbye, Clean Code by antonvs on Monday January 13, 2020 @10:55PM (#22041701)
Only a Sith speaks in absolutes
Re:Goodbye, Clean Code by pvorb on Sunday January 12, 2020 @03:18AM (#22025156)
You nailed it. I will print this and hang it on the wall in our office.
Re:Goodbye, Clean Code by he0001 on Sunday January 12, 2020 @02:55AM (#22025099)
I thought rules were a way of organizing thought, like a language which is governed by rules.
Re:Goodbye, Clean Code by scarface74 on Sunday January 12, 2020 @11:27AM (#22027104)
The rule of 3 usually is in reference to small scoped abstractions, not whole modules or subsystems. We're talking about extracting a short function, not significant and potentially thorny chunks of code.

I would say it’s for entire features sometimes. For instance, we are a B2B company. We have features on the roadmap or a feature might be suggested by a client. Either way, you hit the jackpot if you can get one client to pay for a feature that doesn’t exist in your product that you can then sell to other clients.

The problem is that you don’t know whether the feature is generally useful to the market. But you think it might be, in that case, you build the feature in a way that is useful to the paying client and try not to do obvious things that are client specific. But until you have other clients you don’t know.

Re:Goodbye, Clean Code by Gibbon1 on Sunday January 12, 2020 @09:32PM (#22031380)
That's been my experience doing embedded stuff. Customers will tell you they want a feature. You'll implement it then find out they don't need it enough to devote resources to utilize it on their end. So then it just lingers in the code base. And never gets real world testing. Lately I've been pulling unused features and consigning the code to the land of misfit toys. Just so I don't have to maintain them.
Re:Goodbye, Clean Code by scarface74 on Monday January 13, 2020 @10:51AM (#22035464)
If that’s the case and they were willing to fully pay for the feature, at professional services + markup hours, it wasn’t a loss. In our case, we still got unofficially professional services and recurring subscription revenue and now we have a “referenceable client”.

If it’s behind a per client feature flag, it doesn’t cause any harm.

Re:Goodbye, Clean Code by WalterBright on Sunday January 12, 2020 @01:25AM (#22024823)
Any of these rules comes with "use your best judgement" and not drive off a cliff blindly following it.
Re:Goodbye, Clean Code by dkersten on Sunday January 12, 2020 @09:29AM (#22026395)
> I asked the developer and they told me, "I have this philosophy that says when you have only two of something, it's better to just copy and paste the code, but of course when you get to the third one you want to start to think about refactoring and combining them."

I would argue this is a good rule of thumb, but nothing should ever be a hard unbreakable rule. The usual refactoring rules should apply too: if 95% of the code is the same, you should probably go back and refactor even without a third use case because it sounds like the two use cases are really just one use case with slight variation.

Re:Goodbye, Clean Code by scarface74 on Sunday January 12, 2020 @02:03PM (#22028365)
If the compiler didn’t catch it, doesn’t that say it was modeled incorrectly?

Why not have an IAirSpace interface or an abstract AirSpace class with two specializations? If there were processes that could handle either it should take an AirSpace class, one that could only handle one or the other took the specialization.

If the steps were the same for handling both, have step1...step(n) defined in the concrete class and have a coordinating “service” that just calls the steps and takes in an IAirSpace.

Re:Goodbye, Clean Code by skrebbel on Sunday January 12, 2020 @04:24AM (#22025333)
To be honest I don't get it. What language was this in, that you couldn't duck type the data or make the data structures inherit from some shared interface that encapsulated the commonalities?
Re:Goodbye, Clean Code by Stratoscope on Sunday January 12, 2020 @05:12AM (#22025505)
That is a reasonable question. You may have noted that I left some details vague, so all I ask is that you trust me that the overall story is true.

Of course if you don't trust me, that's cool too! ;-)

Re:Goodbye, Clean Code by skrebbel on Sunday January 12, 2020 @05:19AM (#22025533)
Hah! Totally do, I'm just nerd sniped by the details I guess :-)
Re:Goodbye, Clean Code by konschubert on Sunday January 12, 2020 @05:09AM (#22025493)
Rules of thumb are just that. Developers still have to understand the underlying motivation (incidental vs inherent duplication).
Re:Goodbye, Clean Code by a1369209993 on Sunday January 12, 2020 @05:57PM (#22030255)
> The Rule of 3 is a great rule, except when it isn't.

"Rules are for the guidance of wise men and the obedience of fools."

It's unfortunate that you had to deal with a fool, but that's not a indictment of the particular rule that they picked to follow off a proverbial cliff.

Edit: fixed ambiguous quote formatting.

Re:Goodbye, Clean Code by Stratoscope on Sunday January 12, 2020 @07:14PM (#22030756)
Thanks for your reply. I just want to note that what appears to be a quote in your comment ("Rules are for the guidance of wise men and the obedience of fools") is not something I wrote at all. If you still have time to edit the comment, I might suggest changing that so it doesn't look like you quoted me.
Re:Goodbye, Clean Code by yawaramin on Sunday January 12, 2020 @12:23AM (#22024641)
> But because of blind obedience to the Rule of 3, there were many thousands of lines of code duplicated, both in the importer and in its downstream clients.

Well sure, blind obedience to anything at all can cause problems.

Re:Goodbye, Clean Code by aj7 on Sunday January 12, 2020 @12:55PM (#22027763)
There’s a safety issue here. I can conceive of these code blocks diverging more with time. Plus is there really a cost of duplication.
Re:Goodbye, Clean Code by useful on Sunday January 12, 2020 @04:27AM (#22025348)
but it was used in many places, so the rule of three applies.

Personally, I would have kept the code that he wrote and made something that handled the special cases you are talking about.

Everything should be replaceable, not extendable. Now if the special cases change, my code can be thrown away without changing the data feed code.

Re:Goodbye, Clean Code by loopz on Sunday January 12, 2020 @07:17AM (#22025948)
Are you sure merging code for different datafeeds would be better though? In such cases, what is identical and what is not, should be references to eachother in comments. But you don't know beforehand which approach would be better, unless you know the datafeeds will stay the same as now.

The sad story here is that if you know the datafeeds will stay pretty static, there's little to gain making an advanced abstraction over them. Which is why you often find duplicated code that haven't been touched for years.. The original target was met with a naive approach, and no new changes lead to stale codebases.

Re:Goodbye, Clean Code by labawi on Sunday January 12, 2020 @07:40AM (#22026022)
If you have a 95% match on something nontrivial (and it likely won't diverge significantly), I'd go for merging even with 2 cases. At least merge most of the common parts.

Reading a couple of ifs, and some not-quite duplicate procedures seems much better than having a complete 2-set in cross-refenenced files.

Re:Goodbye, Clean Code by scarface74 on Sunday January 12, 2020 @02:06PM (#22028387)
Why are you reading a couple of ifs instead of having the two similar things represented by separate classes with shared functionality in a common class? Or even if you prefer composition to inheritance you could still make it work cleaner without a bunch of if statements.
Re:Goodbye, Clean Code by dkersten on Sunday January 12, 2020 @09:32AM (#22026406)
With a 95% match, you really only have one use case, with some minor variation.