CHARLES MAX_WOOD:: Hey everybody and welcome back to another episode of JavaScript Jabber. This week on our panel, we have Amy Knight.
AIMEE_KNIGHT: Hey, hey from Nashville.
CHARLES MAX_WOOD:: Steve Edwards.
STEVE_EDWARDS: Hello. This is Steve Edwards known as the fun guy, not one of the smart guys, by the way.
CHARLES MAX_WOOD:: Dan Shappir.
DAN_SHAPPIR: Hey from Tel Aviv, where yesterday it was almost a hundred degrees, but today actually quite nice.
CHARLES MAX_WOOD:: AJ O'Neill.
AJ_O’NEAL: Yo, yo, yo. Coming at you live from where I'm pretty sure it was snowing yesterday.
CHARLES MAX_WOOD:: I must've missed that.
AJ_O’NEAL: In the past couple of days, it definitely has snowed, but like you wouldn't have noticed because it went to rain right away or it was melting in the air kind of thing. But we had some snow recently. It was insane. It's 46 degrees outside. Come on. The weather can't make up its mind. Are you warm or are you cold?
DAN_SHAPPIR: I can tell you that it's warm here. It's we're feeling the beginning of summer for sure.
CHARLES MAX_WOOD:: Nice. I'm CHARLES MAX_WOOD: Max Wood from DevChat.tv. The reason that I'm asking AJ this is because I flew back home from Nashville yesterday. So I may have missed it in the morning, but.
This episode is sponsored by Sentry. Sentry is the thing that I put into all of my apps first thing. I figure out how to deploy them. I get them up on the web and then I run Sentry on them. And the reason why is because I need to know what's going on in my app all the time. The other thing is, is that sometimes I miss stuff. I'll run things in development, works on my machine. We've all been there, right? And then it gets up into the cloud or up on a server and stuff happens, stuff breaks. I didn't configure it right. AWS credentials, something like that, right? And so I need to get the error reporting back. But the other thing is, and this is something that my users typically don't give me information on, is I need to know if it's performing well, right? I need to know if it's slowing down because I don't want them getting lost into the Twitterverse because my app isn't fast enough. So I put Sentry in, I get all of the information about what's going right and what's going wrong, and then I can go in and I can fix the issues right away. So if you have an app that's running slow, you have an app that's having errors, you have an app that you're just getting started with, go check it out, sentry.io slash four, that's F-O-R slash JavaScript, and use the code JSJABBER for three months of their base team plan.
CHARLES MAX_WOOD:: Yeah, let's dive in and talk about this. Now, Dan, you put up this strength and weakness or weakness and strength or something. I'm gonna get confused if I talk too much longer. So why don't you go ahead and explain what we're talking about here with kind of the weak map and new feature that's coming into ECMAScript.
DAN_SHAPPIR: Yeah. So this is actually a part of the series of conversations that we had. We started with the things that JavaScript developers must know. And then we moved on to things that JavaScript developers should know. And I prepared the list of the topics that I wanted to speak about in that context. And when I looked over it, I noticed that some of the topics, if they're taken together, actually can make a topic for a show on on its own. So this is like an episode in that series. And like you said, the subtopic is Strength in Weakness. And it's about weak maps and weak sets and the brand new weak references, which are a new feature of ECMAScript and already available in most JavaScript engines out there. So yeah, that's what I want to talk about today. And like we discussed before, what I actually wanted to start with is to discuss garbage collection, because if you really want to talk about weak references and stuff like that, and understand the motivation for their existence, you kind of need to understand what garbage collection is, what's the motivation for it, how it works. And now we already discussed this in the past, in one of the episodes about the things that JavaScript developers must know, because having some understanding of garbage collection, I think is a requirement for JavaScript developers. But this time, since we're talking about what the things that JavaScript developers should know, I think I can actually go into greater detail, moving beyond what is essential knowledge to what is just, I think useful knowledge. So that's what I would like to begin with, if it's okay with everybody.
CHARLES MAX_WOOD:: Sounds good to me. You know, it's interesting too, because I've worked in languages that don't have garbage collection, where you actually do the reference counting, right? And then you tell it to clear memory. And I like garbage collection.
DAN_SHAPPIR: Yeah, I actually, that's actually where I wanted to start. Because I was using these sorts of languages way before I was using JavaScript. I'm long in the tooth, relatively speaking, I guess. So I actually wanted to start by talking about the heap and to look at it from the perspective of one of the programming languages, which actually gives it kind of like the lowest level of access, which is the C programming language, which I was using long before I was using JavaScript. So in C, so this concept of a heap, a heap is just this, as its name implies, is this just kind of a bag or an area of global memory that you can allocate or request to get memory out of, use it for whatever you want for as long as you want. And then when you don't need it anymore, you deallocate it or free it, basically give it back to the heap so that it can be reused for something else. In C, you actually have two low-level functions to do this sort of thing. You have malloc, which really stands for memory alloc, or memory allocation, where you just give it a number, which is the amount of bytes that you want allocated out of that heap. And what you get back is a reference, or actually in C parlance, you get a pointer, which is kind of similar similar concepts. And then with this reference in hand, you can really use this memory to put whatever you want in it and use it in your application. And you can pass it around. And then, like I said, when you don't need it anymore, then you just free it up. And what's nice about it is that the heap does not enforce any sort of order in terms of allocation and deallocation of memory. So I can allocate, let's say, a memory segment A and then a memory segment B, and I can free them first A and then B or first B and then A, the heap doesn't really care about the order of things. So that provides a lot of flexibility and consequently it's a really, really useful mechanism that's really used all over the place.
CHARLES MAX_WOOD:: Yeah, it's nice because it's explicit, right? So when I'm done with something tell the system I'm done with it and it doesn't hold on to the memory, right? But it makes it really easy to shoot your foot off.
DAN_SHAPPIR: Yeah, exactly. Turns out that there are really three core problems when working with the heap in this way. The problems are memory leaks, are dangling pointers or dangling references. Again, you know, choose whichever term you want to use. And the last one is memory fragmentation. So
CHARLES MAX_WOOD:: I'll tell you, of the three, the dangling pointers is the ones that always got me.
DAN_SHAPPIR: Yeah, those are probably the worst. But, so yeah, so let's start with the easiest one to explain, which is a memory leak. A memory leak simply happens when you allocate some memory from the heap, use it for whatever, and then when you're done with it, you forget to free it or to de-allocate it. And often that's not actually a problem. I mean, computers these days have a lot of memory and you can actually leak let's say a k of memory a second and never feel the difference because your application will likely end before you actually run out of memory. But if you allocate if you leak rather than a k a second, a megabyte a second, then you probably have got a problem. Now you might think, I mean, you know, there's the obvious bug of just forgetting to release the memory of forgetting to call free, but it's not just stupid bugs like that. It can actually be a more difficult problem to, to resolve. For example, let's say I allocate some memory to, to store some stuff and then hand over this memory to separate, uh, subsystems within my application. It then becomes a question of ownership. Which one of these two subsystems actually owns that memory and owns it in the context of being responsible to release it or free it when it's no longer needed? If both of them assume that the other one is actually the owner, then neither will free the memory and then you've got the memory leak. And that's all too easy to do or something that can easily happen when you've got a complex system and you're moving memory around between subsystems within the application.
AJ_O’NEAL: So far we're talking about memory management very generically, like the way that it would happen in another language like C. But in JavaScript memory management, you could still get memory leaks. But I don't think that we're talking about the types of things that are relevant to JavaScript right now. And so I want to see if I can pull us towards how does this apply to JavaScript?
CHARLES MAX_WOOD:: Well, so just to back up for a second, because, you know, Dan's explaining memory leak, stumbling pointers and memory fragmentation. And these problems can occur in JavaScript as well. The difference is, is that the mechanisms by which it happened aren't as explicit. Right. So the dangling pointers is where you free up memory before you're done referencing it. Right. And so that
DAN_SHAPPIR: Yeah exactly. So. So before we get to JavaScript, let's just finish these three problems and then we'll see which ones of them actually happen with JavaScript and which do not. So the second one, so the thing on,
CHARLES MAX_WOOD:: so back on memory leaks for just one second, the other thing that I've seen happen in C is that sometimes you wind up allocating more memory than you need on a regular basis on long lived objects or things there. And so that can also happen that way where you're just taking up more memory than you actually need instead of forgetting to free it up, right? You just don't get around to it because you need something in there and you've grabbed more than you actually need. And so you take up more memory than you have.
DAN_SHAPPIR: Exactly. Now this sort of thing to an extent does not happen in more modern languages where instead of allocating bytes, you actually ask for objects of a certain type and the system does the computation of how much memory you need for you. But you could still, for example, ask for an array that might be too big relative to what you might actually need. So this sort of thing can happen in other cases as well. So moving on to the second problem is that the dangling pointers or dangling references, you actually explained it quite nicely, is exactly that problem of, again, let's say I'm handing over memory to two subsystems. And this time, instead of neither assuming ownership, both of them assume that they have ownership. And consequently, when one of them thinks that it's done with the memory, just frees it, returns it back to the heap, while the other subsystem still is using that reference and assumes that the memory is going to still be there. Now, if you're lucky, this will cause a crash. If you're trying to access memory that, yeah, that you're trying to access memory that doesn't belong to our application anymore and you get something like an exception or segmentation fault or whatever, and the program crashes and you start to debug it and you find the problem. If you're unlucky, then what might happen, for example, is that this same memory might get allocated for some other use. And then you've got the same memory being used by two different subsystems in the same application for storing and doing completely different things. One subsystem might think that this memory is being used to store an object of type A, whereas another subsystem might think that it's being used to store an object of type B, and then they step on each other's feet. When this sort of thing happens, it's one of the worst kinds of bugs to try to debug in language like JavaScript, this doesn't happen. Now, the third type of a problem that you can get with a heap is memory fragmentation. Let's say that we have a really small heap. Let's say it's only, I don't know, 300 kilobytes. And I allocate three segments of a hundred kilobytes each. And they all three allocations succeed because the heap is big enough. And I've allocated all these three. Now the heap is all used up. Now let's suppose that I release the first segment and I release the third segment but I don't release the second segment. If I ask you how much free memory is now available in the heap, you would tell me that the heap has 200 kilobytes of available space. But if I try to allocate a single contiguous segment of 200 kilobytes, that would fail because I've got that still that segment of 100 kilobytes stuck there in the middle and it hasn't been released. So I can create this sort of fragmentation. Now obviously in real life heaps are generally much bigger so fragmentation problems often may not be an issue but if a program is running for long enough and allocating and releasing you know doing a lot of memory manipulations like that you can actually run into situations where the heap seems to be free enough, but when you try to allocate a big enough buffer for something, it'll just fail. And usually when allocation failed, then the whole application fails. Usually, just crash because there's literally almost nothing you can do at that point. So those were the big three problems that we had with heap and memory management, languages like C. But not only. A lot of languages from those days had these sorts of problems. Now there were various types of solutions proposed to address these sort of problems. You know, languages like Rust formalizes the concept of ownership and gets rid of some of these problems this way. But then a lot of programming languages these days, like you mentioned, have this concept of garbage collection, which tries to fix these three problems. So let's get to garbage collection. Now you know, we have garbage collection as part of JavaScript, but it wasn't invented for JavaScript. Java, which kind of influenced, let's call it the creation of JavaScript, had garbage collection. The.NET languages have garbage collection. Python, a lot of languages have garbage collection these days.
CHARLES MAX_WOOD:: Ruby does.
DAN_SHAPPIR: Ruby does. I think the first language to actually have some sort of garbage collection was actually Lisp, as far as I recall. I'd have to check that.
CHARLES MAX_WOOD:: One interesting point on this is that iOS in Objective-C initially had reference counting, which was their way of cleaning things up, right? So when the reference went to zero, it would clean it up, right? So when you were using it, you would increment the reference. And then when you were done with the object, you would decrement the reference, right? I'm not going to touch it again. And so then it could get it essentially called the malloc when you declared it and incremented the reference count. And then when you were done, you would decrement it, but it wasn't proper garbage collection. So there are kind of these in-between things that you run into as well, where they have a different mechanism for this. And eventually I, Objective-C got automatic reference counting. And when they put that in, it was kind of a stand-in for garbage collection, but it wasn't proper garbage collection. So there are languages that do this in different ways.
DAN_SHAPPIR: The problem with the, just to briefly touch on it, the problem with reference counting is that if you've got circular references, you're stuck. So let's say I have a data structure like a linked list where I have a reference to the first item in the list and that reference is the second and the third and so forth. But let's say the last item actually has a link that goes back to the first item. Those data structures can be useful in various algorithms. And when that happens, the reference count will never go down to zero unless you explicitly like go in and cut the link.
CHARLES MAX_WOOD:: Break the link.
DAN_SHAPPIR: Yeah, exactly. So even though it's semi-automatic, it's not wholly automatic when you're using reference counting. So JavaScript garbage collection actually uses a mechanism called mark and sweep. So what is that? When you allocate memory in JavaScript for an object and in JavaScript almost anything that you do allocates memory. If you do new function, obviously that creates an object off of the heap. That's fairly explicit. But even if your function just returns, let's say an object literal, that also gets allocated off of the heap. Like JavaScript is really memory intensive. It uses the heap a lot all of the time. And what the JavaScript mechanism does, but you know, JavaScript, there is no free, you don't explicitly release the memory. When you don't need some memory anymore, you just let it go and assume that somebody will clean up after you and that someone is or something actually is that garbage collector. What happens is that every once in a while, when let's say the system is starting to run low on memory or something like that, kind of a service will automatically start up as part of the JavaScript engine that's running inside your browser or inside Node. And then what it will do, it will actually try to identify portions of heap memory that are no longer in use. And the way that it does that is that it starts with all the variables that are currently active. Let's say they're in the current scope and all the other scopes that are still active due to being part of active closures. Also from stuff on the global object, for example. So all the things that you can directly access from currently running code. And then it looks at all the objects that they reference and it marks all of these objects as being in use. So this is why this algorithm is called Mark and Sweep. And then from these objects, it looks to see if they reference additional objects. And if it finds more objects, it marks those as well. So it's kind of going, you know, through this sort of a tree or a graph, marking things as it finds them. And if there is a particular iteration, where it only finds things that it's already marked, means that it's already visited, then it knows it's done anything that can be reached has been reached, anything that has not been reached cannot be reached. I hope that's a clear explanation, you know, a lot of hand waving. And when it finishes that process, it knows that all of those things that have not been marked can be released back to the heap to be reused. So, and here's the interesting thing. The things that are marked that are still in use, not only does it keep them, but it also compacts them. That means it copies things over so that they are now contiguous in memory. And this prevents that problem of memory fragmentation that I described before. So dangling pointers cannot happen because if something is still referencing some memory, that algorithm that I just described will mark it as being as used and won't release it. Likewise, memory fragmentation won't happen because, as I said, the garbage collector actually compacts the memory that is still in use and adjusts all your variables to point at the correct location. And you might say that memory leaks are also less likely to happen because, you know, any memory that's no longer in use will be cleaned up and reused. So, you know, theoretically, we fixed all three problems and life is good.
CHARLES MAX_WOOD:: Theoretically. Yeah, I think AJ was kind of alluding to this, right? Because you can get JavaScript programs that bloat in memory, right? And appear to have a memory leak. And usually what that is, as you pointed out, Dan, is when it does the marking, it goes through and you have a closure that just never gets let go, right or some other thing that references these memory locations. And so those things will never get cleaned up even though they're really not being used. And so that's, if you're looking at something that appears as a memory leak in your JavaScript program, it's probably something like that.
AJ_O’NEAL: I would think the most common is when you have an array or an object that you keep on adding to, but you never remove from, at least for me, that's been my most common mistake.
CHARLES MAX_WOOD:: I could see that, but usually there's a reason for it, right? There's a reason why you're operating that way. Well, if you forgot, then it sounds like the memory leak is in your head then.
AJ_O’NEAL: Well, yeah, yeah, yeah. But you might have something where you need to store some state in memory. Say for example, there's a multi-part process. You know, if you're doing this best practices style, that kind of stuff would end up in a database, but there are times when you just want something to be able to be referenced in memory for, for quick usage, and then you, you add to it. And then you forget when you're done with it to get, get it removed. And this could happen in something like a, a chat application where you have people connecting, disconnecting, and you want to keep some history again. Like you should be putting this stuff in a database so it shouldn't be happening. But that's that's where it's most common for me. I don't know if I've come across the situation where a closure is keeping something and not being collected. I know that used to be a problem back in the olden days, but I thought that they'd found better ways of doing the mark and sweep so that basically an unfinished promise chains and that sort of thing just get sweeped out.
DAN_SHAPPIR: Well, in the real old days, the browsers literally had bugs where even in situations where the garbage collector should know better and be able to pick up the garbage, it sometimes didn't. This in particular had to do with the fact that browsers actually kind of have two garbage collectors built in, one for the DOM stuff and another for the JavaScript stuff. This is again an example of where it seems like the DOM is like totally integrated with JavaScript because you can access DOM objects as if they're JavaScript objects, but in reality, it's like this separate entity and they kind of cohabitate under the same roof. And this can cause all sorts of problems. And these sorts of leaks were one of one example of that. But even today with these bugs fixed, you can still run into problems like that. For example, let's say I put an event handler on some DOM object. And within some in the, and that event handler is a function and it has a closure and that closure holds onto stuff. So as long as that DOM element is still there and that event handler is still there, everything in that closure, at least the things that I've used in the past, won't get cleaned up because still being effectively referenced.
CHARLES MAX_WOOD:: Right. Even whether or not you need it.
DAN_SHAPPIR: Exactly. Now the last time that we spoke about it in, in, in the context of that conversation about the things that jobs, the developers should know, you AJ said that one way to kind of fix this is to explicitly assign a null to variables. And now I actually checked on it and it turns out that assigning null does not actually force a cleanup. So just because you assign null it disconnects that variable from that object, but that object will still hang around in memory until the garbage collector kicks in whenever it does kick in and actually clean it up. But it is an effective way of first of all indicating very explicitly in your code that something is no longer needed and it's also a good safeguard against, you know, if the closure accidentally hangs on longer than you intended, at least that memory that was referenced from it can be cleaned up because you're no longer referencing it.
AJ_O’NEAL: I imagine that different garbage collectors, different garbage collector implementations probably work differently. What I was referencing is I had experienced a case where while I was debugging the application, if I set the item to null and the only reference left was what was being printed by console.log, the reference being printed by console.log would disappear immediately. So that was the situation that made me aware of that. And that was specifically, it was in Chrome and I don't know if Chrome still operates that way, but that was something that did happen. And go, which Google also does, when something is inside of a function, if you don't return it out of the function, even if you create an object, it'll typically get garbage collected at the exit of the function. I would imagine that JavaScript would work that way in some scenarios too, but I don't know.
DAN_SHAPPIR: Well, the interesting thing is that the garbage collector is actually not a part of the ECMAScript language specification.
CHARLE: Right, I was gonna ask.
DAN_SHAPPIR: You could actually, yeah, you could actually implement a spec-compliant version of JavaScript and not have any garbage collector at all, you know, just let the memory sit there. And if your application doesn't run for very long and you have enough memory to begin with, nobody might even notice that there's a problem. Obviously, that's not a realistic solution in most, you know, real-world cases, but would still be spec-compliant. In fact, and we will see that when we talk about the various types of weak references, they intentionally created the specification in such a way as to put as few constraints as possible on the behavior of the garbage collectors because they're not really part of the specification. In the case of Chrome or V8, which is the Google's JavaScript engine, which is built two types of sweeps. I won't go into too many details about this. I will actually, as part of the show note, post a link to a YouTube video by one of the people working on V8, Peter Marshall, who actually discusses this in greater detail. It's a really good talk. I recommend it to anybody who's kind of interested in this stuff. But it turns out that V8, actually the garbage collector actually has two types of sweeps. It has a really fast and more common type of sweep that it does in a higher frequency, which doesn't collect all of the memory, just collects some of the memory, but really runs very quickly, a few milliseconds. And then every once in a while, it actually triggers a longer sweep operation, which really cleans up the entire memory but that can take a long, significantly larger amount of time. And that actually points to one of the bigger problems with garbage collectors, which is the fact that it used, especially it used to be this way. It's, it's a lot better these days in modern JavaScript engines. But the problem was that when a job, a garbage collector would kick in, the, the application would effectively freeze while the garbage collector was doing its job. Now this could be catastrophic if, for example, you're using JavaScript to program, let's say, the code for the space shuttle re-entrancy or maybe to control a nuclear reactor or something. And just when you have to do something, the garbage collector kicks in and you're stuck and can't react to anything. But even in more common JavaScript scenarios, let's say you implemented a game, it could be really annoying if the game suddenly freezes or the animation starts to stutter because garbage collection kicks in every once in a while and kind of freezes the system.
CHARLES MAX_WOOD:: If you're playing a massively multiplayer game and timing matters, right? So you've freezed long enough for somebody to steal your stuff or take you out or whatever.
DAN_SHAPPIR: Exactly. And that was one of the big complaints against garbage collected languages. So they were avoided in contexts where real time computation was a requirement. It's interesting to see again, I like to say that we're really lucky with JavaScript because we have the best engineers from the biggest companies in the software companies in the world competing on who can create the best engine out there. And the result is that JavaScript is just an amazing, you know, has amazing implementations and it's the same for garbage collection. For example, in V8, they found that they could move a lot of the garbage collection off of the main thread. So they could leverage the fact that the hardware today is multi-core and do a lot of the garbage collection in parallel and significantly reduce the amount of that the main thread was actually stuck or suspended. Like I said, for the short and frequent garbage collection in V8, it can take as little as five milliseconds or something like that to clear up most of the memory that it needs. So it's really, really efficient.
CHARLES MAX_WOOD:: So just to clarify here, it sounds like what you're saying is that the trade-off between garbage collection and sort of the explicit malloc free approach is that the one is a little harder to keep tabs on or keep track of especially under certain circumstances. But the trade off is, is that if you have a garbage collector, it's part of the program that actually has to run. And so it'll actually take up compute cycles, figuring out what to clean out.
DAN_SHAPPIR: Exactly. And usually you have effectively no control over it. Other than trying to reduce the amount of memory that you allocate. Obviously the less memory churn that you cause, the fewer times the garbage collector would need to kick in. But with JavaScript actually, given the way the JavaScript behaves, you're going to do a lot of memory allocation almost no matter what you do. And so garbage collection can really be avoided. And there are intentionally no controls in the JavaScript language to either prevent garbage collection or to force garbage collection. So you're totally at the mercy of the system of, you know, the engine deciding what it needs to do it.
CHARLES MAX_WOOD:: Yeah. I've seen systems where you can explicitly kick off a garbage collection run. I don't know that that's necessarily entirely helpful. I mean, if you know that you've got memory overload, then I guess it makes sense. Or if you have a process, where you know you're going to wind up orphaning a bunch of stuff that the garbage collector could go find to get rid of, then you could do it. But typically, even if they have them in there, I think Ruby has one and they kind of give you, they tell you, you can run this, but you probably shouldn't unless you know you need it.
DAN_SHAPPIR: Yeah, sometimes like they say, if you know that you're going to know to be busy for a while, then you can force a garbage collector run so that the next time that you are busy, you start from a cleaner slate. But in most cases, it's just not worth it. And anyway, you might think that you're not busy. Let's say you're creating a web server and you might think that you're not busy. And then you kick it, the garbage collector off. And just as you do, a new connection request comes in. So it's in any event in JavaScript, they intentionally withheld control over the garbage collector from your JavaScript code. That's just the way it is. So that kind of lays the groundwork for the second part of this conversation in which I wanted to talk about these various types of weak references. And the one that I wanted to start with is the one that's been around the longest and that's a weak map. Just to indicate how long it's been around, IE 11 supports it. IE 11 has built-in support for weak map. So you don't need Babel or anything like that. In fact, you actually Babel won't do you any good because as we will see, these are weak reference types of things that you have are not things that you can actually polyfill. If you have them, then great, you can use them. But if the environment that you're using does not have them, then you cannot simulate them. And we will see why in a minute.
CHARLES MAX_WOOD:: Real quick on this, so I'm wondering then, because you're mentioning Babel, the other one that comes to mind is like TypeScript or maybe Dart, right? Do they, when they compile the JavaScript, do they take advantage of these structures then in the JavaScript that they generate?
DAN_SHAPPIR: To be honest, I don't know, but I don't see any reason why not, given that it's just supported everywhere. But at the end of the day, you just can use it explicitly. I mean, TypeScript is just JavaScript with types, kind of. Well, kind of, yeah. Anyway, so what is, to understand what is a weak map, let's start first with a map. Again, this is something that we actually spoke about in the things that the JavaScript developer must know, I think. A map is in Java. So it's funny in JavaScript, every object is effectively a dictionary, which maps keys, which are either strings or symbols now. And let's not go that down that rabbit hole again. Several times already. And it maps that to effectively anything you want. So the property name is the key and the property value is the value that you're that the dictionaries is, is referencing
STEVE_EDWARDS: and Dan, quick question. Two questions. So what's the similarity of this dictionary that you're talking about versus say a Python dictionary, which is their default method for storing data. Are you familiar with that at all?
DAN_SHAPPIR: Yeah, it's funny. A few months ago, I was helping my son with his CS 101 course in the university. So I kind of knew Python beforehand to an extent, but now I really had to learn it because his course was using Python and I wanted to be able to help him. Anyway, the answer is that JavaScript objects really behave to a great extent like Python dictionaries. They also do some fancy stuff behind the scenes to be really efficient when they're used as objects rather than as dictionaries. But at the end of the day, you could just use them like a dictionary. But it turns out that the fact that the key can only be really a string is a limitation sometimes. And sometimes you want to be able to use something else as a key. In particular, you want to use some other object or an object reference as a key. And I'll give an example. Let's say I have a system where I have objects that represent users. So for every user, I have their, I don't know, let's say their name and their age and their gender and whatever other information I want to keep about my users in the system. And let's say that I wanted to, and I decide to extend the system and also add information about a phone that any user might have. Let's say the phone number, but also the type of phone, whether it's an iPhone or an Android device, whether it's what's bought by the company or belongs to the employee, whatever, additional information. But the problem is that I don't want to modify the original implementation of the user objects. Maybe I'm using some sort of a library that I got somewhere. Let's say it's either not my code or a code that I don't want to modify. Maybe it's code that's being used in other places that don't actually need this phone information. So I don't want to modify the original object. What I need to then be able to do is to map users, user objects onto phone objects. Now, if I'm lucky, then maybe every user has some sort of a unique identifier. And I could use, and that identifier can be converted to a string and a unique string, and then I can use that key and just use a regular old JavaScript object as the dictionary of phones to map from users to the phone, but maybe users don't have this sort of an ID. So what do I do then? Well, one option, because given that it's JavaScript, I could just add, put stuff directly on the user object, even though I don't own it, I can add fields to whatever I want, I could add an ID field, or I can literally put the phone information directly on the user object. But that's probably a bad idea because I'm modifying an object that I don't really own, that never ends well tomorrow they add some conflicting field or whatever and everything will break down and it will be really difficult to debug and fix. So I've created a dependency that should not exist. So I really want to keep the phone information distinct and separate. And let's say again, I don't have a unique idea that I can use well with a map object that was introduced in JavaScript. I can actually use the user object itself or actually the reference to that user object as a key in the map. So I can put in a map a key that is the user object and the value which is the phone object and then if I come back later with that same user object I will get back the same phone object that I want.
When I went freelance I was still only a few years into my development career. My first contract was paid 60 bucks an due to feedback from my friends, I raised it to $120 an hour on the next contract. And due to the podcast I was involved in and the screencasts I had made in the past, I started getting calls from people I'd never even heard of who wanted me to do development work for them because I had done that kind of work or talked about or demonstrated that kind of work in the videos and podcasts that I was making. Within a year, I was able to more than double my freelancing rates and I had more work than I could handle. If you're thinking about freelancing or have a profitable but not busy or fulfilling freelance practice, let me show you how to do it in my DevHeroes Accelerator. DevHeroes aren't just people who devs admire, they're also people who deliver for clients who know, like, and trust them. Let me help you double your income and fill your slowdowns. You can learn more at devheroesaccelerator.com.
STEVE_EDWARDS: And in fact, MDN, according to MDN, key type can be any value, including functions, objects, or any primitive.
DAN_SHAPPIR: Yeah, they support primitives and they support objects. And in JavaScript, everything is either a primitive or an object. So there you go.
STEVE_EDWARDS: That just seems odd. I'm just trying to imagine the use case where you would want to use a function as a key.
DAN_SHAPPIR: Well, again, a function in JavaScript is just an object. So it's not that it supports functions intentionally because cool, let's support functions as keys. It supports functions because, you know, they support objects and functions are objects.
AJ_O’NEAL: So there, there is a very clearly identifiable case. If you are doing event handlers and you want to know what handlers of function has been assigned to, then you would want to look it up by function. And the way to do this previously was that you would create an array of all of your functions and then you would loop through that array to find the function that was the value that matched. So that's the use case for functions.
DAN_SHAPPIR: Yeah, that's that's a good one. Thanks. You're absolutely correct. And that's by the way, how you can simulate or or emulate the existing map type object when when you don't have it in your system. You basically create two arrays an area of keys in an area of values and you search through the key, you find the index of the key and then you have the value in the other array at the matching index. Problem with that, of course, is that you have to potentially scan the entire array every time you perform a lookup, which is inefficient, but it still works. So you can simulate this data structure if you don't have it at the performance cost. But then they took it an interesting step forward with the introduction of a weak map. The idea of a weak map is, let's go back again to that example that I gave about a user being mapped to a phone. And let's say some user left the company, or I don't know, whatever. And I thought about saying died, but that would be morbid. But anyway, we don't need that user object anymore. So we, in the context of the code that manages users, we just let it go. But turns out there's a problem that map that object, the map object that. Maps the, the, all the users to the phones actually has a reference to that user object. So even though your code has let go of the user object, that map is still holding onto it memory. Not only that, it also goes on to that phone object that is mapped to from that user. So that is another memory leak. So you need to, so now you need to kind of modify your code so that when you no longer need a user, you need to go to that map and explicitly remove that user from the map in order to, to, to avoid a memory leak. And that's kind of not the way that garbage collection was supposed to work. You're not supposed to be doing these sort of explicit manual release or free type operations of removing references to objects just in order to have them get cleaned up. And weak map solves this by having what is known as a weak reference as the key. A weak reference means that it's simultaneously has this reference to that key object, but it doesn't prevent garbage collection of that key object. So if only the map still references, only the weak map still references that object as a key, that object will get garbage collected. That's the idea of a weak reference. A weak reference does not prevent garbage collection. I hope that this explanation is clear. And the complementary thing to that is that if that key is indeed garbage collected, the WeakMap is smart enough to say, hey, this key no longer exists, I can also release the value so that can get garbage collected as well. So even though the value is a strong reference, or a regular reference actually, because the key is gone, the map will let it go, and it can be cleaned up as well. So going back to our example, that map that maps users to phones, I would use a weak map. And then if I just let go of that user, then the phone, the user will indeed get, the user object will indeed get garbage collected. And so will the phone object. Now, this is something that you cannot simulate if you don't have this data structure or this capability built into the JavaScript engine itself.
CHARLES MAX_WOOD:: Right. That makes sense. Because essentially what you're saying is, is that, yeah, if I clean up the user, I don't want to have to go explicitly clean up the phone number, the address, the company, whatever, right? Uh, and vice versa, right? If you clean up the company, you don't want to have to go through and explicitly remove references to the, the people and the, you know, what other, what, what, whatever other assets there are that belong to that, that object or entity. Because we have garbage collection, so it may as well be smart enough to know that, yeah, that reference is no longer valid and it's okay that it's no longer valid. And then when the company gets cleaned up, the user reference to the company gets cleaned up. Is that's essentially what you're talking about here?
DAN_SHAPPIR: Yeah, exactly. I mean, let's say I have multiple such entities in the system, each managed by a different subsystem in the application. I have with that user object, I have a phone object and a map that maps the user to a phone, users to phones. I maybe have another subsystem that deals with their computers that maps the user to their computer. So without this mechanism, I would explicitly need to go to each and every subsystem and tell them, hey, this user is gone. You should clean up all the data that's associated with that user. That's kind of like the inverse of what garbage collection is all about. The system should be able to do this automatically for you. If you don't want that user anymore, you should just, you know, kind of let them go and assume that every subsystem that, that uses that, that kind of, you know, uses that user in some way will do the cleanup appropriately. And that's the strength and beauty of WeakMap.
CHARLES MAX_WOOD:: So what I'm wondering is then is let's say that, yeah, they get this implemented. Was there a measurable difference in the performance of applications after this got put in or do we actually know that?
DAN_SHAPPIR: Well, I don't know. It's kind of difficult to measure these sort of things because you don't know if people are actually using them. I can tell you that we at Wix actually used WIC maps to map sessions in a server to transient data associated with these sessions. So that when the session object was gone, so was all the transient data that was associated with that session object in the various different subsystems. So it turned out to be a really useful data structure for us. And again, you can, you know, it's not a must. You can make do without it, but then you just need to write your code really carefully and go and explicitly, you know, like, go to each and every subsystem within your application, go like knock, knock, please release this user, don't reference them anymore, and release all the data that's associated with them, or in our case, session. It's not as if you can't do without this mechanism, it just can make your life a whole lot easier if it's there, especially when you're creating these sorts of more complicated applications and data structures.
CHARLES MAX_WOOD:: I would imagine also that it makes a bigger difference at scale, right? So, you know, you're running servers upon servers upon servers. And so if you can save yourselves the memory, right. Then it starts to add up.
DAN_SHAPPIR: Exactly. I mean, with most web pages, they are short-lived enough and simple enough that even if you leak a ton of memory, you'll probably not run into any problem because the system will just do the entire cleanup for you once that page is unloaded and replaced with some other page. But if you're writing stuff that's running on a node server and it's supposed to be long-lived, then you can run into all sorts of issues if you're not managing memory in a smart way.
CHARLES MAX_WOOD:: Yep, makes sense to me.
STEVE_EDWARDS: And now the question with all this talk about maps and this is sort of a poll for the listeners is how many people with kids and young children have hear the song from Dora on the map? Dora the Explorer. I know that repeatedly goes through my mind every time we talk about maps. So hit me up on wonder 95 on Twitter if you hear the same thing in your head.
DAN_SHAPPIR: Yeah,
CHARLES MAX_WOOD:: somebody's gonna put up a meme. I'm the weak map. I'm the weak map.
DAN_SHAPPIR: Yeah, exactly. So just to conclude that part, a weak set is just complimentary to that you can think of a set as something that maps a key to a Boolean value. Usually to like, you're either in the set or you're not. So a weak set is kind of like to a set what a weak map is to a map. I don't think it really warrants more explanation than that. Which brings us to a really new feature that was recently introduced. It's actually not even officially part of the ECMAScript standard. It's a stage four proposal which means that it's as official as you can be without being yet in the standard. Literally, it means that the next time that the, uh, the standard document is released, it will be in there. So you can, you can consider it to be effectively part of the language.
CHARLES MAX_WOOD:: And is it, is it in there now, like in some of the engines and some of the browsers and the node?
DAN_SHAPPIR: Well, it's not in IE 11, but, but, uh, actually, so, so a weak ref, is actually in Chrome, it's in Edge, which these days is effectively like Chrome. It's also in Firefox. It's not in Internet Explorer, and unfortunately, it's also not in Safari. So what is a weak ref? A weak ref basically gives you this low-level capability very explicitly. A weak ref is an object you create, and you give it, the constructor, you give it just a reference as a parameter. And it maintains a weak reference to whatever object you gave it in the parameter. So you basically have a strong reference or regular reference to a weak ref object, which is just a thin wrapper around the weak reference to something. Now, if you want to get at that something, well, the weak reference object actually has, you could say a single method which is called deref, that's D-E-R-E-F, and it will either return the object that you're referencing or it will return undefined if that object was garbage collected. So it's kind of an object that has, how would I say, the indeterminate behavior. You can put something in there and then you call deref and you will get back that object and then at a certain point in time with no warning in advance you'll suddenly start getting undefined instead. And it's this fact that it's kind of an undetermined behavior is why they kind of encourage you not to use it. The MDN, which I love, has this to say about weak ref. It has a note. It says, note please see the avoid where possible section below. Correct use of weak ref takes careful thought and it's best avoided if possible. So it's interesting when you add the feature to the language and then tell people, please don't use this feature.
CHARLES MAX_WOOD:: The RB dragons, right?
DAN_SHAPPIR: Exactly. But there's a V8 post where they actually give a nice use case for it. Again, like you said, there'll be dragons, but it's an interesting scenario. Effectively, what they have is, let's say you add an event handler and whenever an event triggers, you get some data and you keep that data in some storage that you reference from a closure that's on the event handler function. Let's say you want to log data or something like that, or you want to keep the data. So as long as that event handler is there, you're accumulating more and more data every time that event handler is triggered. The example that they give is a web socket. And every time data comes to the web socket, they record how much data has arrived. Now, if it's, you know, this web socket is alive for a long time, you know, it could end up you know, the situation where you can you keep a lot of data associated with it. Now, let's say now as long as you're maybe using that data, it's important that it be kept. But if you have no interest in it anymore, then why keep it? So what they did is that in the closure, instead of having a regular reference to that storage, they actually used a weak reference. And they checked whether or not they got back undefined or not. So they said, as long as somebody is interested in it, it'll still be there. And we keep on putting data into it, but if it's undefined, well, it means that nobody is interested in it anymore. And we, we won't put any more data in it because, you know, there's nowhere to put the data. And if you kind of had issues following my, my explanation, because it's, you know, all hand wavy and no pictures and stuff, I will post a link to that blog post and they actually have some nice diagrams that illustrate what I'm trying to explain. So I've never used a Wecraft. I'm totally not sure that I will use a Wecraft, but it's cool that it's there. It's one of those things that maybe library creators or frameworks creators will use to try to optimize their memory usage even more. I mean, if you're implementing something like a React or an Angular or something like that, anything that you can do to make your code more efficient goes a long way. So I guess it's intended for these type of scenarios. And the final thing that goes along with it is this mechanism of wait a minute, let's, the name escapes me for a second. It's called the finalization registry. And that's the last item that I wanted to bring up in today's discussion. And just to really bring it again, this is one of those things that you should not use unless you have, you know, you really know what you're about. The idea there is that you can specify a function to be invoked when a certain object is garbage collected. So it's kind of like getting a callback from the garbage collector. And this is a mechanism that enables you to do potentially some extra cleanup. So let's say you have some sort of an object that holds on to various resources and you want people to call close or dispose or whatever on it when they're done with it before they just release it, but you're concerned that maybe they'll forget to do it. You can use this finalization registry as like saying if they forgot to do it, then at least I'll try to do it for them. And the reason that I'm saying try is because there is no guarantee that the finalization will actually ever get caught.
STEVE_EDWARDS: Oh, I thought you were going to say there was no try only do.
DAN_SHAPPIR: Yeah, exactly. So that blog post in the V8 blog, which describes the weak ref. Also describes this finalization mechanism. So if anybody is interested like I said, I think it's an excellent broad post and we'll post a link to that in the show notes and that more or less covers this topic of strengths and weakness
CHARLES MAX_WOOD:: Nice dan Will you tell me a story? How did how did you how did you get around to looking at this? I mean it's It's like so far into the weeds that i'm wondering, you know prompted this, you know, maybe you watched the conference talk or was it more just, Hey, I'm always looking at ways of upping the performance on stuff at Wix or somebody came to you and I don't know, I'm just curious, you know what, how did you get to looking into these options?
DAN_SHAPPIR: So with Wic map, we actually had a need. Right. It's interesting. I described it. We were, uh, if people go back along, like, something like a year and a half ago before I was a panelist, you had me as a guest on the show and I was talking about SSR and I was describing how we moved a code that ran in the client where you only have a single session to the server where you can have multiple sessions running at the same time and we used weak map as a mechanism to map the session object into additional data about that session. And I wasn't actually the person who put that in. So I was familiar with WeakMap, but it was interesting and cool to see that other people within their organization actually used it. As to the other stuff, I don't know. It's, I like to learn. JavaScript is my primary tool. This is the thing that I use day in, day out. And I feel that I need to know as much as I possibly can about this tool that I'm using in order to be able to make the best use of it, to understand how it operates so that I'm not surprised by things that it does. All too often, I see people who kind of use the browser platform without fully understanding what's going on. And it can work. But you're always at the risk of something not working according to how you expected it to and then suddenly finding yourself in a situation where you literally don't know what to do. And I really hate to be in these types of situations. And also, I guess I'm kind of a programming nerd.
AJ_O’NEAL: Nerd!
DAN_SHAPPIR: And that's the reason why I, for example, have those JavaScript riddles that I like to post on Twitter every once in a while because, and they often deal with these various kind of weird and whacking features of the JavaScript language, which JavaScript has an abundance of. So, so yeah.
CHARLES MAX_WOOD:: Cool. All right. Well, let's get to some picks.
Hey folks, if you love this podcast and would like to support the show, or if you wish you could listen without the sponsorship messages, then you're in luck. We're setting up new premium podcast feeds where you can get all of the episodes released after Christmas 2020 without the ads. Signing up will help us pay for editing and production, and you can go sign up at devchat.tv slash premium.
CHARLES MAX_WOOD:: Amy, do you want to start us off with pics?
AIMEE_KNIGHT: Oh man, I'm scrambling. Let's see. I've been very quiet today. I'll go with this. I think I saw this on Hacker News last week. It's how to read a book when you have ADHD. One of my favorite tricks is to go to the gym and get on the treadmill because it's really hard for me to sit still. So I thought there's some valuable stuff in here.
DAN_SHAPPIR: And I thought you were going to say that you shred the book and then mix it with water and drink it as a shake.
AIMEE_KNIGHT: Maybe so. I'm trying to think if I have any other good stuff. Hmm. I'm going to go with that for now. It's pretty good.
CHARLES MAX_WOOD:: Awesome. I'm going to check that out. Steve, where are your picks?
STEVE_EDWARDS: Before I get to my pick, I have another similar question. How many people think of V8 juice when you hear talk about Google V8 all the time? I should have had a V8, always runs through my mind.
CHARLES MAX_WOOD:: I'm a car guy, so it goes in a different direction for me.
STEVE_EDWARDS: Oh yeah, that's true, I didn't think about that. Yeah, I certainly didn't hear I should have had a V6 or a straight eight. Anyway, so couple things. One is a website that I found and it was pointed out to me by a friend of mine and it's called doesthedogdie.com. And the tagline is crowdsourced emotional spoilers for movies, TV, books and more. And so the context was a buddy of mine who has a teenage son, his friend of my sons, and they're watching a movie in the sense that, you know, we were talking about Old Dealer and somehow this topic came up. And he said they were watching a movie in the sense of the son says, I don't want to watch this movie if the dog dies because he just, you know, one of his things. And so my friend starts Googling, comes up with his website. And so basically you have this 70 plus categories of different things like people dying or animal abuse or dog fighting or whatever. And so for instance, a dog dies is one of the categories. And so people can list movies and TV shows about, yes, the dog dies here. No, the dog doesn't die or the dog dies, but it's off-screen or that kind of stuff. So it's a somewhat more of a good resource if you don't like that kind of stuff in your movies and then along the dad jokes line. The other day my wife asked me, are our kids spoiled? And I said, no, all kids smell that way. And then Drew. Hello. And then I heard another story about a, this husband and wife, they'd had a kid after about 10 years, and this seems sort of long, but here's how the story goes. She started to think their child didn't look like them, but also she did a DNA test and found out that the kid didn't belong to either of them. And she told her husband what she'd found. And he said, well, you don't remember, do you? When we were leaving the hospital, the baby had pooped. You told me to go back inside and change him before we left. So I went back and got a clean one and left the dirty one there.
DAN_SHAPPIR: Oh man.
STEVE_EDWARDS: Right.
AJ_O’NEAL: It's too cutting edge.
STEVE_EDWARDS: So those are my picks for the day.
CHARLES MAX_WOOD:: Gotcha. All right, AJ, what are your picks?
AJ_O’NEAL: Okay, so on the topic of all of this memory management, whatnot, whatnot, I have to pick the Ars Technica War Story series yet again, and specifically, the story about Elemental War of Magic. So I'm going to have links to both of those in the show notes. But this is one of those just crazy stories where they built the game at just the right wrong time, because there was enough RAM in people's systems for the game to do what they wanted it to do. But we hadn't make the yet made the transition to 64 bit. And so they were having memory fragmentation errors and it totally destroyed the launch of the game. And yeah, so most of the war stories have a happy ending. This one the dog dies. And I'll also pick super guitar bro, super guitar bros, cause I have not made a VGM pick in a long time. So we will pick that. Very simple thing from, I think I meant to mention this last time, but didn't, or if I did, that I'm picking it again. We had talked about the importance of sharing what you know, and that the barrier to what you know can be you know, pretty low, a lot lower than you think. And there was an extremely useful article that I came across that had about three sentences in it. And so I'm just gonna give this as an example of if you can write a blog article this simple, then you have something worth sharing to the world and you absolutely should. And then after that, I just gonna put out another reminder. If you want to ask me personally any questions about JavaScript programming in general, Linux, any of this type of stuff where I have some expertise or maybe even places where I don't have expertise, you can hit me up on Twitter at underscore beyond code. And also I do live streams every day for my beyond code boot camp. Well, the live the live stream is actually separate from the the edited stream. But anyway, I'll give you links to that you can follow on Facebook, YouTube. And I put that out. And that's it for today.
DAN_SHAPPIR: I have to say, I don't actually watch it live. Your hours don't quite match mine. But I have watched some of them after the fact. And I really like them. So kudos for that.
AJ_O’NEAL: Yeah, about a third of them are pretty good. And the other ones you can just skip. So there's no harm in subscribing.
DAN_SHAPPIR: Yeah, that's always true.
CHARLES MAX_WOOD:: Dan, what are your picks?
DAN_SHAPPIR: OK, so it's funny, I actually came in without any pick ideas. And then while you guys were speaking, I actually came up with two nice ones, I think. So the first one is the fact that in Israel, we don't have to wear masks outside anymore. In Israel, wearing masks was actually mandated. You could, you would be fined if you were caught not wearing a mask. Well, now you still need to wear masks indoors. So let's say if you go into a supermarket or a bank or something, but outdoors, you don't need them anymore. And this has to do with the fact that two-thirds of the Israeli population is either fully vaccinated or recovered. So hopefully we are approaching kind of a quote-unquote herd immunity for COVID. It does seem though that we will need to get vaccinated again in about a year, I guess. But for now, things are looking much better. And indeed, the infection rate has gone down dramatically. So that's definitely good news. The other thing that I wanted to pick, you're going to love this, I think. If you've got the latest version of Chrome, Chrome 90, Google have introduced a great feature. If you open some web page and you select some text in that web page, you can then right-click and there's an option called copy link to selected text. And it will create a URL that not only references that page, but will actually scroll to that text within that page and highlight that text. So in the past, you might've been able to copy links to portions inside pages if they had an ID, if you created something using Markdown, for example you could have links in subsections, but if it was just random text within a page, you know, there was no way. Now you can actually send links to people that will get them to that interesting, you know, bit of content that you want to have them look at. I think this is a super useful feature. Hopefully the other browsers will follow suit. Anyway, those are my picks for today.
CHARLES MAX_WOOD:: Awesome. And the infection rates going down here too, but how they enforce the masks and stuff kind of varies from state to state, county to county, et cetera.
STEVE_EDWARDS: Funny enough that the states where the masks are off, the rates are still dropping like a rock, but people don't like to hear that.
CHARLES MAX_WOOD:: Yeah, I think that has more to do with the vaccinations than the masks. But yeah,
STEVE_EDWARDS: there's debate about that. I won't open that can of worms.
CHARLES MAX_WOOD:: Yeah. I'm going to jump in with some picks. The first thing that I'm going to pick. So this weekend I got away with a bunch of friends of mine. We were actually in Nashville. So I was in Amy's neck of the woods and we didn't quite get to meet up because she had something come up at work. But anyway, the first pick I have is just having some terrific people in your life that will actually tell you the good, the bad, the ugly, right? And so I've gotten no end of encouragement from these guys there is the occasional, Hey Chuck, you need to stop doing this. Or, you know, Hey, we're worried about you in this way or things like that. And we just kind of had an intense three days where that kind of relationship was had. And you know, we, we just talked to each other about each other and it was, it was really, really powerful. And so I, if you, if you don't have people like that in your life, you need to find them. And I don't know how to tell you how to find them. This particular group, primarily evangelical Christian, which is actually not a group I fall into because I'm a member of the Church of Jesus Christ of Latter-day Saints or LDS or Mormon or whatever you want to call us. But we fit together real well just because we all have faith in a lot of the same things. And so anyway, at the end of the day, yeah, we just, we really just dug in deep. And one of the things we did was a duct tape session. And what it is, is you basically act like you have duct tape on your mouth so you can't talk back. And then they start out telling you what your strengths are. And then they tell you what your kryptonite is or what your, your biggest weaknesses or flaws are. And then you go into like blind spots, you know, things that you don't necessarily even see about yourself that you should know. And there's nothing like it with people that you know, care deeply about you and will be brutally honest with you. And so anyway, I really, really enjoyed the time. A few things that I have picked up from there. One of them is I've been playing with a tool called Monday.com. It's kind of a task manager system, but it was funny because I was going back and I was looking for a CRM system and it turns out that Monday has a CRM implementation that fits into their system. And so really, really digging that. So that's one thing I'm looking at. And then the other one.
DAN_SHAPPIR: Just a comment, just so you know, Monday is an Israeli company. It's like a sister company to Wix in a sense, because the founders are kind of they came from the same kind of incubator or something and there are sort of this unicorn there They've grown really rapidly over the past few years. I think they're looking at an IPO or something like that Cool point of interest.
CHARLES MAX_WOOD:: I think I knew they were in Israel, but I didn't know that Yeah, they were looking at an IPO or maybe just I've seen them grow a ton A lot of people are using them and really really like them for me It's just kind of the versatility that I can put into one tool and you can automate the crap out of all kinds of stuff. And what you can't automate in Monday, you can connect to Zapier. So anyway, it's super powerful. The other thing that I'm going to shout out about is, um, at this retreat, uh, they gave us two books and one of them I'd already read. And so I'm going to shout out about it. It's the common path to uncommon success by John Lee Dumas. And he talks about sort of his journey. He's, he's well known in the podcasting space, but he's created a bunch of products at this point and grown his business. And he talks through the things that have worked for him. I already talked about Masterminds, but he talked about podcasting. He talked about a bunch of other stuff in there. And it's a really, really, really well done book. And so if you're looking for that way to lift your career into that next level, start your own business, things like that, it just outlines the entire path. And he has an online course that goes with it that you get for free if you bought the book. And anyway, I can't say enough good things about it. It's a terrific book. So I'm going to pick that the common path to uncommon success by John Lee Dumas. All right. Well, it looks like Amy dropped off and we got through our picks. So thank you all for coming. Dan, thanks for sharing with us. And until next time, max out everybody.
STEVE_EDWARDS: Adios.
Bandwidth for this segment is provided by Cashfly, the world's fastest CDN. Deliver your content fast with Cashfly. Visit C A C H E F L Y.com to learn more.