top | item 22973007

(no title)

tcgarvin | 5 years ago

Using common functional tools can be a great way to simplify code like the example here, but as with most programming techniques, it can easily backfire in real-life scenarios.

There have been a number of times I've seen junior developers who are high on functional/immutable paradigms commit mazes of mapping, filtering, rolling and unrolling, resulting in something that's hard to understand and hard to debug.

Even in the example here, while it's obvious what the replacement code _does_, it's less clear what it's _intending_. I actually had to refer back to the original code to understand that the thing we were trying to generate were IDs of some sort.

discuss

order

Konohamaru|5 years ago

Functional paradigm's problems are severe but people dismiss them as something we'll grow out of. If you can't tell what the code is intended to do, then the "savings" of functional are spent on more comments and documentation. Which is worse than the previous state of affairs.

It's also a little bit of Paul Graham's fault with his silly accumulator challenge. Not every language needs closures, and because closed over variables act as global variables, they might even undo the progress we've made in adopting structured programming. But by framing accumulator-capable languages as being more "powerful" now nobody wants to forgo them.

ken|5 years ago

I've seen a-million-and-one junior developers screw up for-loops, too, with overly complex code that's hard to understand and debug. That's in no way unique to FP.

I would need at least 3 more pieces of data -- the other (experience_level, programming_style, bug_rate) tuples -- in order to judge whether this constitutes a pattern which is best avoided.

baron816|5 years ago

> I've seen a-million-and-one junior developers screw up for-loops, too, with overly complex code that's hard to understand and debug.

Everything can be abused. I see people doing side effects in their mapper callbacks, deeply nesting ternaries and switch and if/else statements, mutating far off objects, and just generally making code way more complex than it needs to be. Usually, this is from junior devs, but not always.

In the right hands, functional programming in JS can be very powerful. It can be easier to reason about (linear data flow, declarative code), and more performant (immutable data structures, transducers). In the wrong hands, it can be even more opaque than imperative, procedural code.

mntmoss|5 years ago

What tends to be absent in the simple analysis that leads to these kinds of hammer-to-all-nails solutions is a full enumeration of the classes of errors or intractable problems in the domain, and how the proposal does or does not address each.

This blogpost does not even attempt such an enumeration, but instead appeals to aesthetics.

FWIW I went through a period of using map and filter a little bit, went, "that's nice", and then resumed using for loops, sometimes with comprehension syntax to sugar it up. Both methods basically cover ways to specify simple iteration and selection. But I know which one is going to port better across the majority of environents: the plain for-next, and if a complex iteration is called for, the while loop. It puts the data allocation where I can see it, and it maps to the single-threaded computing model that is still the default today.

If I want a more complex query, I am going to start wanting a more expressive query language than either imperative or functional selection and iteration can provide by themselves. Left outer joins do not come easily to either method. Neither does constraint logic programming. You obviously can implement those things, but it isn't blindingly obvious, and when your problem grows to need a very broad expression of selection and iteration, it is those kinds of tools that you really need to aim for.

dogweather|5 years ago

Yes, that's a good point. The intermediate variable names help document what's being produced.

habitue|5 years ago

It's not just junior programmers