DEV Community

Discussion on: What s wrong with Array.reduce ?

Collapse
 
genreshinobi profile image
Shinobi🕹 • Edited

I didn't mean to imply that developers intentionally make there code complex, but the OP did mention that he initially favored array.reduce because it "looked smart".

The barrier to understand code isn't necessarily subjective. A for loop in most cases is objectively more widely understood than array.reduce.

If you work on a team where you aren't going to be responsible for maintaining your own code and you aren't in control of who will, then choosing a simpler more readable approach might be something you'd consider. From a business perspective the more time someone spends trying to understand what you wrote the more expensive what you wrote becomes which depending on the team you may or may not care about.

Thread Thread
 
wulymammoth profile image
David • Edited

Okay, you’re making the same argument Objectively easier? No. I disagree. Familiarity, yes. Give the example of filter or reduce to a non-programmer and ask them what they think is happening. The for-loop is a familiar construct for those coming from C-style languages.

So you’re still arguing on the basis of “simpler and more readable”. It is subjective, because if I’m the audience, it is far simpler and more readable to me to see a reduction than have to read through the body of a for-loop to understand what’s happening. What you’re really stating is to consider writing in a way that covers the broadest audience.

Let’s take another concept that’s often hotly debated — recursion. Should we avoid recursion because we want to provide the most accessibility? Honestly we can just use for-loops and nested for-loops to express a bunch of ideas that are recursive or repetitive in nature. The fallacy in your stance is using “simpler and readable” because what is simple and readable is different to different audiences of different levels of programming ability. Therein lies why it is subjective. By golly if someone wrote a bunch of for-loops to express a recursive operation that is elegantly expressed in a simple recursive function with a base case would drive me nuts. The only consideration would be performance here — memo-ization and dynamic programming is far more performant and changes recursive functions to iterative and performant ones but is far more difficult to understand

Thread Thread
 
genreshinobi profile image
Shinobi🕹 • Edited

Just to be clear, my original point was: If you're given a choice, simple and readable might be something you'd consider because there might be a business advantage.

//edit I also unfairly edited my response to you prior to you responding. Apologies for that.

Thread Thread
 
genreshinobi profile image
Shinobi🕹

"Consider your audience" is probably the point I was trying to make. Thank you for talking me through that.

Thread Thread
 
wulymammoth profile image
David

Fair -- whatever "simple and readable" means to the developers...

But again, I, too, responded to that bit -- "business decision" or "business advantage". Unless you're in the business of writing code for developers to read, this is a bit of a moot point. Right? The business does not care about the code -- only the result of that code. The consumer of an iOS or Android app does not need to know whether the developer has used for-loops or reduce in the code...

Thread Thread
 
genreshinobi profile image
Shinobi🕹 • Edited

Open Source might be an example of a situation where a single dev might consider there audience being other devs.

I also don't think it's fair to say businesses don't care about the code. I just don't think it's practical for most businesses to care. A business might empower someone to make decisions on their behalf; "Lead Developer" comes to mind. A business might document how it expects it's developers to code, Google's Style Guides for example. Either of those might care whether for-loops are favored over reduce.

I don't think many developers appreciate the succession of their code. I also think, many developers don't have to. If you're a single dev, writing a single app, for a small business who doesn't care about anything except the app being delivered on time. Your audience and priority is obviously not other devs.

Thread Thread
 
wulymammoth profile image
David

I didn't mean "businesses don't care" to be a sweeping statement, but again, it comes down to the audience.

When you're bringing it into the arena of empowerment, it's almost an entirely different discussion. A lead developer or senior dev or engineering manager typically help bridge the gap between product managers/stake-holders which I perceive to be "the business". To me, that's divorced from the implementation as stakeholders at companies that I've been at have no say and won't even be able to read code. Even if you take Sundar Pichai and ask him, unless he's worked in a language, he's probably not going to have a valuable opinion on how some deliverable should be implemented.

When we're talking about style guides, these are created and consumed by developers and if you're in the business of building for developers (I currently work on APIs for devs), it is important that everyone is on the same page about these sorts of things. As someone that also contributes to documentation, I'd probably share both examples and let the end-consumer decide which is best in their case, but in the source code of the library, follow the established or agreed-upon style guide (if any) internally.

And you're totally right in your last paragraph -- I think this entire discussion started on the premise that our code is intended to be read by others and why reduce may be bad. But like any tool, it's just a tool and they can be used well or poorly. Someone stuffing a massive reducer as the callback to Array.prototype.reduce is a code smell, but so is stuffing that same conditional logic within the body of a for-loop. And if there are multiple declarations an initialization of collection objects (arrays, objects, sets, map) that the for-loop will be mutating scattered about on different lines, it's going to be very difficult to keep track and who knows if between those lines some other code is mutating it before it reaches the for-loop. Reduce keeps things atomic. There are a segment of folks that will tell you that the readability trade-off for atomicity is HUGE, because debugging won't be an issue with reduce as you're sure that mutations happen in ONE place. The easy thing to do doesn't always yield the desired result. The one thing that is constant in software is change -- the more churn and change that happens to such code will inevitably result in a regression that becomes hard to track down, fix, and/or refactor. Look no further than scripts. Scripts are ad-hoc and implicitly coupled to the very specific use case the author had in mind, but are not maintainable by a team of people. This is why patterns exist and abstractions and sometimes it is good to force the wider audience to learn and adapt to them if there is merit and that merit being less pain later on. It's not to "be smart". Those that are deeply down the functional paradigm can be assholes but unfortunately what they spout is too far to bridge the gap between what most people are used to and what they've come to realize (useful and arguably better). But I think core functional facilities like reduce strike a good balance and it's best that people are familiar with when and why to reach for it and also not be taken aback when it is used. Lastly, they should also call out when it is abused -- stuffing a massive callback/reducer. Just rip it out and give that a name and unit-test the reducer in isolation. It's not reduce's fault that someone decided to write an anonymous/lambda/callback that is untenable and unreadable. People are arguing about the wrong things here...

// this should be tested in isolation
function sum(total, num) { return total + num; }

// read as: "reduce to a sum"
let numbers = [1,2,3,4,5];
numbers.reduce(sum);
 
dvddpl profile image
Davide de Paolis

Yes. Familiarity and audience are the key here. In our team everyone is able to understand a reduce. And everyone likes it over a forloop. But now that I rewrote it with filter and map it looks more readable than reduce. So it depends. I really like the conversations here. Thank you all

Thread Thread
 
wulymammoth profile image
David • Edited

Communication in a team and outside both matter. It's always about the audience and sometimes that communication means getting each other on the same page. Filter and map are less generic than reduce when maintaining the same collection data type. Reduce is typically used to "distill" or bring it down or fold the collection (array) into something else. It's much more clear to map and filter in many instances because that's exactly what we're doing -- we still want to retain the collection (array). Whereas some other operations are: "reduce to an integer/sum/max", "reduce to a different data type/object", "partition" that are better expressed as reductions that map and filter can't do.

If it's a mapping operation or filtering operation, I'd much prefer to see map or filter. If I were reviewing that code and somebody threw a reduce to do what a map or filter call does, I'd ask them why...

But generally, I see folks throwing the for-loop at map and filter operations as well -- procedural and imperative. I'd much rather the code state what it's doing (by declarative means) than have me read through the body of the for-loop to determine that what is being done is a reduction, a mapping, or a filtering operation. The for-loop is much too generic outside of small use cases.

For one place that I've worked, we always asked people to use reduce, map, and filter. If a for-loop is used, that means it's a signal to other developers that there is the possibility of early termination (not iterating across the entire collection). So we have all these use-cases broken down and documented, otherwise the for-loop can be ANY of these four operations and requires the developer to read the body of the for-loop. Accessibility is high if the audience is broad, but in a team-setting with established patterns, this is just overhead...

Thread Thread
 
dvddpl profile image
Davide de Paolis

Indeed. Early termination (or very huge datasets, where I really need/want to iterate only once) is the only case where I use for loops. Otherwise it's always map and filter + reduce sometimes.