JS is an occasionally functional language
In this episode of JS Party, I talked about my new book Grokking Simplicity: Taming complex software with functional thinking.
Transcript
Now we gotta learn how to maintain the order and the timing and everything and how many times they get run. And functional programming has a lot of tools for doing that, that other paradigms borrow from functional programming. - That's really interesting. You could almost describe it as it's another way of thinking about separating concerns, but in this case, what you're separating is the easy stuff and the hard stuff, and you're making sure that those are dealt with differently so that you can really focus on the hard stuff. - Right. Buy it, so. - Exactly, exactly. (bell dings) - "Bame with for Change Log" is provided by Fastly. Learn more at fasty.com. Our feature flags are powered by LaunchDarkly. Check 'em out at launchdarkly.com and we're hosted on Linno Cloud servers. Get $100 in hosting credit at linno.com/changelog. What's up, party people? This episode is brought to you by Strapi. Strapi is an open source, headless CMS that front enders love. It's 100% JavaScript. Fully customizable and developer-first. Strapi is more than a node framework and more than a headless CMS. It saves API development time through a beautiful admin panel anyone can use. It's open source, it's agnostic. Choose your preferred database and API options using GraphQL or REST. It's self-hosted and GDPR compliant. Control your data, privacy, and cost at all time. It's customizable, create content structures that flex to fit your needs. Customize the admin panel as well as the API and extended content management with custom plugins. To get started, head to the homepage using our special URL, Strapi.io/DSparty. That's STRAPI.io/DSparty and click the Get Started button for a step-by-step guide to create a sample app using Create Strapi app. Strapi is also enterprise-ready. For those who need to unlock enterprise features and services, email gsparty@strapi.io and connect with Maxine, the resident expert on guidance and a special offer for JS party listeners. Again, that's Strapi.io/DSparty. This is JS party, your weekly celebration of JavaScript and the web. We record live on Thursdays at 1 p.m. U.S. Eastern and you can be part of the show. Come hang with us in our community Slack. It's totally free. Head to changelog.com/community and sign up today. Okay, let's get into it. Hey, it's party time, y'all. (upbeat music) Oh, yes, it's time once again, friends. It's JS party time. I'm Jared, I'm your and that friend and I'm joined by long time. JS party friend, K-ball, what's up, K-ball? Hey, hey, glad to be here. Glad to have you as always. And we're joined by a special guest, Eric Normand is here. Eric, thanks for coming on JS party. Yeah, thanks for having me. This is quite a party. We like to have fun. We like to talk about JavaScript and the web. We think these things are fun and so it's a nice combination. So today we are going to talk about some programming paradigms, one specific paradigm and maybe contrast it to some other ones. Eric is a long time FP guy, functional programming and JavaScript is a functional language, sort of, JavaScript is a multi-paradigm language. So it has some functional things to it, it has some object oriented things to it. It's very general purpose in that way. And Eric is an advocate of FP and says that you can improve a lot of things, write good code, maintainable, et cetera. There's lots of virtues to functional programming. So that's the topic of conversation today. Eric, why don't you start us off with the real basics of like what makes a language functional? What does that mean? - Well, that's a really like deep philosophical question, what makes a functional language? - Dang, I was trying to start basic. - Yeah, yeah. So JavaScript, as you said, is a multi-paradigm language. So functional programming is possible in JavaScript. It's actually quite good for, you know, it's above average for doing functional programming. But I don't think anyone would say it is a functional language. So there's other languages like Haskell or Closure or Scheme or, you know, these other languages are much more focused on functional programming and give you a lot more features that support functional programming. So JavaScript is kind of in this place on that graph of like how functional is it? It's more functional than a lot of languages, more functional than say Java, for instance. - Yeah, it's not completely a dysfunctional language like Java, well, it's both functional and dysfunctional. - Right, and it's not anti-functional, dysfunctional. It is certainly possible to do functional programming in JavaScript. - And occasionally functional language. - Right. - Occasionally functional, if you, and of course you have to do a lot of discipline to maintain the functional programming. I like to say that JavaScript is okay for doing functional programming. It's bad for learning functional programming because you can always just slip back into procedural, you know, you can just make a for loop wherever. But it's actually good for teaching functional programming. It has everything you need, but you kind of have to do it yourself. 'Cause when I teach functional programming, I wanna show it's not just some feature of the language, it's a way of programming. And so here is the odd way that you would program in JavaScript to keep it functional. And so I find it, it's pretty good for teaching. - So what is the mindset then? What is the way of programming that is functional versus imperative or object oriented, or any other way? - So functional programming is like an onion. - Okay. - All right. So you can go real deep and there's, you know, some people who go super deep. But that first layer, that first like gateway into the onion. (laughing) - Okay. - Sorry, mixing metaphors. - It's the onion routing, it's like a tour network kind of a thing. - Yeah, I imagine it like, you know, have you ever seen the original show that gets smart, like the intro, where he has like 30 different doors he walks through? - Yeah, and then he holds up his shoe to his ear and talks about it. - Yeah, he has a phone, he has a cell phone in his shoe. Yeah, but he, you go through all these doors, right? And you get deeper and deeper into the sanctum of functional programming. Well, that first door is just recognizing the difference between what I call actions, calculations and data. - Okay. - Calculations are often known as pure functions. They're the stuff you can do in your language that always gives you the same answer no matter how many times you run them or when you run them. Okay, so this is like addition, right? Edition, it's always gonna, two plus two is always four. Doesn't matter how many times you run that. But then there's actions that do depend on when you run them or how many times you run them. So reading from a mutable variable, if you read after someone has written to it, you're gonna get a different answer than reading before the other part of the code writes to it. Likewise, sending an email or writing something to disk. These are all actions because sending the email zero times is different from sending it one time or 10 times. And so making this distinction between actions that depend on time, 'cause they're hard to deal with and calculations is like the first gateway into functional programming. Oh, and data is easy. Data is just the stuff that doesn't do anything. It's just inert, the strings and numbers and hash maps and lists and stuff like that. - I like how simple your language is there, 'cause I feel like one of the barriers to a lot of folks getting into FP is like it feels like there's a lot of jargon and you start talking with somebody and you're like, I just wanna send an email and before you know it, they're talking about monads and you're like, what in the world is all of this? - Yeah, I think that I speak for functional programming as a community, we have over-complicated it. Functional programming kind of has been incubated in academia and you don't get tenure by making stuff easy. You have to find a hard problem and solve it in some weird way, novel way and you don't show credibility by just talking about basics. You have to use the jargon and show that you're like one of the club, right? And you understand this, you earn your PhD by learning all these obscure terms. So like, that's a shame, right? For the rest of the industry, for the non-academic side, that we don't have a lot of good literature that has taken the time to like, let me just shed all that academic stuff and start over and talk like real people without all the jargon. - So when you describe actions, and I'm gonna probably spend a lot of this like trying to map between this, as I said, beautifully simple language that you're using here and like some of the language that I've previously absorbed for FP and things like that, is there a one-to-one between what you're calling actions and what are often called side effects or are those related but not the same or like, how are you thinking about that? - They're related, it's not one-to-one. The one-to-one mapping is, so calculations are pure functions. But that's not, then you have this other mapping of function in the mathematical sense versus the language feature, you know, pure function. So there's that problem there. So 'cause like arithmetic's not a function in JavaScript, right? Anyway, so calculations mapped to pure functions, actions mapped to impure functions. So it's not the act of sending the email that's an action. It's the piece of code that, you know, you can pass around, hasn't been run yet. It's just a closure, right? It's just a function that you're passing around that when you call the function, it will send the email, right? So I toyed a lot with a whole bunch of ideas, like how do I name them so that the words are clear but don't have all the wrong baggage but I don't wanna invent new terms just because. And so I wound up just not using the term effect because, well, I mean, to get deep into it, I didn't wanna call them effects because it's not the effect, it's the cause. All right, I'm talking about the code that sends the email, not the emails being sent. So, and then the cause, like, that's not the right word either, so. - So get us on the same page with regards to a pure function and an impure function. Let's just start at base principles there. Help us for differentiate, if that's the big difference. - Right, right. So a pure function, like I said before, the nice thing about a pure function is that you can call it, you know, as long as you pass it the same arguments, it's going to give you the same result. And that makes it great for testing because when we test, we test on our development machines, we test on the build server and then we wanna make sure that the same function that we're testing is gonna act exactly the same way in production. So we want, by making it a pure function, we get that out of the box that we can guarantee that we can test it a thousand times and it's gonna give us the same answer. An impure function, you can't do that. And so notice it starts to become a lot harder to test. So it might have to read from the database. Okay, now in your test environment, you have to set up a database and put some data in there for it to read. And the reproducibility becomes a lot harder. You have to basically set up the like bubble that impure function runs in to like simulate it, you know, working in production. Because that's when you want it to actually work. It's in production. The other thing about actions that makes them hard besides being harder to test is ordering and the number of times they get called is actually the point of your software, right? Like I want the email to get sent. - Right, like that's the point and only once. - Right, once. - Exactly. Unless this condition happens. - Right, right. I wanna choose if the email gets sent or not and when it gets sent. So now this kind of the point of your program, right, is to like apply the break in the car or not or how much you apply the break and at what time. And so by pushing as much stuff as possible into calculations, we've reduced the amount of hard stuff that we have to focus on, the actions and ordering and timing. We've reduced that so we can pay more attention to it. Those calculations, like I think I like to say that like functional programming in general has gotten it backwards. Like we like to focus on the pure functions. But really the reason we do so much code in pure functions is because they're easy. - Right. - And so we wanna just get them over with and like throw them at the test server and they can deal with them from now on. Now it's the actions. Now we gotta learn how to maintain the order and the timing and everything and how many times they get run. - Yeah. - And functional programming has a lot of tools for doing that. That other paradigms, you know, borrow from functional programming. - That's really interesting. You could almost describe it as, it's another way of thinking about separating concerns. But in this case, what you're separating is the easy stuff and the hard stuff. And you're making sure that those are dealt with differently so that you can really focus on the hard stuff. - Right. - By itself. - Exactly, exactly. - Because the hard stuff is the stuff that actually matters the most at the end of the day because that's not to use the word side effect again, but like that's the point of our programs. It's to change the world somehow, right? - That's right. - Maybe it's just to provide some information and that's it could be a calculation. But most of the time, valuable software changes the world, interacts with the world in a way. And these are our actions. And that's, I haven't thought about that way. I always have, once I started picking up that distinction, I've always thought, yes, I want as many pure functions as possible and I want to minimize the impure functions because easy and hard, right? Easy to test, hard to test. All the things you've just described. But I never thought of it as because the hard ones are the important ones and actually you're then, I mean, it's all important, so relative. But the hard ones, the actions are where the focus needs to be because they're hard, because they change the world, because they're the point, they're kind of the point. It's interesting. - That's right. They're the point, and I really think that in discussions about what functional programming is, we've gotten it backwards that we say, oh, functional programming is all about programming with only pure functions. And I think it's really the opposite. It's like, well, we've got this tool called Pure Functions that will let us ignore them for a while, 'cause we know they're not gonna change and they're really easy to deal with. They're so easy to deal with that we can put a type system on them and the computer can figure stuff out about them. It's the side effects. It's the when to launch the missile. And do I do this first or that first? And how do I guarantee that in an asynchronous environment or a multi-threaded environment? How do I do that? That's where functional programming has a lot to say and a lot of constructs for dealing with stuff like that. - So can we talk a little bit then about what are the language features that are important for doing this? 'Cause as we've currently described it, this is something that you could do in Java, right? Like you could separate out the easy deterministic functions from the actions that are changing the world. And yet as we described, like Java is a dysfunctional language. It is not a good language for functional programming. Whereas JavaScript is reasonable and then there are these dedicated functional languages or languages that are really functional oriented. So what are the sort of layers of language features that make this paradigm easier or harder? - So I think the first one is something that most languages have for this first gateway, right? It's simply having a way of not changing stuff. Like something like machine code, it's like every single machine instruction modifies a register. Like it adds two numbers in stores it somewhere. That's these two numbers in store. Like so you have to modify it and you have to build in like a stack or something to make sure that you can allocate local variables and all this stuff that you don't get out of the box. So most languages that we use every day are have this. They have local variables, they have ways to allocate new memory, new values. And then of course you need the discipline to like, I'm not gonna change this after I said it or I have a list and I'm only gonna do a copy on write which we can talk about like an immutability discipline. But then there's the next gateway which is sort of higher order programming. And to do that, you need to be able to make my first class function as you can in JavaScript. In Java, you can kind of do it with lambdas. That makes it kind of easier. But even if you like, you faked it with classes that you instantiated, you could get by. It just seems very heavyweight to like make up a function or a class called plus then added two numbers, right? But in JavaScript, it's like, you know, especially with the ES6 syntax, it's like six characters. - And just to be clear, when we're talking about a first class function, that is a function that you can pass around as an argument, is that? - That's right, yep, that's it. You can treat it like a value in your language. So it can be an argument or a return value. It can be stored in a variable or even in like the value of an object, a property of an object, put in an array, you know, anything you can do to a number or a string, you can do it to a function. (upbeat music) (upbeat music) - This episode is brought to you by Source Graph. Source Graph is code search for every developer and team. Easily search across all the code that matters to you and your organization. Find example code, explore, read code, debug issues and so much more. And I call it beyond lose CTO and co-founder of Source Graph and ask them to share what code search is, what developers and teams are missing out on and how Source Graph provides code search to every developer in the world. - If you've worked inside a Google or Facebook or any one of these really big, well-respected technology companies, chances are you've used something like code search before and you know the value that provides to your team. You know that almost every single engineer inside these organizations uses it on a daily basis. If you've never had that experience, chances are you may not know what you're missing out on. You know, the term code search sounds a lot like, you know, grep or the search inside your editor. And that's what a lot of people think when they first hear it. But it's really about much more than that. It's really about connecting you as a developer to the broader universe of code and code related data that's relevant to you, that you need at hand in order to enter that, you know, magical flow state of, you know, being in your editor, writing code, quickly making rapid progress towards that feature bug fix that you're working on. It's really about making all that contextual information accessible at your fingertips. And what that means is think about every single repository, every single file and every single language, every single diff and every single open source dependency or maybe closed source dependency that's shared across your organization. All that is searchable through a single text box. And that's really powerful because it means all this friction is eliminated between you and understanding that broader world of code. You don't have to clone stuff down to your local machine. You don't have to mess around with editor config. You don't have to be constantly bugging people on other teams who may not even know who you are in order to teach yourself how all that code works. What source graph is is really a way for the rest of us, the people who don't work inside the Googles, the Facebooks to get a tool that gives us access to that sort of information readily at our fingertips. It's really about bringing this type of tool that a lot of the larger technology companies have developed invested hundreds of millions of dollars into making for the productivity of their own engineers and making that accessible to every single developer in the world. - All right, if code search powered by source graph sounds like something you and your team can use, head to info.sourcegraph.com/changelog and click the button that says try source graph now. You can install it locally, deploy it to a server or to a cluster. You have a quick start guide that takes less than five minutes to install source graph using Docker. So it's too easy to give it a try. Again, head to info.sourcegraph.com/changelog. (upbeat music) (upbeat music) - So we've talked about a couple aspects of functional programming languages. Immutability, would you avoid that word? I wonder if you had your own way of describing it, which was simpler, but I can't remember what it was. Immutability and first class functions. What was the way you described it immediately? Was that on purpose? 'Cause you seemed very careful with your wording. You said like the ability to not change things. - Right, okay. So yeah, I use the term immutability. I've made a very conscious decision not to talk about language features. - Right. - And that's all we ask you about. - Well, that was me. I'm the bad cop. - And yeah, here we are. (laughing) - It's true, you do need some. - We need some hooks. - Language features. Immutability is not a required language feature. - Right. - Because you do it with discipline. - Yes. - You just don't change things. - Exactly, you just don't change things. And so what I am calling immutable is a value that you have, even if it's just mentally marked as I'm not gonna change this, sometimes you get help from your language. So like in closure, the data structures that gives you are immutable. - You can't do it. - Like there's no methods on them that allow you to change them. But in something like JavaScript or Java, like that's kind of the default is that you can change the stuff. So you have to provide the immutability yourself as a discipline. - Mm-hmm. And then we talked about functional, first class functions. So in JavaScript, you can do immutable programming. In fact, there's libraries and things out there that will help you practice that discipline. But it does have to be a discipline because you can mutate variables in JavaScript. - That's right. And it's so easy to just assign to a hash map or an object as a hash map and delete keys out of it. Like if you do any of that, you're modifying it. And any other piece of code that has a reference to it, it's also changed for them too, right? And I'm not saying it's bad. Like it's not bad to do that or to be able to do that, but it's not immutable. - Well, to go back to your language from earlier, you're kind of taking what would have been a calculation and turning it into an action at that point because you are changing the world. - That's right. - And that's dangerous because you're increasing the surface area of your actions. And we already decided that we want to minimize those. - Another thing about actions that I didn't mention was that they spread. So if you imagine function A calls function B and function B calls function C. If function C is an action, meaning it depends on when it's called, then function B has to be an action too, 'cause it calls function C. And then function A has to be an action because it calls function B. So this is kind of like a corollary of the definition of actions, calculations and data. A lot of people tried to put layers and layers of wrapping around mutation so that it goes away, but it can't. If you put it down at the bottom, everything above it is gonna have to be an action. What you wanna do is kind of reverse it. - That's interesting. - And put it all at the top because the top is gonna be an action anyway. Your main function, for instance, that's gonna be an action. There's no way to avoid that. - And have a good piece of software. I ran it and nothing happened. - Something that just adds, adds some numbers up. - I think we'll get into this a little bit more later, but I think that ties deeply into the way that in sort of front end frameworks and their move towards functionality, how they think about where state lives, right? And you wanna push state up the tree so that you can have more and more pure components. - Yeah, I was gonna say pure components, but I was trying to figure out like calculated components. What's a nomenclature we might use here? - Well, yeah, and the move is that they become like just functions of their props. - Oh, all right. - They've written DOM nodes and don't have any state or side effects or anything. I mean, that's the ideal, right? - Right. - Now, do we have to worry about the fact that by modifying the DOM, they are in some ways taking action or do we conceptualize that as they return what the DOM should be and a higher level thing is what's actually having the action of changing the DOM. - Right, right. They are not actually modifying the DOM. They are just returning a value and something else which someone has carefully constructed and presumably tested is managing the actual actions that happen, which is a common pattern in functional programming where you kind of return a data representation of what you wanna get done. So, you know, a simple example is instead of a function looping through a bunch of customers and sending each one an email like inside the loop, you could map over the customers and generate a list of the emails and a data representation. So, you know, the two, the subjects, the body and then something else will loop through that and send off the emails, maybe in batches or however you wanna do it. And that way, you're pushing more and more of the code into calculations and then you just have this little tight loop that just send emails, send emails, send emails, send emails. Doesn't have to do any decision making or anything. It's just a very simple, like, you could, you know, just do a for each on it. - So, we're getting into some of these functional things. Now, we talk about immutability. This is not a feature of JavaScript or something you can do in JavaScript and you have first class functions. This is a JavaScript feature. And so you can pass functions around as values and that's very useful in functional programming 'cause that's what you wanna do. And now you also have these specific language features which are sometimes standard library, oftentimes right there in the language where these are functions which are useful to functional programming. You have map, reduce, filter, et cetera, et cetera. Explain why these lend themselves to make functional programming easy. - Right, so these I call functional tools. They are often, they come in the form of a function that takes a value, often a collection, you know, like in the case of map or filter and a first class function as an argument. And what they let you do is stop writing for loops basically. So for loops are a very imperative construct. They require you to initialize a variable and then modify that variable, you know. We've all done it. The i++ and the i is less than array.length and all that stuff. And instead of doing that, you notice these patterns where look, I'm taking a list and doing something to every element over and over again. I'm doing that in a lot of different places. Like half of my four loops probably are just that. And so instead of writing that over and over again, I can consolidate that into one place. Sometimes you might think of it as drawing that up. And the first class function is what lets you represent the body of that loop. You couldn't do it without a first class function because, you know, typically when you abstract with procedural abstraction, you take like you have a 10 step process and you say, okay, the first three steps, I'm going to name them in a function and then I'll just call them. And then the next steps, I'll name them. And then the last two, I'll name those. And so now I just have a three step function. But you can't do that with a four loop because the four loop needs the opening and closing braces. And you can't separate them syntactically. Like it's just not valid syntax to do that. So there's no way to have like, here's the two breads, the two pieces of bread for your sandwich together. And then define the ingredients on your sandwich separately at a different time. Well, first class functions let you do that. So you can replace a four loop with a four each. And the four each does the same thing looping through an array would do where it gives you access to each element and then you pass in what you want done to each element as a function. And so anyway, we have a bunch of tools like this. What I really like about them is they're very simple. Like you could write them yourself. They're not like some complex thing. You probably have written them yourself. Maybe you didn't know it. So map is like three lines long, four lines long, filter it's a few lines. Reduce starts to get a little bit more complicated, but you could write it in a couple of lines. And there's a number of these. Low dash has a bunch of them already built in. I know a lot of people use low dash. It's a really great tool for that kind of thing. And so the reason I think that they're useful is it lets you transform really complicated nested four loops into a sequence of steps. So you look at the four loop and you're like, I really have to trace through in my head what's happening in every iteration and like keep track of two nestings of like what's going on at which point. But if you turn it into a chain sequence of functional tools, it might be four or five steps. And each one is really simple and clear what it's doing. So you could, you know, this nested four loop could have some conditionals inside. So like that conditional could be turned into a filter. It's like, oh, I'm only dealing with the even numbers. Okay. And then the next step is for each of those numbers, we're calculating a string, an offset in the string. Okay, that's a map 'cause you're calculating based on the input. And then, you know, it just becomes this like sequence of what looks like linear steps operating on collections of data. Yeah, and it's very easy to reason about, right? Because you see those boom, boom, boom, boom. And you can just like hop into the middle of that and, you know, insert another thing right there. That's right. Or take that thing out. When I first learned about this approach, it was probably one of the biggest productivity improvements that I've, or leaps that I've had in my career programming because it changes the way that you think about this and gets you used to thinking about things as a series of transformations to the data. Right. Right. And it really forces you to think about the data kind of pipeline of how it's going through, which is in many, many examples, a much more productive way to think about it and a much simpler way to think about it than trying to think imperatively what are all the things I'm doing to a single item. Yeah, you think smaller 'cause you think in smaller steps. Whereas in the past, maybe you started that for loop and then you got your editor like right there inside the for loop and you're like, now what are the eight things I gotta do to get out of here? Right. Right. But instead you think like what's thing one, I'm gonna do that, what's thing two, right? You think in those smaller steps. The other thing is you can just, you know, let's say you do the first step. You can just print it out. You just print out the value you got, you know, test it out right there. Whereas if you're in a for loop, you're like, well, I haven't done anything yet. Like I've just got this local variable that I've been like accumulating stuff in, but at what point do I print that out? Like at the end of the loop, but then something else happens to it. So I can't do that. You know, so having these steps, each one is an immutable collection. You could print all of them out at, you know, you have like a record of everything you've done. And then the other thing is like often for loops start out really easy. And then as you add features, they accumulate local variables and conditions. Conditionals and stuff, and so they just become really hard to work with and modify. But if you've got it in steps, it might not be a linear series of steps. It might be four series of steps, right? But you can reuse the first two steps for the next set of steps. Like, you know, you can compose these however you want, but each step is clear. Each step shows you like, okay, I've gone from a list of all numbers from one to a hundred to a list of only the multiples of three. And that's a concrete step that is easy to understand. - So there's probably a lot of people out there thinking, holy cow, I've been doing functional programming this whole time, I just didn't know it. I hope so. - At least in some parts of my code, right? - Yeah, what I've noticed is like a lot of people get to the map, filter, and reduce and well, they stay there, yes, they get it and they use them really productively and that's great. But I would implore people to look at stuff that low dash gives you besides map, filter, and reduce. There's a lot of other cool tools that could like really be great in your toolbox. One I really like is called frequencies. So if you have a sequence or any collection, but let's say it's an array of values, it's surprising how often it comes up where I just want to know how many of each thing I have, like how many twos do I have, how many threes do I have, how many tens do I have? And you could write that really easily. You know, it's just a loop through this array and you plop it into a hash map with a one, but if it's already in the hash map, you just add one to it, right? You could just write this and now you have this reusable, very abstract reusable function that is useful in so many algorithms. - You use that all the time. - Yeah, yeah. So there's that one, there's one called a group by, which is similar, which instead of counting them, it actually puts them together and the by means, you're passing in the function of how to group them. So like, let's say you have an array of users, user maps, right, user objects, and you wanna group them by like the first letter of their last name, something like that. You would pass in this array and you would pass in the function that can calculate the first letter of their last name, given one of them. And then it will make a map where like all the E's are in an array and all the B's are in an array. And there you go. Now you have them, you know, grouped in this way, and that's great for making indices. If you need an index, so that you can do quick look up by a certain value, like the first letter of their last name, it's great for algorithms. - Yeah, 'cause you avoid nesting because you effectively return yourself, what is conceptually a list of lists, and then you're just applying the next operation on that list of lists, and then you're back to, you can flatten that back out and keep going. - That's right. - Yeah, that type of grouping is often a super valuable performance improvement too, 'cause I so often run to code that I'm coming in, having to make it scale after the fact where folks have written something that basically does a nested pair of loops, right? That's where it scales quadratically. It's like, okay, for this case, go and find-- - For all the A's, loop through and flip through. - Right, to figure out if it's got an A, okay, now for all the B's, loop through, yeah. - Exactly, and you do a pre-group by, single iteration through a list, and then you list through the set of things you need to check, and you transform the quadratic operation into two linear ones, and suddenly it's fast. - It's so funny because, you know, we often think of making a data structure as like an expensive operation, but these days, people have so much memory on their machines, like a little hash map. I mean, literally this hash map could have at most 26 entries in it, like it's not big. And you're not copying the users, right? Those objects are just being referenced. So when you think about how little is actually being allocated, it's not that much. You've got 26 entries in a hash map and 26 arrays. And the rest is all just referenced to the original user object. So, you know, we're like counting pennies over here, and people have millions in their iPhone. (laughs) (upbeat music) - What's up, JS Party people? Have you ever wondered if you could be offering a faster, less buggy experience for your customers? Well, with Ray gun error and performance monitoring, you have all the information you need at your fingertips to quickly find and fix errors and performance issues across your tech stack down to the line of code. Ray gun makes it easy to mark the impact of your performance improvements, quickly identify issues across web and mobile apps, and see how your code performs in the hands of your customers. This saves you time, this saves you money, and this saves your sanity. Head to raygun.com to learn thousands of customers and took software teams who use Ray gun every single day. Again, raygun.com to get them to try with a free 14 day trial. (upbeat music) (upbeat music) (upbeat music) - So, one thing that I think has brought functional paradigms very much front and center for many folks using JavaScript is the trend in front end frameworks and react in particular to move towards more functional paradigms. And so I'd love to kind of get your sense of both, what are the parts of that that are working well? What are the parts that are unintuitive? And how do some of the kind of more react specific concepts like hooks and things like that play into your mindset when you think about functional programming? - Okay, this is a big topic. So I think react is a great thing for the functional programming world. Just making these ideas more popular. The thing that is really the most functional that I see is this idea of a thing and a component that takes props and returns DOM. And I don't know how old the audience is, but I remember jQuery and I remember having to keep track of what the view has in it and what I need to change. And then every now and then being like, I'm just gonna re-render the whole thing 'cause I've lost track. And it was really hard. And you're basically doing your own little ad hoc virtual DOM each time. So this technology of the virtual DOM, this trick, is a really cool way of making it for the programmer a very pure function experience. And then having like the React team figure out the virtual DOM diffing and actually modifying the DOM one time for everybody. So everyone using React is getting the benefit of that one development. And so I think that's great. The stuff I worry about when I see people in the wild actually using React is them making impure components. So components that will like call out to the server to get like user data whenever they're mounted into the DOM, right? Now they're doing it with hooks, but they used to do it on like component will mount or whatever lifecycle method they chose at the time. And what that means is now your component is an action. It depends on when it mounts and how many times it mounts and you have the same problem. And you see apps that have this issue where every component on the page, the idea is like the component is supposed to be self-sufficient. It's supposed to know where to get its data from and how to get it and it's gonna get it when it needs it. And so you've totally given up any ability to control how many requests it makes or when they get made. So you have a thing where on a page it might make a hundred requests at the same time. Those are gonna get queued up in the browser in some random order because you can't control it in an Ajax in a asynchronous environment. And then maybe three or four will go out at the same time and like you're just waiting on them and they're all blocking each other. It's like the opposite of what I dreamed of when I first started using React. In the React it's supposed to be very reactive. You click on something and it changes instantly without a loading spinner and stuff like that. Nowadays we've like re-implemented the page refresh poorly. So I think that that's the wrong direction. I see too many people, what I really think it is is that people don't know the functional ideas. They haven't made this first gateway step of actions and calculations. It's distinguishing between them. And they're thinking of components as the building blocks of their whole application. When really they're just the building blocks of the view. They're just supposed to be used for projecting the state into HTML. I mean, this is my opinion as a functional programmer, okay? Like I know there's a lot of ways to write software, but this is the mistake I see as from my functional programming perspective. I do a lot of closure script and we don't do that in closure script. Closure and closure script, they're functional languages. And what we do is we keep the state outside of the DOM mostly. Sometimes you have a little bit of state in the DOM where it makes sense. And when I say when it makes sense, I mean like if you have a panel that opens and closes, like that open closed state, that can be in the panel. It's tiny. It doesn't have any effect on anything else. It's fine. It doesn't hurt anything. It's so manageable that you're not gonna get into trouble. But the user's information, come on, that's gonna be used in several places, right? Like the law, you're gonna have like a little avatar up at the top, you're gonna use the username somewhere in another component. So you wanna get that out of the DOM, just get it out. Because it needs an Ajax request, like just take it out of the DOM. So we don't put state in the DOM and we do all of our Ajax stuff outside of the DOM as well, outside of the components. - One question on that. So thinking about the React paradigm in different ways, like there are many different folks who use it in more or less kind of functional ways and I love the language play of the English meaning of functional as compared to our technical meaning there. But there's trends towards, okay, like every bit of state should be done in a component that renders no view and then it should use its own set of components that are pure and there's things around that. But one thing I was wondering as you're talking about the approach you use in Closure Script is does the model of context and context providers get closer there if you use context providers to manage the data, or is that not quite what you mean? - It does get closer, so this is funny in Closure Script. We were one of the first adopters of React. I remember David Nolan, the maintainer of Closure Script was like experimenting with it back in 2013 and I looked at it back then too. And then sort of all these, there was like an explosion of wrapper libraries in Closure Script in 2013 and 2014. And we kind of set the trajectory back in 2014. So we haven't kept up to date with all of the developments in the React world, I mean, it must have been like React 10 or 11, like when we stopped doing new features 'cause we had everything we wanted. We had the virtual DOM, we had a better event system that React gave us and like what more could you want? Like we can make a wrapper to provide anything else. So we don't use context that much, but I am somewhat familiar with it. It does get closer, I still think that the big problem is that it requires those context wrapper elements and that you can't make modifications outside of that. So this is what I'm talking about. I like to keep my state in a global variable. Okay, so an object that has like a semantics in a global variable and that way I can do like, what if I want to make a web socket to the server and the web socket's gonna send me data and I wanna put that into the state? Why should I have to go through a component to do that? The context requires you're still in the DOM and you have to use some kind of a hook or something to get a setter for that state, that context state, and then get it into the web socket like that's weird. How does you do that? Like without all these problems. You can just have a handler on the receipt. I don't remember what it's called in the event in the web socket world that like I just got a message, like you handle that and you just update the state. And then because React is reactive, it should just re-render everything that's looking at that state. So that's what I see as like one of the problems. It's like a lot of workarounds when why don't you just not have it in the DOM and you won't have all these problems. I do think another great advance is the hooks. You know, they're composable, which is really nice that you didn't have before with class-based functionality. But then the other thing which is very functional is, so your components are functions, right? And so they have arguments. These are the explicit inputs to the function and they have a return value, which is the DOM that they are returning. And so in a strict sense, like that's all you get. You shouldn't have any other inputs to your function, right? Otherwise it would be impure. But with hooks, you can like do a use state or use something and you're getting data from outside of the props, from outside of the arguments. But the nice thing is it's all at the top and it's all kind of declared, you know, and it's a very declarative format. And so you're bending the rules because this functional programming stuff, it's all a mental construct, okay? Down at the level of the machine code, it's all mutation everywhere, right? You just wanna be explicit about where is the data coming into this function? And hooks make that easy 'cause they usually go up at the top. And so you can see, okay, it's getting stuff from the props and it's also getting stuff from this other thing and this, you know, et cetera. So that's the other good thing I like about it. - Well, I have to say, Eric, you are very good at explaining these things and you're reasoning. I like how careful you are with your words. As I said at the top, you've been doing this for a very long time. I think 2001 is what your bio says. You've been teaching FBE to people for like 14, 15 years, something like that. A long time, right? - Yeah. (laughs) A long time. - Yeah, a long time. So you've had a lot of like iterations on like how to explain these concepts. - Yes, yes. - And I think you've gotten very good at it. I should say for those who wanna hear more from Eric, we had you on the change log back in 2017. Can you believe it was four years ago talking a lot about similar things 'cause you've been beating the functional programming drum for a very long time and that was a well-received episode. So I'm sure we cover similar but different ground on that. We'll link that one up in the show notes. And you're also working now on a book. Like I said, you've been teaching this stuff for a very long time in person, online courses, books, videos, all the things. You're working on a book right now called "Grocking Simplicity." You wanna tell us about it? - Yeah, sure. So the book is about functional programming. It's the kind of stuff we've been talking about. The first part is all about actions, calculations and data, how to refactor actions into calculations, how to implement immutability and also how to do your functional tools and how to chain them. And we also talk about something we didn't talk about much is how to manage your actions. So there's a lot of stuff that once you get into first class functions, you can start to build little primitives, little tools for managing the order of actions or managing how often they get called. And so those become like higher order functions, functions that take functions. And so we go over stuff like that. We also do a little bit of design and architecture of functional applications. The whole idea is that functional programming isn't like this, I don't know, field of study, this abstract field of study. It's a set of practical skills that industrial programmers, meaning like people who work on commercial software that we use and to look at it in a more practical way and start to document what we actually do because so much of the literature is academic that there's not much to build on for someone who's like getting interested in it and just wants to get some practical stuff. And also it's practical whether you go all in in functional programming or not. These skills are very practical for building software. And sometimes it's exactly what you need and it'll help. - Yeah, absolutely. And I think it's sometimes hard. I think a lot of times the way FP is presented, it is impractical, pure, and academic. And I think you're doing a great job of bringing it to the pragmatists, they're the ones out there trying to use these things. Like I said, in some cases, in small ways, people using it without even realizing it, it's empowering to know what you're doing and how you can embrace that and follow through to its full extent. So one thing that's cool about this book is you do have some exercises and some other things as well. So not only are you reading these things, but aren't there ways you can take that? Because it's a way of thinking. And sometimes you seem to practice that way of thinking, right? - That's right. And so there's opportunity there. - Yeah, I mean, even just identifying the actions and the calculations, people have told me early readers, 'cause it's in early access now, it should be published soon, but people have told me like, wow, that has changed the way I see all the software. And I can now say like, oh, this is gonna be hard because look, it's an action. And all this other stuff, oh, that's easy to test. Let's just test it, get it out of the way. Like those kinds of things really help people. And I haven't seen anyone, you know, besides this book, even in my previous content, 'cause there's a lot of work. It wasn't just like me writing down what I know. I had to like figure out like, what's the best way to teach this? Or just like why I came up with actions, calculations and data and all these little mnemonics for remembering this stuff. This is stuff that we do and changes the way you see programming. And no one had gone through and actually broken down functional programming to this basic level. You know, when you read a functional programming book, they might have one or two sentences explaining what a pure function is. Well, we spend the whole first part on that, right? We spend eight chapters just talking about like what's a pure function? How do you make them? How do you recognize when it's impure and convert it into a pure function? How do you make data immutable? All the stuff that like is just kind of like a footnote in other books. Like, you know, I basically take a step back and say, this is the stuff that people need here. You're not teaching the meat of it. You're just teaching the, I mean, I call it froth, right? It's the froth of like, oh, once you get all this other stuff, you can go super deep. You're four levels into the onion and you're doing all this cool stuff. But no one knows how you got there because you're not making a path for people to follow from where they are. And so that's what I tried to do is like figure out where people are and bring them. So the book is called "Grocking Simplicity." It's published by Manning. And it's available in early access. So you can get it now. If you buy it now, you'll get the updates. And once it's finalized, you'll get the printed version. - So I think those mental model shifts are where the goal is, right? Like I mentioned, I think early on in my programming career, the shift of thinking about loops and into map and filter and like as data pipelines, just massive, it's a mental model shift and it massively upped my productivity. And I, when you started talking about this distinction of action and calculation and thinking about that, like I can already see myself, I'm thinking about that now. Like I've learned about pure and impure, but that shift, that shifted something for me and I'm excited to explore that. I'm curious if there are other mind shifts you have identified through your teaching or through going through this book that also provide those kind of step function changes in how you view programming. - The third one that I deal with in the book. So just to do them in order again, the actions, calculations and data, then the first class functions and higher order functions. So just even learning that oh wait, plus isn't a function, it's just an operator, it's part of the syntax, but I can wrap it in a function and now it's first class, right? That's a big leap and being able to pass it to a function and that's another leap. The third one is starting to think about having a, I call it first class, maybe that's the wrong term, but an explicit model of time. So when you're dealing with any domain, the domain itself is not going to always match the languages model, right? So for instance, if you have a function that sends an email, every time you call it, it's gonna send that email. But your domain says, wait, I shouldn't send it more than once, right? So how do you make an explicit model of time, which is like once only, how do you make that out of the implicit model of time that your language gives you? Okay, so you have something like, how do you coordinate all these Ajax requests that are coming in at random order? You put them out in a certain order, but they're coming back, however they come back. And so you need something to reorder them in the order you want them to be in. And promises is one way to do that, right? But we talk about different approaches and different constructs similar to promises that you can do. So you're actually making a new model of time that like, this is the order that things need to happen in a way. Like so here's one, a simple one I can describe quickly. Let's say you have two things, two Ajax requests you need to send off. And you need to wait for both of them. Okay, I know you can do promise.all that exists, right? But let's say you don't have a promise, you want to do it a different way. You can't put a call back on like the one that you think will take longer because it's not how Ajax works, right? Like they just come back in random order. So you can create a little object that records how many times the, let's call it the done method gets called, right? So that object has a callback. And when the done method gets called twice because you have two Ajax requests, it will then call the callback, right? And so this is equivalent to like saying, like you go to conferences a lot, like after the last session, you're like, hey, let's meet down here for dinner, right? Well, you don't know who's going to get done first, right? So if you get to the lobby and there's no one there, you have to wait because the other person's coming. And but you both follow that rule and you meet up and you go to dinner, right? So you want to make little simple rules like that that you can put into your code. This is like a new model of time. There, that's the third one. - I think you've sold me here. I definitely need to check this out. I only have one model of time and it's the one that's always running out. We have friends at Manning. We've been working with them for a very long time and they've been kind enough to give us three free ebook codes for Eric's new book, "Grocking Simplicity". Like you said, it's in early access, but getting close to done now. And if you get it now, you'll get the final version as the updates come out. So three to give away and all you have to do to enter is just join the JS Party channel in our Slack because we're going to keep it easy. We're just going to give it away to our friends in our JS Party channel of our Slack. So if you're not in there, hop in at changel.com/community. Totally free, totally easy and totally fun to hang out with us during the show and in between shows as well. Of course, if you do not win one of the three codes, we also have a coupon code for all Manning products. 20% off all Manning products use coupon code pod. JS Party 20 at checkout to redeem that. Eric, this has been a great conversation. I feel like we really did just kind of scratch the surface. Just some froth on the conversation, but you did a great job of explaining things to us and answering all cables, hard balls and my soft balls. Thanks for coming on JS Party, it's been a lot of fun. Cool, thank you so much, this was fun. Support our work and help ensure JS Party continues into the future with a changelog plus plus membership. Ditch the ads, get closer to the metal and directly contribute to all of changelog's podcasts at changelog.com/plusplus. Once again, that's changelog.com/plusplus. Music for JS Party is provided by the mysterious breakmaster cylinder and we're brought to you by our awesome sponsors. Thanks again to Fastly, Linode and LaunchDarkly for their continued support. Next time on JS Party, there's an imposter among us as Matt Ryer from Go Time joins the panel. We're talking the biggest stories from around the community, sharing things we've learned recently, dropping some unpopular opinions and collecting a few new jingles as we go. Stay tuned for that one. It'll be ready for your ear holes next week. [MUSIC PLAYING] [MUSIC PLAYING] So I've got to get props before I go back in to Igor for the best drop in the chat room so far. He says, "FP is like an onion. If you go deep into it, it makes you cry." [LAUGHTER] Nice. I like that one. There's your hater there, Eric. Yeah. They're everywhere. Everywhere you find a hater. [MUSIC PLAYING]