 Also, I just learned my camera, Jake's camera, two-shot. Is that what that is? That's the two-shot. Oh. Sorry. Because it shoots two. Go three. So you're sick. Yeah. I guess we should explain. Like, we decided to come to the studio and film two or three, which is, like, what we do. Yeah. That's our drop. That's it. And we picked today because it's, like, the only day that we have for, like, the next month. Pretty much. And then I got ill. Yeah. My eyes are running. My nose is running. My ears are running. They're not actually running. But they're dying. Like, it's only going to get worse. So you're going to be moany and insufferable to listen to? Well, what I'm going to try and do is I'm going to do the kind of forced talking thing that I used to do as a teenager when I got home drunk and I didn't want my parents to know I was drunk. And sort of, oh, yeah, they always knew. They knew, right? Yeah. But this is me pretending not to be ill. So, but there might be some sniffles. So editor Lucas, he's going to do an amazing job of editing all of that out. Cheers, Lucas. Hashtag. Thank you. No pressure. So. So. I, this is probably one of the most clickbaitiest titles. I've, well, not even clickbait, just polarizing titles. Well, the answer is yes. Yes. It is bad. Is reduced bad? Yes. Bye. Okay. I like your impression of the theme. That was quite good. Okay. So there is obviously a background story to why this is a topic now. Yeah. But first, just to make sure everybody knows what we're talking about, we're talking about the array method. So you have an array with stuff in it and reduce is one of these array methods that you can mutate or process whatever's in it. So you do specifically, you give it an accumulator start value and the function. Yes. And then for each element, the accumulator and the element will be passed in whatever the function returns becomes the new accumulator value. Yeah. And that just keeps going until the entire array has been processed that can be used for a couple of things that can also be abused for a couple of things. Many things. And you did a tweet. I did. Which was actually triggered by another conversation that we had on the side. Yes, it was. This was me sub-tweeting one of our colleagues. And I think we've talked about this before a couple of times. But we basically both think most of the time what reduce is or where reduce is used, it shouldn't actually be used. There's better ways of achieving the things where people use reduce. There's a couple of very few cases where it actually makes sense. One of them is like, if you want to look smart. Yes, absolutely. But I would, I mean, I want to point out that I'm not shaming people here. Well, actually, there is one person I'm shaming and it's myself. Because I definitely went through three phases, like learning code. First one, my code is very simple. And I didn't use things like regx and array.reduce because they were scary. Agreed. And then I learned these things and I learned all of the programming techniques of like currying, recursion, blah, blah, blah. And I thought, you know, my code, yeah, my code should demonstrate how clever I am to everyone. So I will use all of these things so anyone can look at anyone bit of my code and they'll go, that guy is smart and he knows lots of things. And then I because if the other person doesn't understand your code, you are smarter than that person. Exactly. Yeah. Yeah. Yeah. And they should just get cleverer, which is really, which was like a lot of the replies that I got to this thread. But I'm now like, you know, I've been doing JavaScript which is just like. 20. Yeah. I'm old. I'm quite old. I look particularly old today with the illness. But I feel like I'm now in the third phase of my coding experience, which is like, I want my code to look like the code in a beginner's book. Like I want it to be that straightforward. Yeah. I definitely over the years I've learned to appreciate code that you can just read. And you're like, I understand what is happening. That is so invaluable when you have that in a project and you actually know where to go and fix it. And so that's basically what I want to talk about. So what I did is look at some examples. And I kind of want to throw an hypothesis out here where I think when you see reduce, it will fall into one of four categories. Four. Right. Okay. The first category is it's a sum or something that is like a sum. It's some like. Some like. I like that. The second category is it should really be just using array methods, maybe with some object entries and object from entries. And those things are, some of those things are new like from entries is particularly. Yes. We want to talk about that. Yeah. Okay. But basically sometimes I see a reduce that is just a glorified filter on map and really you should have been using filter and map. Yep. The third category is it's a loop in it. Yeah. Like just use a loop and don't do reduce to abuse a loop. Like they're just using the loop aspect of reduce and actually don't use the thing that makes reduce, reduce. Yeah. And the third category is hashtag I'm smarter than you. Yes. And those were examples where I looked at them and I just couldn't figure out what they were trying to achieve. So my theory is actually that these would fall into category one to three if I could understand what they were doing. Yeah. And I didn't put any examples of category four in here because otherwise people were just explaining the comments to me what this fragment does and that would just be, you know, point. In that thread, there was a, I was asking for examples as well. And yes, there was a lot of times where I had to just like really stare. And like I say, 20 years of experience. I'm not the smartest person by any stretch, but I was had to really stare at the code. And then, thank you. And then once I kind of like, oh, oh, oh, I know what this is doing now. And I would write it as a loop. And so much clearer to me. But then, you know, the code you write is always clearer to you. But yeah. And so I thought I would look at some popular projects, clone them and just do a code search for dot reduce. Spectrum chat. Spectrum chat is a chat. That is really cool. Should have figured that out myself. Written on the Sinclair Spectrum. With React Redux. That's all I remember. But I thought, you know, if Redux is in there, there probably is reduce in there. What was my assumption? And so I just used a couple of projects I knew, looked through the code and picked some examples of good examples for these categories that I have. Let's see them. So let's start. First category. I'll let you take a look and try to explain it. This one is a pretty easy start, I think. Oh, I see. Okay. Yeah. Okay. So you got an array of durations and you're trying to find out the maximum one. It turns out there's a better way to do this. Yes. It is that. Yes. There it is. I'm not sure if this is just a pattern that exists now because spread of the thing. But even before that, you could use apply or call. It's easier to read. Like the entire reduce just is more mental overhead to parse. So I think this would be a preferable way to write it. I heard someone actually say that this hits a limit of argument count whereas the other one doesn't. Now, I've not tested this. So I don't know what that is. Okay. But even then, I think you could fold out to a loop. Right. Or just, and at least contain this slightly overhead version and put in a function called max. Yes. Absolutely. Which just takes an array. Yeah. And even then I'd use a loop. Yeah. Because it would be faster and easier to read. This one I found interesting. Okay. Because I actually am not sure. Yes, you could probably write it as a loop. But it's, so the good thing about this example is they used reduce, but they contain the reduce weirdness in a function. So it takes, gives an array of values. Oh, I see. And you want to basically accumulate them up for each. And each one is the accumulation of the last IC. And as long as you put it in a function, it has a descriptive name. I actually kind of don't care how you implement it because the functions that use this function are going to be quite easy to read. Right. You could use a loop in here. I don't think it makes a big difference. So it's starting to get to the point where the things I dislike about, I've just noticed there's an extra line of this code missing. Anyway. What is it? Yeah, the final thing. Some of my brain's all on fire now. It's just starting to get to some of the stuff I don't like about reduce. And one of the, it's a problem for quite a few functions in JavaScript. The arguments are in the wrong order. Yeah. Right? Like if you've got a callback, that needs to go last. Right? Or it needs to be because the simplest code is read sequentially. True. Like a loop is fine because you go down and then you go back. But it's still sort of sequentially. Whereas here to even start to understand this, you have to go to the end of the thing and then read back from there. And yeah. And also this is creating a lot of arrays as well. I mean, I know you didn't, you're not willing to talk about performance. Oh yeah. That's what you think. I think I mentioned it. I didn't want to talk about performance because I feel like the first order that you look, when you look at code, should be readability. Absolutely. Performance should be a second priority most of the time because, and that's only because we have reached a point where the community looks at performance first to the point where they have reached a point of return of investment is just not there anymore. They optimize things that don't need optimizing at all. And some people sacrifice with ability in favor of performance that they don't need. Right. But this is doing, it's sacrificing readability and performance. Potentially. Yes. I may most put this in because I wanted to show that if you put it in a function that has a good name, you can get away with more in my opinion. I absolutely agree with that as well. And even then actually, I would then take the opportunity to just put it in. Sure. But then you have it well contained. You can write tests. You can do the refactoring in one place. A lot of people don't like mutations. Yeah. In code. But if you're limiting it just to one function, it's okay. Yeah, I would agree. Definitely. The next one, I found that interesting. But it's one of the classic examples. Basically you get a, you get, you have a list of edges, which are between two points in a graph. It's trying to build the graph, which you can look up for a start edge, all the connection that a start edge has to all the end edges. And this is this example where you're abusing reduce just for the loop aspect. And the detail here is the thing that is put here comes out here and it's just returned. It's the same object every time. It's just a loop. So really if you have that, just use loop. And this is actually, I think, so much easier to understand what's happening because you create a map, you loop over the edges, you add sets for the edges if they don't exist yet and then you just add the individual edges to the array that corresponds to it. Yeah. If you, and now I know some people like, oh, but this is not pure. Like I said, like some people like the pure aspect. But the pure version is just not as readable. I tried to write one and it like, yes, it is potentially understandable. But I don't think that is worth for purely sake. Yeah. Especially because JavaScript to me is still not a functional programming language. You can write functional code in JavaScript, but it's not functional programming by nature or by design. Yeah. So like readability is tangible. It's subjective, but it's tangible. You can look at two things and go, that's the one I prefer. Performance is tangible, right? Even measurable. It's measurable. You can see that. But when people say like purity, it's like, well, but what do you get for it? Right. And I understand like you can actually gain a lot of reliability by avoiding mutations. But again, if you're isolating that into one function and the mutation doesn't happen outside of it. If small self-contained functions are your building blocks, then you can work with mutability inside those well-defined scopes. Because mutation is happening somewhere, right? Yeah. Those ones are turning to zeros and vice-versa. Okay. At some point. So yeah. Okay. Let's carry on. This one I found cute. And this is one of these examples where something that exists now probably didn't exist. It is flat. Right. And so I was like, okay, let's give them the benefit of the doubt because probably flat didn't exist at the time they wrote it. Yeah. So what they should really have been doing is just error. Which probably didn't exist at the time. Yes. But even then write a function that's called flat because when I see this code, I have to read it and like you go, huh, huh? Oh, it's flat. Yes. Which is a semantic abstract that makes so much easier to read. So if flat didn't exist, just write this code, the previous code, and put it in a function called flat. Yes. Absolutely. Which just makes it easier to read. Yeah. And again, even if I was writing that function, I would avoid the many array create. Oh, okay. Here we go. Yeah. Even then you would use a loop because once again, and I know that some people have problems with the whole, oh, you create a variable and then you mutate it in a loop. But I think it's easier to read. It's easier to follow what is actually happening. And if you're, yeah, trying to be strict about mutations, as long as it's held within one function, like we said, I'm fine with it. Couple more examples. So this one I looked at and I was like, holy crap, this is unnecessarily complicated. Because what they're effectively doing is they're creating an empty array which they are concatenating to and returning. So it is kind of like, oh, this should probably be a loop. So we're appending. And this I look at and then I realized, oh, they want to put commas in between the individual links except for the first and the last element. Oh, hello. It's joined. It's not, is it? It is joined. However. However. This is a list of VDOM nodes of JSX. Right. So a join that basically intersperses element between already existing elements and returns a new array doesn't exist out of the box. Right. I see. Yes. So this is actually a thing where this one would give you the wrong results. You can't just use join because the join returns a string. But again, write a function that's called JSX join or something which just makes it easier to pass of what is actually happening. So what it's trying to do is put the text node with a loop or in between. Right. I see. Okay. Yeah. Fair enough. Once again, I feel like a loop write a function. Functions don't cost anything. A loop would have made that so much clearer to me. I acknowledge it's subjective. Loop would also work, actually. That's a good idea. I just like in this case, you get a bunch of links and a bunch of issues and you turn each issue in its own link tag. The map here, I find very expressive. Yes. Oh yeah. I mean, but yes, you would have to change it so you're returning. Like you could do it as a flat map. Exactly that. Yeah. So you, because you, it's valid to have an array where it's a JSX element and then a string, which will be a text node. Yeah. Okay. Flat map is the thing, which is also pretty new. Yeah. Again. Just write your own function. All right. Okay. So we've got the usual problem of just passing the object around and around and around. Yes. So this is basically something we would say write a loop, except in this case, we're building up an object. And when that's happening in modern JavaScript, we're building an object from entries. Yeah. So basically what they were doing is they just look at all the events that were there and creating a new object that has a function for each of these events. So in this case, you could just use, turn it into an entries list, map over the values, change them how you like, and then turn it back into an object. Yep. This is actually borderline readable to me. I feel like if this gets a bit more complicated, a loop might be easier to read. Yeah. And again, like if the idea is you're wanting to assign it to a constant rather than, well, actually even, you wouldn't, it would be a constant anyway because it's an object and you just rotate it right. And again, farm out to another function and it's fine. Yeah. Agreed. Now this is something you already mentioned to me earlier, so I didn't talk about it anymore. But this, so here's someone who put it in a function and wrote a comment. Really good. You're allowed to use reduce with a comment and an explanation like, I wouldn't have written it this way necessarily. But you put it in a function itself and it points to the person who wrote this. And you add together the top left bottom and right properties of each client track but keep within height of the first one. Right. Oh, interesting. So that's what they're doing here. And now that I've read the comment, I can almost immediately see that that's what's actually happening. Personally, I would have written it like this where I would actually make the code give the explanation and that I would turn each property into a sum. However, if this is a hot path in your code, iterating over your rectangles four times or iterating and mapping and summing, this could potentially be a performance consideration at some point. Yes. In which case you can turn it into a loop, a single loop. Potentially, yes. So, yeah, the reason we started talking about this and then you told me to shut up because you were going to be talking about it in this episode is when, you know, I stuck my neck out and said, reduce is bad. Obviously, I'm likely to be releasing in the next month and just like to say, have I used reduce? Because, you know, I'm not a bit of a hypocrite sometimes. And, like, I used reduce a few times for adding stuff together. Yeah. The one exception was kind of similar to this. I had an array of client rect objects and I was finding the the bounds, the total bounds of all of those. And I am still into minds of whether it's a good use of reduce. You would find the minimum of top, maximum of bottom and the maximum of right, basically, right? Yes. So, you could map in Max and Min. Yeah. Would be fine. Potentially. More expressive. But, you know, as I said, this was put in a function so I'm less inclined to actually get annoyed by it. I really just dislike when there's like a reduce in the middle of a bigger function and then I have to stare and figure out what is the semantic equivalent of that reduce. Yes. And that's probably the, any tricks you do if you can isolate those into a single function. Because sometimes tricks make the code really fast. Yeah. Or if you are chasing file size, which probably shouldn't be, but if you are, yeah, putting that stuff into another function, even if it's only used once, a good minifier will be able to inline that. Yeah. And so you get the benefits of documentation and readability and you still get to use your trick in it. Yeah. Exactly. Do I have more? I think I have some more. So, this is a pattern I've seen quite a bit actually where this filter boolean application is basically a way to say, only keep the truthy values. That's quite, that's kind of cool. It's a fun trick. I would, I would only spell it out, but. But is a filter like F, maps to F, like it's also not much more expressive. I feel like this is actually a bit more expressive in the sense what it does. True. True. You could say it reads like filter the booleans from the other day attacks. Yeah. I guess it could also be misunderstood and I did actually write a piece of filter like F. Arrow F. Arrow F. And, yeah, in this case I was actually trying to get rid of the empty strings. Yeah. Yeah. Actually, that's good. I don't know which one and maybe I should have done F equals equals empty string would have probably been the more expressive way of doing that. So, what they do is they get the edges, they filter out the falsi values and then for each remaining one, they start with zero and if the node is seen, they don't increment the count and otherwise they do. So, they're basically counting the things that are not seen. I see. So, I feel like this should be done differently because what you could just do is like you map to is seen then map out the boolean and just say dot length. Right, of course. So, this is going to be either, yeah. Either it doesn't exist or it is. So, it's going to be false. Yes, yeah, that's much more obvious to me and it's nice that it's, one of the things that I like about the functional programming thing is it, for example, it's simple code is sequential. Yeah. And this is a sequence of steps that execute. And if it was a series of function calls, you have to read them inside out. Yeah. Which is not sequential. So, yeah, I like that element. Agreed. Yeah. This is another example. I think of a combination of things really where you just, they reduce over a list, see if it has a thumbnail and if it has a thumbnail, it gets pushed into a list. So, really, or if you want to use the new pattern that we just showed, you can map first and then just fill out the dirty values. Both of these work just fine. All right, this is all the examples that I have. Okay. But I thought, these are code examples from these real projects and some more, like this is real code out there. And I feel often you can have more expressive, more readable code. Code, not cold, although you have an expressive cold. Yeah, you're just making me feel bad because you're allowed to use reduce. It's not as wagging our fingers just saying, like, here's how we've come to the conclusion that most of the time reduce can be replaced by something that we would deem better. And it is something that like, let's say, I have made this mistake in code before and much worse mistakes with lots of tricks. Like, I often felt like going back a few years, my attitude to coding was like, I was doing all this smart parkour when I could have just walked down the street and got there faster. Yeah, pretty much. Even if you feel like seen by this, if you think, oh, yeah, that is what I'm doing, you're not alone. So one last thing I want to point out, obviously if you have these nice sequential type of a map and a filter and another map and a flat map or whatever, some people might be worried about creating all these intermediate arrays for the individual steps, which JavaScript will create under the hood. Like, one map will take the original array and create a new array. It doesn't mutate the existing array. It doesn't have a function applied to it. If people are worried about the intermediate values and arrays being created, there is also a way of doing this with iterators. Oh. So I'm going to plug a super old project of mine. OK. Which is called underdash, where I basically collected all the functions that underscore and similar libraries provides and have little two to three line implementations of them. You can just copy paste. So rather than having a library for it that you download and install, that you need. And I have it for arrays, but most of them also have a synchronous iterator and an asynchronous iterator version. So instead of chaining array methods, you could be working on iterators which basically prevents all the intermediate arrays being created. Yes, because it's passing. It's like a stream. It's basically streams. Yeah. Yes. And I thought, you know, if somebody is interested in that, take a look. It still exists on my GitHub. Yep. Yes. Yes. See you next time. I'm going to keep that ending. Yeah, I like it. Go for it. Our editor, Lucas, is really cool. Really cool. Really, really, really cool. Cheers, Lucas.