Live data from Hacker News

Good refactoring vs. bad refactoring

builder.io

11–20 of 154 posts

Re: Good refactoring vs. bad refactoring

#11
post #4

The first example complained about the refactor appealing to functional thinkers (implying that it would be difficult to grok by the existing devs), but then the “improved” version is virtually the same save for the (unnecessary?) use of Ramda in the first. And while many devs are resistant to try functional ways, this first example reads so much better than the original code that I find it impossible to believe that…

Aesthetic aside, I am under the impression that people start programming, by and large, with imperative for/if style => so the imperative style is readable by more people. Even for more experienced programmers, reading imperative probably cost less energy, since it is more internalised? Futhermore, in JS, the functionnal style is less performant (nearly twice on my machine, i assume because it do less useless memory…

> I am under the impression that people start programming, by and large, with imperative for/if style => so the imperative style is readable by more people.

IMO, this is a simple consequence of technology moving faster than society. There are still instructors out there who learned to program in an environment where the go-to options for imperative programming were C and FORTRAN; the go-to options for other paradigms (if you'd even heard of other paradigms) were things like Lisp, Haskell and Smalltalk; and CPU speeds were measured in MHz on machines that you had to share with other people. Of course you're going to get more experience with imperative programming; and familiarity breeds comprehension.

But really, I believe strongly that the functional style - properly factored - is far more intuitive. The mechanics of initializing some output collection to a default state (and, perhaps, the realization that zero isn't a special case), keeping track of a position in an input collection, and repeatedly appending to an output, are just not that interesting. Sure, coming up with those steps could be a useful problem-solving exercise for brand-new programmers. But there are countless other options - and IMX, problem-solving is fiendishly hard to teach anyway. What ends up happening all the time is that you think you've taught a skill, but really the student has memorized a pattern and will slavishly attempt to apply it as much as possible going forward.

> Futhermore, in JS, the functionnal style is less performant (nearly twice on my machine, i assume because it do less useless memory allocations)

Sure. Meanwhile in Python:

    $ python -m timeit "x = []" "for i in 'example sequence':" "  x.append(i)"
    500000 loops, best of 5: 796 nsec per loop
    $ python -m timeit "x = [i for i in 'example sequence']"
    500000 loops, best of 5: 529 nsec per loop
... But, of course:

    $ python -m timeit "x = list('example sequence')"
    2000000 loops, best of 5: 198 nsec per loop
Horses for courses.

Re: Good refactoring vs. bad refactoring

#12
post #5

The first example complained about the refactor appealing to functional thinkers (implying that it would be difficult to grok by the existing devs), but then the “improved” version is virtually the same save for the (unnecessary?) use of Ramda in the first. And while many devs are resistant to try functional ways, this first example reads so much better than the original code that I find it impossible to believe that…

(Raises hand.) I prefer the for loop. Pushing items to an array is idiomatic Javascript for creating an array. An if statement is an idiomatic way to do it conditionally. It's also easier to debug. The map and filter methods are nice too, but they're for one-liners.

I will say in 2024 i feel like for/of or forEach would at least let you avoid the boilerplate of an index.

Re: Good refactoring vs. bad refactoring

#13
post #11
post #4

Earlier quoted context omitted.

Aesthetic aside, I am under the impression that people start programming, by and large, with imperative for/if style => so the imperative style is readable by more people. Even for more experienced programmers, reading imperative probably cost less energy, since it is more internalised? Futhermore, in JS, the functionnal style is less performant (nearly twice on my machine, i assume because it do less useless memory…

> I am under the impression that people start programming, by and large, with imperative for/if style => so the imperative style is readable by more people. IMO, this is a simple consequence of technology moving faster than society. There are still instructors out there who learned to program in an environment where the go-to options for imperative programming were C and FORTRAN; the go-to options for other paradigms…

People think imperatively though. If I think of visiting my friend, grabbing gas on the way back, the way I'll visualize the steps is not functional.

Re: Good refactoring vs. bad refactoring

#14
post #4

The first example complained about the refactor appealing to functional thinkers (implying that it would be difficult to grok by the existing devs), but then the “improved” version is virtually the same save for the (unnecessary?) use of Ramda in the first. And while many devs are resistant to try functional ways, this first example reads so much better than the original code that I find it impossible to believe that…

Aesthetic aside, I am under the impression that people start programming, by and large, with imperative for/if style => so the imperative style is readable by more people. Even for more experienced programmers, reading imperative probably cost less energy, since it is more internalised? Futhermore, in JS, the functionnal style is less performant (nearly twice on my machine, i assume because it do less useless memory…

> Even for more experienced programmers, reading imperative probably cost less energy, since it is more internalised?

I disagree. For-cycles are usually more difficult to reason about, because they're more general and powerful. If I see "for (...", I only know that the subsequent code will iterate, but the actual meaning has to be inferred from the content.

Meanwhile, a .map() or .filter() already give me hints - the lambda will transform the values (map), will filter values (filter), these hints make it easier to understand the logic because you already understand what the lambda is meant to do.

Other benefits stem from idiomatic usage of these constructs. It's normal to mix different things into one for-cycle - e.g. filtering, transformation, adding to the resulting collection are all in the same block of code. In the functional approach, different "stages" of the processing are isolated into smaller chunks which are easier to reason about.

Another thing is that immutable data structures are quite natural with functional programming and they are a major simplification when thinking about the program state. A given variable has only one immutable state (in the current execution) as opposed to being changed 1000 times over the course of the for-loop.

Re: Good refactoring vs. bad refactoring

#15
post #8

Good refactoring respects the idioms of the language and the culture of the organisation. Change to new methodology is thoughtful and probably slow, except when a revolution happens but then, its still respectful to the new culture. Bad refactoring is elitist, "you won't understand this" commented and the owner walks with nobody left behind who understands it. That the examples deprecated FP and preferred an idiom na…

The dig against FP is weird since the "good refactor" also uses FP, just a built in one in JS. Which I agree is better, but mostly by being built in and idiomatic, it's still exactly as functional.

Re: Good refactoring vs. bad refactoring

#16
That OO refactor isn’t actual OO. The tell tale sign is that it is named by what it does rather than what it is (verb vs noun) and the -or ending in the name [0]. It’s just a function masquerading as a class.

The better refactor to introduce OO concepts would have been to introduce an isAdult function on the user class and maybe a formatted function. This + the functional refactor probably would have made for the best code.

    return users.filter(u => u.isAdult())
      .map(u => format(u)); // maybe u.formatted()

[0] https://www.yegor256.com/2015/03/09/objects-end-with-er.html

Re: Good refactoring vs. bad refactoring

#17
post #13
post #11

Earlier quoted context omitted.

> I am under the impression that people start programming, by and large, with imperative for/if style => so the imperative style is readable by more people. IMO, this is a simple consequence of technology moving faster than society. There are still instructors out there who learned to program in an environment where the go-to options for imperative programming were C and FORTRAN; the go-to options for other paradigms…

People think imperatively though. If I think of visiting my friend, grabbing gas on the way back, the way I'll visualize the steps is not functional.

That's quite debatable.

In this case, you first declare the end-goal - visit a friend and have full gas tank, with the actual steps to achieve them being much less important and often left to be defined at a later point (e.g. which particular gas station, which particular pump etc.). This corresponds more to functional thinking.

An imperative thinking would correspond more to "I will sit in the car, start the engine, ride on highway, stop at address X, converse with Y, leave 2 hours later, stop at gas station X" - in this case the imperative steps are the dominant pattern while the actual intent (visit a friend) is only implicit.

Re: Good refactoring vs. bad refactoring

#18
post #9
post #5

Earlier quoted context omitted.

(Raises hand.) I prefer the for loop. Pushing items to an array is idiomatic Javascript for creating an array. An if statement is an idiomatic way to do it conditionally. It's also easier to debug. The map and filter methods are nice too, but they're for one-liners.

Writing assembly was the idiomatic way of programming before Fortran and human-readable languages came. Writing with goto was the idiomatic way before Algol and structural programming came. Having only a handful of scalar types was the idiomatic way until structural data types came (and later objects). Writing programs as fragments of text that get glued together somehow at build time was the idiomatic way until modu…

Making analogies like this doesn't prove anything, they're just suggestive. All I'm getting out of this is that you think for loops are old-fashioned.

Re: Good refactoring vs. bad refactoring

#19
post #15
post #8

Good refactoring respects the idioms of the language and the culture of the organisation. Change to new methodology is thoughtful and probably slow, except when a revolution happens but then, its still respectful to the new culture. Bad refactoring is elitist, "you won't understand this" commented and the owner walks with nobody left behind who understands it. That the examples deprecated FP and preferred an idiom na…

The dig against FP is weird since the "good refactor" also uses FP, just a built in one in JS. Which I agree is better, but mostly by being built in and idiomatic, it's still exactly as functional.

"I don't like this style of FP coding" ok: if you run the group and own the codebase you can enforce that. So good refactoring is style guide enforcement.

I think I over-read his dislike of FP. really the complaint is "why did you introduce a new dependency" which I am totally fine with, as a complaint. Thats not cool.

Many of his examples kind-of bury the lede. If he had tried to write an abstract up front, I think "dont code FP" wouldn't have been in it. "use the methods in the language like .filter and .map" might be.

Re: Good refactoring vs. bad refactoring

#20
post #13

Earlier quoted context omitted.

People think imperatively though. If I think of visiting my friend, grabbing gas on the way back, the way I'll visualize the steps is not functional.

That's quite debatable. In this case, you first declare the end-goal - visit a friend and have full gas tank, with the actual steps to achieve them being much less important and often left to be defined at a later point (e.g. which particular gas station, which particular pump etc.). This corresponds more to functional thinking. An imperative thinking would correspond more to "I will sit in the car, start the engine,…

Your second part is how I think and how I think most people think. That's exactly what I meant.
Post reply on HN