pullAllBy(pluck(things, 'bar').map(compose(xor, lol, rofl)).reduce(differenceWith('id'))
Just write your transformations inline and go work on the next feature. pullAllBy(pluck(things, 'bar').map(compose(xor, lol, rofl)).reduce(differenceWith('id'))
Just write your transformations inline and go work on the next feature.If you don't use the builtin transformations, you'll just end up re-implementing them, poorly. And adding to the cognitive overhead with new concepts. And I have to read your code with a fine-toothed comb to ensure it's really side-effect free. I don't advocate turning everything into a named function as in your example though, short one-off functions should all be inline IMO.
Ideally this is how it should be written for maximum readability.
things
|> pluck('bar')
|> map(xor)
|> map(lol)
|> map(rofl)
|> reduce(differenceWith('id')
The code is written equally well without using pipe operator but the proposal to introduce it is in works [1].Here is it using lodash (not even lodash-fp), and this is going to do a single for loop when executing because this is lazy.
_.chain(things)
.pluck('bar')
.map(_.xor)
.map(_.lol)
.map(_.rofl)
.reduce(_.differenceWith('id'))
.value();
It's no less readable than the code you'd write using using unfolded transformations. things
|> pluck('bar')
|> map(compose(rofl, lol, xor))
|> reduce(differenceWith('id')Composing xor, rofl, lol isn't any better (esp in terms of readability) than it is individual maps.
What would be better is this:
const makeHilarious = compose(rofl, lol, xor);
things
|> pluck('bar')
|> map(makeHilarious)
|> reduce(differenceWith('id') things
.map(thing => x.bar)
.map(thing => {
// whatever happens in rofl
// whatever happens in lol
})
.reduce((acc, thing) => {
// more stuff
}, {})
This is code that is easy to understand and safe to change. The maps could be combined into one function body if it's convenient.It is one thing to quickly be able to understand that the person is doing a xor, then a rofl and then a lol of each element of an array, and a whole another thing to understand what the combination of these three actions over an array means. The python school of "code is read more than it's written" heavily stresses on explaining how easily the code should be understandable the first time someone reads it, but not whether it's easy to reason about or not.
The beauty of declarative style programming isn't to get more readable code immediately, but rather that once you understand the vocabulary, how easy it is for you to understand and reason about the code.
For instance, imagine reading a novel which is written like this:
"After Jack was done from the place where he went to do things for money everyday, he entered an establishment which served drinks that get you inebriated for money. This establishment was one he frequented regularly and preferred it over the others. He asked the man behind the counter for a wheat fermented brewed drink. After putting the drink to his lips and pouring it in to his mouth, he felt a sense of calmness enter his mind. It pushed all the thoughts which occupied his mind away, as he earlier desired before entering this establishment."
As opposed to:
"Jack really needed a drink after hard day at work. He went to his favorite pub, and ordered his favorite beer. After finishing the pint, he finally felt relaxed."
The Python philosophy (which is permeated everywhere in imperative world) is to describe everything in the simplest possible terms just in case there are people who may not understand what work, pub, beer, bartender, and relaxed means. But this just prevents from understanding of the actual purpose of the code.
This is at least the basic philosophy behind not using for loops everywhere.
so someone reading over it can kind of skim down the left side and follow what's happening and scan to the right if they need to understand some part in detail