In JS/TS, I occasionally see people excited about writing "functional" code write code like the following:
const schools_by_id = schools.reduce((acc, school) => {
acc[school.school_id] = school;
return acc;
}, {} as Record<string, School>);
Personally, I find this "functional" style hard to read! The first time I encounter acc
, I'm unsure of what it even is and then it needs to be returned? It takes me a second to parse even a simple reduce like this one.
I find a for
loop much easier to read:
const schools_by_id: Record<string, School> = {};
for (const school of schools) {
schools_by_id[school.school_id] = school;
}
Sure, we're mutating data, but it's local. This isn't the kind of data mutation that's going to cause a problem—it's exactly the same mutation that we're doing in the reduce.[1] And a for
loop makes some code much easier to work with—if we want to skip a row, we can continue
and if we need to make this code async, we can just add await
.
If we wanted to write this code in a functional way, we should do so by writing (or importing) utilities that describe what we want to happen rather than describing how it should happen.
// https://lodash.com/docs/4.17.15#keyBy
const schools_by_id = _.keyBy(schools_by_id, school => school.school_id)
How much easier is this to read than the schools.reduce
version?
And I know you might not need lodash, but you'll probably want your own versions of some of lodash's utilities if you're doing any sort of data transformation. I don't use most of lodash's functions, but if I were dropped into a code-base that didn't have its own versions of _.keyBy
, _.groupBy
, _.mapValues
, _.partition
, and _.orderBy
, I'd probably want to add them.[2]
Listening to me gripe about .reduce
isn't likely to convince anyone. Try searching your code-base for .reduce
! What do you think? Would they be better as for
loops? Or using utility functions?
When I do this in code-bases I work in, I see a few good examples of code that is clearer because of .reduce
, but the vast majority of the code I see could be clearer if it were rewritten.
Unless someone has written an abomination like
const school_by_id = schools.reduce((acc, school) => ({...acc, [school._id]: school}), {})
. That code is slow and unclear for no good reason. ↩︎It's worth noting that lodash doesn't tree-shake well, so if you're working on the frontend, it may make sense to stick plain javascript versions of the utilities you want into a utility file. https://youmightnotneed.com/lodash ↩︎