AJ_O’NEAL: Well, hello, hello, and welcome back to another exciting episode of JavaScript Jabber. In this week's episode, we have Luis Satencio from Florida here to talk about the joy of JavaScript.
LUIS_ATENCIO: Hello, everyone.
AJ_O’NEAL: Also joining us from Tel Aviv. Everyone, please give a warm welcome to Dan Shapir.
DAN_SHAPPIR: Hi, hi. Hi, everybody.
AJ_O’NEAL: And it wouldn't be a bright day without Amy Knight.
AIMEE_KNIGHT: Hello from Nashville.
AJ_O’NEAL: And last and certainly least, Stephen Edwards.
STEVE_EDWARDS: Thank you very much. Hello from Portland. Somebody's gotta be the least, might as well be me.
AJ_O’NEAL: All in good teasing. Now let's get this one dog pony on the road. What does it mean to find joy in JavaScript. Is this a new religion based on like some sort of semantics and grammar? What are we talking about here, Luis?
LUIS_ATENCIO: You got me AJ. I secretly, I'm recruiting. That's what I'm doing here. So I figured you guys, you know, I figure I get the biggest audience by doing a JavaScript Jabber. So that's exactly what I'm doing is recruiting for this religion.
AJ_O’NEAL: That's great.
This episode is brought to you by Dexecure, a company that helps us developers optimize images, JS, HTML, fonts, videos on your own website automatically. With Dexecure, you no longer need to constantly chase new compression techniques. Let Dexecure do the work, and you can focus on what you love doing, building products and features. By integrating Dexecure in 10 minutes, you'll get a lower CDN bill, increased website traffic, and faster website than your competitors. Visit dexecure.com slash JavaScript Java free trial offering 20 gigabytes, CDN bandwidth and 110,000 optimization requests free every month.
AJ_O’NEAL: The world needs more religions that declare themselves as religions rather than hiding in the secret. So tell us what's, what's this about? I mean, you lead the way here. I don't know much about the joy of JavaScript. I've been using it for 10 years. I know about some of the other things.
LUIS_ATENCIO: Yeah, absolutely. I've also been using it for about as long. So the joy of JavaScript is, well, it's, it's two sides of it. One is, uh, Manning as the publisher has sort of the joy of series, right? They do joy of other books as well, other programming languages. And so this is the JavaScript version of that. And the second side of it is basically JavaScript is my favorite language. And so I did want to write about how, you know, I have fun using it in what ways. And so really it's all about putting JavaScript in the perspective of using it with like a multi-paradigm perspective. You guys, we met, we talked about functional programming a couple of minutes ago. And so the way you can use JavaScript and all the options it gives you, for better or for worse, to do things like functional programming, to be able to be used in a reactive manner, to be used obviously as an object-oriented language. And what does that mean, right? Which is object-oriented but not class-oriented. And so it's really the true meaning of object-oriented programming. And so those are some of the highlights of the book and what it emphasizes.
DAN_SHAPPIR: Speaking of religion, hallelujah, because I've had this argument about whether or not JavaScript can be considered an object oriented language. And I'm definitely in the opinion that it is because in JavaScript essentially everything can be, is an object or can be used as if it were an object, but you're right. It's not a class-based object oriented programming language. And there are some people out there who think that if you're not really class-based, then you're not really object oriented.
AJ_O’NEAL: Which does not include the author of the original object oriented paper.
LUIS_ATENCIO: That's true. And so if you look at it from the, from the point of view of the original definition of object oriented, it only discusses things like encapsulation and the message passing, right? Which is basically calling methods on objects and sending, sending data to other objects and that's exactly what JavaScript does. And it does really, really well. The whole class mentality and that whole, you know, class oriented mental model is just a layer over that. Right. And I've used Java, C sharp, Python, and all these other languages. And nothing feels more O O than JavaScript to me, at least, I guess, as a, in the true nature of the definition.
AJ_O’NEAL: So I want to unpack that for a second. Oh, go ahead, Dan.
DAN_SHAPPIR: No, I was saying that that's definitely correct because in all of these other languages, you cannot invoke a property on the literal number 42 and in JavaScript you can
AJ_O’NEAL: once it's expressed as a value.
DAN_SHAPPIR: Well, you can actually write 42 dot dot to string and it'll work.
AJ_O’NEAL: I think you have to put in parentheses to do that.
DAN_SHAPPIR: No, you don't. You do need to put two dots rather than one. And can you guess why?
AJ_O’NEAL: Oh, okay. Dot was not a word though. That was, this is new to me. Tell me.
DAN_SHAPPIR: Because one dot would be considered the decimal point. Oh, so it's a syntax thing. It's a syntax thing.
AJ_O’NEAL: I thought-
LUIS_ATENCIO: The second dot is what does the boxing.
AJ_O’NEAL: Okay.
DAN_SHAPPIR: And by the, can you clarify what you meant by boxing?
LUIS_ATENCIO: So it's that second dot that actually will behind the scenes, take that value, that primitive value and box it into an object so that you can invoke methods on it, technically speaking.
AJ_O’NEAL: But if you wanted it to not look strange to people and you want it to be polite to your fellow coders, you would do four D two dot zero dot so that they don't get confused thinking that it's a typo or one of those weird things like.
DAN_SHAPPIR: Well, to be honest, you probably aren't going to be invoking methods on numeric literals anytime soon anyway.
AJ_O’NEAL: Oh, I will. Don't you worry, because I came across this case one time where I wanted to do some number dot something. For some reason, it was probably a two-string or two fixed or whatever to concatenate as part of the string. And I had that, I am grateful for this moment. I feel like a noob, but I was gonna talk about, you know, classical programming, functional programming, blah, blah, blah. I feel like programming languages that are modern, meaning that are created, say, after 1984 or so, pretty much all have all of the paradigms that are necessary to do most of the things that you want to do with a language. Like I don't know where this concept of like, well, this language is object oriented and this language is not object oriented even comes from. Unless you're talking about stuff like bash or, you know, like assembly, what, or I guess, you know, see itself is not super friendly to objects, but like, are there any languages that are not object-oriented aside from the ones I just mentioned?
DAN_SHAPPIR: I would look at it from a different perspective.
AJ_O’NEAL: Okay.
DAN_SHAPPIR: JavaScript and certain other programming languages like C++ are multi paradigmatic programming languages. You want to go like, like what I said before, if you want to go the object oriented route, you can. If you want to go a functional route, you can do that as well. You can even do procedural. But there are programming languages that have been created after 1984, which are not multiparadigmatic and intentionally so. For example, Java kind of forces you into the object-oriented model. There are other programming languages that run on the JVM that take a functional approach, like let's say Scala. But Java itself, you know, you can't have a top level function in Java. You can kind of hack it using static methods, but really in Java, you can't have a function that's not associated with a class.
AJ_O’NEAL: Okay, that's well that brought us to a very good definition. So, object, pure object oriented, non-functional, non-functional, I guess, would be a language where you can't have a function exist by itself. Is that what we're saying?
LUIS_ATENCIO: I think non-functional means a lot of things, but yeah, I think that's one of those.
AJ_O’NEAL: Well, that's that's a probably a pretty powerful one if you can't pass functions around or...
LUIS_ATENCIO: Right, correct.
AJ_O’NEAL: Okay, okay. All right. All right, I'll buy it. Okay, I'm schooled.
DAN_SHAPPIR: And Java did that intentionally because Java came out at the height of the OOP craze and you had C++ as a multi-paradigmatic programming language. And Java kind of said, no, no, we are going to jettison all this weird C++ syntax. We're going to be a more smaller, more coherent programming language. And one of the things that they decided to do was just to focus on object-oriented programming. So yeah, so there's that. But you know, that's Java. Let's go back to JavaScript. So Luis, we were talking about the joy of JavaScript. So we mentioned that one of the reasons that you really love JavaScript and it gives you joy is that it's multi-paradigmatic.
LUIS_ATENCIO: Right, exactly.
DAN_SHAPPIR: Can you elaborate on that? Do you actually use multiple paradigms as you code or do you just like the fact that they're there if you ever want to use them?
LUIS_ATENCIO: Yeah, I do use them. So we have at work, actually, we use this, we code with this mentality of this doing a hybrid model. So we have people with different backgrounds and a lot of them will tend to start writing classes immediately. And so, you know, it's kind of that mental model that they're used to, and it doesn't make sense to, to go against that. And it doesn't make sense to, you know, force things, right, and have it to be a bad experience. You know, if you're familiar with that sort of mentality, you can go ahead and use it. But then we, we always we always delegate out into sort of functional components. So we have modules and we have the classes, right? Classes tend to be the more mutable, you know, your typical class with methods and attributes and things like that. But then when you have to perform business logic, we tend to encapsulate those in modules, right? Of functions, like is that top level function inside a module, which you can easily do in JavaScript. And that forces you to be sort of separated from that class-oriented mentality. And now you basically pass all your arguments into these modules of functions that take that business logic and implement it. We tried to do that as pure as possible with no unintended side effects, and all of these good principles that come around when you start to do things functionally. Just there in that example, you can see how basically we have a hybrid object-oriented programming model with a functional programming core that takes care of that business logic piece and make things a little bit easier to parse, a little bit easier to maintain, and definitely easier to test. That's just one example. Then you can take that and build upon that and you say, well, in the browser, we use a lot of Angular, and so we're using a lot of these reactive programming techniques through observables and through RXJS and things like that. So now we have really all three, where you have the events and all the data come in, process through a set of functions with your business logic that we tried to make them as pure as practically possible. And then you can always hydrate a model of classes that are all kind of in an object oriented fashion, right? So now you have all three combined and really, JavaScript lets you do all that seamlessly without friction. And that's one of the things that I think is amazing about the language that lets you do that.
DAN_SHAPPIR: You mentioned a couple of functional programming terms or while you were describing this, you mentioned pure functions and you talked. You mentioned reactive. Can you elaborate on that?
LUIS_ATENCIO: Sure. So object-oriented programming, I think we spent a few minutes on already. The functional programming side is where you look at your program as just a set of functions that carry out, that do some work. And all of what they need is provided to them as arguments. You don't go out and assume that you have some global state or some shared state somewhere. Everything that you need should be provided to you as arguments. And that makes things a lot more self-documenting and a lot clearer and a lot easier to test because you can easily just pass any test parameters that you need to these functions.
AJ_O’NEAL: So no scope.
LUIS_ATENCIO: Well, so, and I noticed that I said as practically possible, right? It's good, we do tend to do, you know, we do tend to take advantage of closures. I mean, if you're coding with JavaScript, coding with closures is one of the, you know, one of the best things you can do. And so with that, you encapsulate within functions, you're going to encapsulate scope, right? But not out to a global scope or not out to shared state. That's what we're definitely trying to get rid of. And a lot of people would try to declare these global variables and start using them. Like, no, no, no, no, we have to put things in modules. If you need this data, you pass it to as a function. You don't assume that you have a global scope somewhere, right? And putting things in modules helps you do that.
DAN_SHAPPIR: But at the end of the day, you know, there are states. We all like to ignore it or avoid it or not think about it. But then at the end of the day, there's going to be some sort of a global thing that contains your applicative state and you're going to be modifying it. So how do you go about doing that in a let's call it functional way?
LUIS_ATENCIO: Yeah, so you, you know, I think that the key term is the practical, right? So there is state and that's the reality. And the reality is that you do have to write to the DOM. You do have to write to files and write to a database and read from database. What you try to do is basically is to, and this is what we're trying and it's worked out really well is to move it to the boundaries, right? Move state changes out to boundaries. And what that basically means is try to keep your business logic as removed as possible from the either the backend technology that you're using or whether you have a browser or not or whether you have a window object or not, those kinds of things. Try to not make any assumptions about that. When you need to write the data, just write the data. Create a function that basically takes care of the writing piece, call that function when you need it, but then you can always use things like, if we're talking about functional programming, you can always use things like composition to stitch together the business logic pieces with the writing pieces. Now you're just isolating the state changes out individual functions that you can test separately in a different type of way. Because you can't test things that assume that you have a DOM, you need to test in a certain way. You need to be able to mock this and do that. Test functions that rely on a database, you need to test differently. But if you have business logic just sitting in these functions, you can test those without making any assumptions. You can test those easily by themselves as isolated components. So that's what we try to do is just as practical as possible, the reading, the writing, all these side effects. That's what we call them side effects out to the boundaries as much as you can.
AJ_O’NEAL: So I find one of the things that makes logic difficult to test is the, what you referred to earlier as the dehydration and rehydration, the database boundary. Like once stuff starts to go to SQL or to documents or whatever, it seems like that's where, that's where it gets tough to, especially when you have interactions of things or APIs for that matter. How, what's a good paradigm to help make code testable when you have like these complex interactions of things that have relationships, whether in a database or through an API?
LUIS_ATENCIO: Yeah, so you're talking about, just to clarify, a piece of code or some kind of program that to carry out all of its purpose, let's call it that way, it relies on fetching data from APIs and reading and writing to a database and things like that, right?
AJ_O’NEAL: Yeah. So like you've got a process and the process needs to do some work and then, and then it needs to save something maybe in a draft stage, and then it needs to do some more work and then it has to market as completed or, you know, you, you have these things where the logic is not complete except for if the logic includes things that modify beyond the edge boundary.
LUIS_ATENCIO: Yeah. So, you know, you can, you can do that with. If we talk about it from an FP perspective, then you can do that by, like I just said, just trying as much as possible to have a clear boundary between the two, to have a clear boundary between when you need to click on a button and get the reaction of that click to the code that goes ahead and processes that click and does something else with the database. As much as you can, you try to decompose that logic into a collection of functions that you can test in different ways. Business logic on its own gets tested really simply, and then things like rely on these external resources get tested in a different way. But as much as possible, try to see if you can decompose and isolate these components to their own function. That way you can either assume that they're there and test them, or just plug them in and compose all of it together to basically carry out the entire business logic that you're going for.
AJ_O’NEAL: This may be something that's hard in an audio only setting, but, you know, if you can imagine this function that's say 150 lines long and it has everything that needs to be done, it is complete in terms of, it describes a process in the way that a human might understand the process from beginning to end to say this process was started, it accomplished its tasks, and then it completed. So when you break that out into multiple functions, sometimes it feels like it becomes really awkward because you're doing like half of the task. And then you're doing an important piece that has to deal with one of these edge boundaries, like an API or a database, and then you're doing like another portion of the task. And so then it can feel like the, the, the set of functions become less readable because now they're more abstract and there's always that balance. Like procedural programming is perfectly easy for a non programmer to understand, assuming that the variable names use full words. And then as you get more and more towards dividing these functions up to the point where, maybe there's only two or three lines in them, then you get to this point where you have to hold a lot in your head in order to be able to make sense of it. So-
DAN_SHAPPIR: AJ, I have to contest the premise of essentially everything you said.
AJ_O’NEAL: Excellent, excellent.
DAN_SHAPPIR: Because I think you're looking at it from the wrong direction The way that you're describing it is as if you have a working Thousand line function.
AJ_O’NEAL: I actually said 150 but we'll go in a thousand
DAN_SHAPPIR: and you're thinking hey, this is too long So I need to break it up and then I count down Let's say 20 lines and then arbitrarily decide to break it there and count another 20 lines and again arbitrarily break the function up.
AJ_O’NEAL: Not arbitrarily, but where their boundary conditions are.
DAN_SHAPPIR: Yeah, but that's the wrong way to go about it because you do that's a bottom-up type approach that's exactly the wrong way to solve problems in computer science. The way that I go about it is I go from a top-down approach. I write the top level, I take a complex problem and instead of trying to write it out as a single super complex function that has many, many lines, I break it down into a series of simpler problems like assuming that I can do this and assuming that I can do that. It's like writing a pseudocode and then each one of these steps becomes its own function and I repeat and I rinse and repeat. I keep on breaking things down into simpler and simpler and simpler functions. So it's a top-down approach. In fact, my son is studying, started his computer science bachelor's degree right now and I'm helping him with writing the code in the intro to CS course and that's the one thing that I'm really trying to hammer into his head about taking complex problems and breaking them down into smaller and simpler pieces and each and do this repeatedly and iteratively. So it's not that I start with really long and complicated function and then I have to break it up. It's the fact that I have, I'm always building smaller, small functions that rely on the existence of other functions, which I then implement.
AJ_O’NEAL: Well, but it's, it's not like, well, In some cases, for example, homework assignments, there is a solution that is a correct solution that pre-existed before you approach the problem. And all of the business logic was determined before you approached the problem. But in the real world, the reason that we get paid is because we're solving problems in a way that is somehow unique from the way that it's been solved before. Otherwise, we could, you know, just use a library and we're done with it. Right. So in my experience, the way that this seems to happen with most people and anyone, feel free to contradict me. But in my experience, what happens is people get some information and they start to build and then they get some more information and they start to build and there's a deadline and they need to add this thing to it. And then later you come back around and you say, Oh my gosh, this is terrible. How are we going to make this something that we can test and something that we can feel confident shipping to our customers and making updates to and then you do have to work backwards and break it down. So I'm, I, I a hundred percent agree with you on the approach of taking a problem and breaking it down into pieces. But I think the way that people get into the situation that I'm describing is that the problem was not delivered as a complete problem. It was delivered as the business needs arose.
LUIS_ATENCIO: AJ this is where, you know, this is where refactoring becomes so important. Right. And I don't remember who the author was or who said it, but I think a code that code that doesn't get refactored decays quickly or something like that. Something like that.
AJ_O’NEAL: Yes, it does.
LUIS_ATENCIO: Yeah, exactly. And so like you said, things are like they don't come in all at once. And definitely we all we've all been there where requirements change on you unexpectedly, right? The the ability to decompose in a top down form, just like Dan was saying, and thinking about problems as smaller functions allows you to be more flexible two changing requirements because now you don't have to refactor necessarily to avoid duplication because now you needed that function and you needed to perform that with different types of conditions some other place because the requirement change. So I think that approaching it as smaller problems, approaching it as encapsulating the business argument that you need into functions and then with that mentality, we'll give you more agility when it comes to changing requirements.
AIMEE_KNIGHT: Yeah. Something I wanted to add here too that I feel like we're leaving out of the argument We're kind of talking about functional programming from the developer perspective and working in the code. But I mean, really, I think it's important to understand for people who may not be aware or used to it, functional programming came about because of distributed systems and trying to handle I.O. better. So while it's like it does in some ways, I think make it easier for us to write code that's functional for testing and those kinds of things like we talked about. I mean, the why behind it really, I think, is the distributed systems.
LUIS_ATENCIO: Yeah. To avoid the share multi-threading issues and things like that.
DAN_SHAPPIR: Said like a true DevOps person.
AIMEE_KNIGHT: Exactly. I got to bring in the infrastructure side here.
DAN_SHAPPIR: I totally agree with what Luis said. Breaking down the problems into segments enables easier refactoring down the line. And sometimes the refactoring entails changing or shuffling up the pieces that you've broken it down into. So maybe a function starts to grow so complicated, so complex that you feel the need to break it into two functions. But I never write an entire piece of complex code as just a single large function and then go about breaking it. I still remember to this day, a program that I saw that had 10 functions called init1, init2, init3, and so forth because they did exactly that. They had this huge init function. It became unwieldy, whatever, and so they broke it into 10 init functions, but because they just essentially broke it down arbitrarily, they just called it init1, init2, and so on. And that's, well, that's definitely a code-smap. And I think that one of the things that distinguishes between a capable or an experienced or whatever developer and one who isn't, is their ability to decompose problems into smaller, simpler problems and then solve them that way.
LUIS_ATENCIO: Yep. So
AJ_O’NEAL: one more- It's tough man. Oh, go ahead.
LUIS_ATENCIO: Sorry, AJ. I was just gonna add that the ability to do that, to be able to take a problem decomposing into simpler problems is one skill. And the other one is abstraction, right? The ability to take sort of an approach of simplifying the problem through building abstraction. Those are the two pieces that I find, you know, a lot of people struggle with and it's not something that you can easily learn in school and things like that. It comes with a lot of practice and things like that.
AJ_O’NEAL: So here's my question, which you gave me an excellent lead into. If most people are not very good at creating abstraction, and that is a difficult mental model for them, what is the burden of creating the abstraction that allows for cleaner, better code. But like, what does that do to the mental model of a person? Because like I, I've had this conversation with people, which is why I'm bringing this up, right. Is that I say, okay, well, let's take some of this code and let's, let's try to break this down and we spend a little bit of time on it. And we, we try to identify the components and the boundaries and, you know, and, and maybe we'd spend an hour discussing you, what was this supposed to do? Why was this implemented this way? What are the side effects of this? What are the conditions, you know, just trying to understand like why, how did this arrive to the place where it is? And then we, we, you know, we break it down and we end up with like, well, here's a function that's build widget and here's a function that's insert into cog and, and so on, and then at the end of it, I've gotten the feedback. Well, I guess this is great from that perspective of, yeah, we did make the code better. But now it's harder for me to work in because now, whereas before I understood this process as a whole of the 150 or 200 or 250 or 400 lines. Now I have to understand this process in terms of, I have to go look up what the widgets doing and I have to go look up what the cog is doing. And I have to, you know, like, so
DAN_SHAPPIR: I have to contest this for two reasons. First of all, because nobody can keep in their head all the complexity required for a really large function. If you've got a multi-screen function, you just can't keep it all in your head. It's too complex. Human brains don't work that way. I mean, computers could care less. That's why the, you know, some optimizers inline functions, for computers it's fine. But for people, if it's beyond the size of a single screen, then I just can't encapsulate it in my brain. It's difficult for me to figure it out. And the other point is that when I break it down into smaller functions, and there's this point of trust that you, assuming the function that you use passes its tests, you can trust it to do what it's supposed to do. So I don't even need to think about how it achieves the thing that it does. If I invoke a function that does a sort, I can trust it to sort. I don't need to have an implementation of quick sort in line into my source code.
AJ_O’NEAL: I mean, that, that example that you gave, I think is somewhat of a straw man in that it's so obvious that no one's going to argue against it. But, but, okay. So let me, let me just ask this then what I described. Do any of the others of you feel that that is common? Have you seen that kind of pushback before? Have you observed that before? Or am I just observing something that is kind of niche?
DAN_SHAPPIR: I'll tell a story. Sorry, Luis. I'm kind of kidnapping you at the episode, but I have this amusing story. So one of the first projects that I worked on, I was recruited to work on developing like kind of mini games, which is funny because I really don't enjoy playing games myself, but you know I enjoy writing them so I really like working in that company and they hired two of us more or less at the same time. Both of us I was out of the army, he was out of the university, but we were both recruited to into the company to develop mini games and I was creating this 3d shooter and he was working on a backgammon game I think or a checkers game I think it was checkers game and I finished the 3D shooter and he was still working on that checkers game and kept explaining how difficult and challenging it was because it was turn-based and yet it was between several people over the network and synchronizing the turns and it was so difficult. Okay, I worked on a flight simulator game, he kept on working on the checkers game. I think that by the time I finished my third game and he hadn't finished his first, he was let go. And then we were a small company VP of R&D of the company asked me to look at his game and at the code and see if I could just finish it. And it was written in C and when I opened the file, it was just, the whole project was one file.
AJ_O’NEAL: The way it's supposed to be.
DAN_SHAPPIR: Exactly. And that one file contained one function. For those of you who know C, it was one big main function.
AJ_O’NEAL: And it's got the four right up at the top, like it's supposed to, right?
DAN_SHAPPIR: Exactly. All the way down something like I don't know, several thousand lines of code of a single loop. And after looking at it for five minutes, I went back to my boss and told him, look, if you want, I'll rewrite the game from scratch. I'm unwilling to try to fix this code because there's no way that I can understand what's going on here. And I think that's the point. The whole point of being a good developer is being able to break down a problem into smaller problems, implement those smaller solutions for those smaller problems in a way that satisfy the tests, then you can trust the results and then you can reuse them without having to think about them until you do.
AJ_O’NEAL: And I absolutely agree with that. Luis, what did you have to say earlier?
LUIS_ATENCIO: Well, you asked if we had seen that and definitely AJ. So that's, I mean, that's, I've seen it more where when people try to, you know, they get some kind of task a JIRA assigned or something like that. And they just jump immediately into it. Okay, well, you know, start coding. Like they're quick, they're quick at coding, but they've forgotten to just say, why don't you take a step back and see how it plugs into the rest. Maybe you can, you know, do this portion in a reusable manner so that you can, you know, benefit from that, or you can, you know, plug this here and do that. So taking just a step back at it and maybe building a little bit of abstraction so that you can interface with other components. That would have been a much better solution. More, you know, it would have given you all those great benefits. Right. And that's where, where I've seen it the most is when they just start coding blindly, like they just put the blinds on and they start typing and what you get is that game, right? You get that one file, you know, everything is in there, but now you can't, you know, for you to be able to troubleshoot one aspect of it, you need to read to the entire program, right? That's why one function approach doesn't really work because you need to read through the whole program just to fix one bug, right? You can't really, you know, you can't really separate things, assume things and separate, you know, that the sort I know, sorts the fetch, I know fetches, it must be in this area, right? You can't do that anymore, right? You have to read through the whole thing. Everything is tangled together.
Have you ever wondered if you could be offering a faster, less buggy experience for your customers? I mean, let's face it, the only way you're going to know that is by actually running it on production. So go figure it out, right? You run it on production, but you need something plugged in so that you can find out where those issues are, where it's slowing down, where it's having bugs. You just, you need something like that there. And Ray Gun is awesome at this. They just added the performance monitoring, which is really slick, and it works like a breeze. I just, I love it, I love it. It's like, it's like you get the ray gun and you zap the bugs. It's anyway, definitely go check it out. It's going to save you a ton of time, a ton of money, a ton of sanity. I mean, let's face it, grepping through logs is no fun and having people not able to tell you that it's too slow because they got sidetracked into Twitter is also not fun. So go check out ray gun. They are definitely going to help you out. There are thousands of customer centric customer focused software companies who use RayGun every day to deliver great experiences for their customers. And if you go to RayGun and use our link, you can get a 14 day free trial. So you can go check that out at javascriptjabber.com slash raygun.
DAN_SHAPPIR: I think that was really well said.
AJ_O’NEAL: Yeah, I definitely-
LUIS_ATENCIO: Thanks Dan.
AJ_O’NEAL: I definitely agree on all these. Anyway, I believe that there's probably some people out there that are encountering this with other people and that are, or that-you know, hold these hold these beliefs dear and I am wondering, you know, just trying to pull out tease out. How do we how do we challenge that and is there some validity to it? And one thing that I don't think anyone else is really latched onto in the way that I was hoping is I think that there is validity to that when you abstract things it does become more difficult to understand to some degree than when things are not abstracted something that is hard coded, that is a set process, that is not reusable. If it's a thousand or 10,000 lines long, no. But if it's, you know, a hundred, 150, 200 lines long, even if it doesn't fit on a single page, I believe that there are cases where the abstraction pulls it into a place where it is less approachable to some people. So
AIMEE_KNIGHT: I- I agree with that.
AJ_O’NEAL: And I'm not saying that's what we should strive for, but I think that in order to make the argument to there's a better way, there has to be some buy into there are benefits to the way that isn't as good.
LUIS_ATENCIO: Yeah. I was just going to say, AJ, that I think you're absolutely right. Um, so you, you don't even consider, or I at least won't even consider whether something should be done with this paradigm or that paradigm, if I'm only writing 150 lines of code, I mean, if I, if I'm only writing 150 lines of code, it's just get it done. It's, you know, it's a script to me. I just consider it as a, as a small program, just, just get it done because really, you know, it probably can fit all in one. When we talk about applications, right, then all that theory is thrown out the garbage, right? So, you know, when you talk about applications...
AJ_O’NEAL: You could have many 200 line functions that are encapsulated to some degree.
LUIS_ATENCIO: Well, yes, but 200 line functions, when you talk about 200 of them, right, now it's hard to keep the whole thing into consideration, right? Because if 200 line functions are talking to each other...Now it's really hard to keep track of the whole thing. And we talked about, I think, Dan, you mentioned the cognitive overload or something like that earlier. Now it's almost impossible to keep track of everything. Again, if you're building a single program and it's 150 lines of code, there's really nothing much else to think about other than how that program is being used, sort of where the inputs and things like that. But when you talk about how that one function fits into a million other lines of code and it's 200 lines long, then it becomes an issue. Right? Because that function is doing a whole bunch of things that maybe should be, you know, or well, maybe should be done in much simpler functions that could be. I'm sure some of that part of that logic could be reused somewhere else. Or maybe you build the wrong abstraction and maybe that's why it's so hard to understand. If by building abstraction, you make something harder, then that's probably the wrong abstraction that was built.
DAN_SHAPPIR: Again, I totally agree. I would just add that while I like using small functions as units. I hate arbitrary limitations. So if, you know, I've seen people use a cyclomatic complexity or other types of rules to restrict the size and complexity of functions, and I dislike that because it always gets me into a position where I want to add just one more thing into a function and I can't because I've hit some arbitrary restriction or wall and I have to split something that should not be split.
AJ_O’NEAL: You just put a semi-colon there and put it on the end of the same line.
AIMEE_KNIGHT: So I want to push back there on what Dan said. I mean, I feel like having those constraints in place are really good. I mean, there are escapes that, you know, if you're, if you're linting for that, you can, you know, ignore that function or something. And I feel like it's better to kind of, you know, whitelist things, like whitelist a function by saying, okay, this one might be more complex, so we're going to, you know, not lint this one. Then that's a little bit better.
AJ_O’NEAL: It's an AES algorithm. It has to be 500 lines long and the variables only can be one letter because we need 26 of them.
DAN_SHAPPIR: All I have to say, Amy, is I'm very much in favor of linting tools. I always use them in my projects and I think they're a very powerful mechanism to let's say, for example, in force consistency across a project in an, in an organization, but every time I need to use one of the escape hatches. A little bit, a little part of me dies inside.
AIMEE_KNIGHT: I mean, that's, that's, I feel like that's a good thing. Like you should feel, I'm not, I don't mean this like any personal way. Like you should, you should have to think twice about it.
DAN_SHAPPIR: Yeah. It's just that I've run into situations with function size, even though I really keep, usually keep my functions really small, really, really small. I have run into situation with file sizes and it always feels very arbitrary to me.
LUIS_ATENCIO: Yeah, and escape hatches tend to be abused, right? And once you ignore it once, now you've basically opened it so that anybody else can just use that. But I also agree, you know, so I agree with Amy that I think generally it's having a guideline is good. And then you always have to balance that out and you have to kind of trust, right? And use the, you know, the code review process and things like that to enforce the second part, which is you need to be able to also escape it out sometimes. Where some algorithms require it, a deeply complex algorithm probably needs to be in its own separate function. It might have a cyclomatic complexity that is higher than X number, but it just needs to be there. It needs to be as a unit. And so it should be acceptable that we can do that. Now, always there's that balance, right? It's not an exact science, this thing. So use the, uh, you know, use, use the review process to basically try to enforce. And if something is splitable, then then do that there.
AJ_O’NEAL: So this quote comes to mind, which is not about programming per se. And I don't, it's only subsidize the behavior that you want more of. And I don't know exactly how that applies, but I've got the little spider sense that tells me that, you know, part of the review or the reward process or whatever, whatever it is that you're rewarding or subsidizing. You're going to get more of even sometimes in ways that you didn't anticipate. So be careful about what you are funneling towards, I guess.
DAN_SHAPPIR: I do want to move us into another topic before we run out of time. So I was really, I was looking through the content of, of Louisa's book, the joy of JavaScript. And there's one chapter that caught my eye. And I do want a chance to talk about that a little bit at least, and that's meta programming. So can you tell us about that?
AJ_O’NEAL: We didn't even change topics.
LUIS_ATENCIO: Yeah. So the meta programming chapter is basically the, the artifacts in JavaScript that allow you to do things like reflection and introspection. So that chapter is pretty fun one, actually. So it's, it starts about using symbols and then using the, the, the well-known symbols JavaScript, where you can use to hook into, you know, to create hooks so that you can change the behavior of things like a for loop or a for a weight or, you know, then things like that.
AJ_O’NEAL: Okay. Pause symbols in JavaScript do not mean symbols as I am familiar with them. What is a symbol in JavaScript?
LUIS_ATENCIO: It's just an, uh, an object with an opaque value. It has an opaque representation, like a unique value that that's all it is. And so they're good for making them collision free properties and objects.
AJ_O’NEAL: Okay. That was a little bit abstract for me to quite grasp what maybe you could tell me. What is it? What, what's three lines of code that might use it or help me understand a little better.
STEVE_EDWARDS: Um, concrete examples. Yeah. So it'd be good.
LUIS_ATENCIO: Yeah. Suppose you need to, let's say that you need to define a property that you only want accessible within that object. So a symbol, a private property, somehow you want to emulate something like a private property and you don't want to use the whole syntax of classes and things like that. You can do it two ways. You can do it using the closure, right. Encapsulate in the closure, or you can assign a symbol, create a symbol for it and use that symbol as an object as the key to that value, right?
AJ_O’NEAL: Oh, so this is like before we had symbols, if I'm understanding this correctly, if you wanted to do that behavior, what you'd do is you'd create an object because every object is unique. So you just create an object literal, and then you would check if the the value of that object was?
DAN_SHAPPIR: It's a little bit, let me try to explain it a little bit differently, AJ. So first of all, let's start by saying that symbols are a basic type in JavaScript. So, you know, we are familiar with strings in JavaScript and we are familiar with numbers in JavaScript and there's the undefined.
AJ_O’NEAL: And regular expressions, right, Steve?
DAN_SHAPPIR: Well, actually, regular expressions are considered to be objects. But so that's another. So that's another basic type that you have in JavaScript is objects. So JavaScript has a few basic types, not a whole lot. Those are the different values that you get when you apply a type of operator on some, you know, variable and see what the type of whatever it contains. And it turns out that the symbols are yet another basic type in JavaScript. And if you put a symbol and into a variable and then do a type of form on it, you'll get the string symbol. So it's really basic in JavaScript. And so that's one aspect of symbols. And the other aspect of symbols is that they can be property names. So if you've got simple object in JavaScript, up to a few years ago, property names or property identifiers were always strings. You might use something else, but it got converted into a string. So you did x.Hello, hello would be the property that had, as it's a key, the name hello. And now you can also use symbols as properties, property keys in JavaScript. And Luis, you want to add on that?
LUIS_ATENCIO: Sure, so one example of that, AJ, let's say that I think there's something that the Node.js team implemented a few years back and then they might've deprecated it. You could, and any object that you, any custom object you could declare an inspect method to return a string representation of the objects, something like a two string. Then in Node.js, you can use something like console.log, and then console.log internally would check to see if you have an inspect method and do it and then return that representation. Otherwise, maybe it will bubble up to object per type.toString to return it. Something that fell out of that was, well, anybody can write an inspect method on any object and do something completely different. It's, you know, it wasn't, it was meant to return on a string representation, but now people, because they didn't know, they used it as a function to do something else, to maybe, you know, read from the database and do an inspection there or something like that. Right.
AJ_O’NEAL: They completely changed the purpose of the properties and increment the by one.
LUIS_ATENCIO: Right. Exactly. So the purpose of the symbol being that it translates to a unique name is that now you you can check for the symbol itself. You don't have to check for a well-known inspect method that could mean anything to anybody, but you can use a symbol to hook into that since it's unique and you can't really override it or anything like that and use that as the string representation function. Because to that symbol, it's just a key, it's just a name. You can assign a function, you can assign a value. You can hook in and use it. It would have been best to use, to hook into looking for a symbol instead. That is a, something that's a little bit more clear than just an inspect method. So, and use that to, to return a string representation. And in fact, I think JavaScript is, has something similar with the well-known two string tags symbol. Something similar to what they wanted to do there.
AJ_O’NEAL: So this is kind of like if I wanted a non innumerable random number that is only known by one part of the program. And I guess this would be most useful in areas where you have third party scripts running together with other scripts and you want to keep some information hidden or private from a potential malicious code that ends up in those scripts. It sounds like this is more of a security concern than a make developers life happy concern.
LUIS_ATENCIO: I think it's an interoperability concern. So it's not security concern because you can definitely use methods to inspect on the symbols. You can use, I believe it's called has-owned property symbols or has-owned symbols or something like that to enumerate symbols. Now, you can enumerate them just because you can enumerate them. Doesn't mean you can access those properties.
AJ_O’NEAL: I think I get it. So this, this is like, I could put, I could have a symbol where my symbol name is something like name and another part of the program could have a symbol where the symbol is something like name. And so we could both be accessing name on the object, but we could be getting our own private value of what name is.
LUIS_ATENCIO: Right.
AJ_O’NEAL: That clicks for me. Okay, thank you. The joy of JavaScript.
LUIS_ATENCIO: And that gets a little bit more confusing when you talk about the registry. So what you refer to there are two local symbols using the local registry. I create a symbol with a name key, and a name descriptor, and that name really has no meaning, other than just for the developer to read. Because internally, it translates to just a unique hash, a unique ID or unique value. So we can have two just like you said, and we won't collide. Then there's the global registry where you can register a symbol globally to the entire application, and that's where you would do things like interoperability. I can inspect that symbol of an object somewhere else in the application to call that function or to do things like that. Typically, that's where you see the JavaScript, the well-known symbols that they have to do things like. I want to modify the iteration behavior of this object that I have. And that has a lot of...