Charles Max_Wood:
Hey, and welcome to another episode of Adventures in Angular this week. I'm your host, Charles Max Wood. You can tell I've got a little bit of a cold. My voice is scratchy. But hey, we're talking about cool stuff, right? I've got a guest here. It is Lucas Pagnini.
Lucas_Paganini:
Paga nini!
Charles Max_Wood:
Do you want to Paganini?
Lucas_Paganini:
Ya!
Charles Max_Wood:
Oh, there is an A in there. Do you want to introduce yourself real quick, and we'll dive in and talk?
Lucas_Paganini:
Sure, sure. Awesome. First, Charles, thanks for the invite. I have to say that this is actually my first podcast, so I'm very excited. And this is a podcast that I had listened to many episodes in the past, so it was a very happy surprise for me to get invited to that. So thank you so much for the invitation. And yeah, so... My name is Lucas Paganini. I have been working with Angular since 2017, so near the release of Angular 4. Some people feel old by realizing that individuals born in the year 2000 are already 22 years old. I feel old by admitting that I've started at Angular 4, and we're already at Angular 14. Currently, I run two projects. So I am a content creator. I have a team, I don't do any of that alone. And with my team, we create in-depth educational content about web development in the form of articles and YouTube videos. Our articles are published in my personal website, lucaspaganini.com, and my YouTube channel is under my name, also Lucas Paganini. Eventually we will create paid content, but currently all our content is 100% free. On YouTube, we have more than, I think we broke, we hit... to 150,000 views last week. And we have videos going from 50, like a 45 minute video as a crash course on TypeScript narrowing to a 10 minute video on how to organize front end projects for scalability. So I run that as a content creator and I am also the CEO of Unvoid. So Unvoid is a remote company that provides software and design services to a small number of clients in the United States. And being a remote company, we could provide our services to companies anywhere in the world, but so far we haven't had clients outside of the US yet. So it's more of a coincidence in the fact that the US generally is able to pay more. And we're basically a software house, right? So it's a similar business to software or design agencies. Clients hire us to design and develop websites and web applications. It's not always a project starting from scratch. Many companies already have a product and this product usually has a great backend when you're talking about tech startups. But most great tech startups, they don't have an excellent frontend. I don't know if you noticed that trend, but there are excellent tech companies that have an awesome backend, but sometimes the frontend experience, the thing that the end user actually is not in the same level off the backend. So this is the issue that we solve. We are very specialized in the front end. So we can do an awesome design, and we have the necessary knowledge in software development to actually execute that design without compromising it. So that's
Charles Max_Wood:
Right.
Lucas_Paganini:
basically what I do. So content creation and this company called Unvoid.
Charles Max_Wood:
Gotcha. Very cool. What are you based out of?
Lucas_Paganini:
I am based in São Paulo, Brazil. Been
Charles Max_Wood:
Oh,
Lucas_Paganini:
here
Charles Max_Wood:
okay.
Lucas_Paganini:
for my whole life.
Charles Max_Wood:
That makes sense. It also makes sense servicing US companies since you're pretty close to the same time zones and stuff. I know
Lucas_Paganini:
Yes.
Charles Max_Wood:
that's been an issue for other places I've worked and stuff, so.
Lucas_Paganini:
Yeah, that's true. That's one of the differentials, right? Because when US companies try to outsource to other countries, they hit this huge problem, which is the time zone. So if you try to outsource to Asia or to Europe, then you have huge gaps in your time zones, and you can't always
Charles Max_Wood:
Yeah.
Lucas_Paganini:
communicate with the client when they need you. So we don't have that problem being in Brazil. and we still have the benefits of a weaker currency, right? So
Charles Max_Wood:
Mm-hmm.
Lucas_Paganini:
U.S. companies can still pay less and get premium
Charles Max_Wood:
Right.
Lucas_Paganini:
quality and don't have issues with the time zone.
Charles Max_Wood:
Yeah, it makes sense. Um, well that that's cool. Man, I'd love to just go into that more with you, but, uh, maybe we'll do that another time we'll dive into the whole, uh, outsourcing across borders or whatever. But, uh, yeah, we brought you on today to talk about one of the articles that you wrote. Um, you said you have a content team, so maybe you had help on this, but it was interesting. It was the, um, automatically unsubscribing observables on destroy. And you know, that got some attention of some folks on my end. So we invited you on to talk a little bit about it. But yeah, I'm not sure where you want to start. So if you want to just kind of, you know, we I think we have more time available to us than this, than would take than it would take to dive into the ins and outs of this particular things so we can expand a little bit. So let's start wherever you want and then we'll kind of go from there.
Lucas_Paganini:
Definitely, I 100% agree with you. If I just, for the listeners that want to check out the original article, there's also a video format and the video is less than two minutes long. So if we wanted to just talk about that, it would be a very short podcast. But I thought about that too and I thought, hey, instead of just giving the audience... my solution to that specific problem, which is automatically unsubscribing to observables when the component is destroyed. Instead of just talking about that, I can talk about how my solution works and also other ways to do the same thing because that way the listeners can understand it further and maybe they can apply it to other scenarios. I know that I have other places where I could use. the same logic that I applied here, so it can be used to solve other issues. So I think that's more valuable to the audience than just talking about that particular thing. And yeah, so let's get into it. Before we start, it's funny that I always post my content first on YouTube in the video format, and then I make an article about it, and I put it in lucasparandini.com and also Medium. And that particular article got a lot of traction on Medium. And with the traction, I got comments from people suggesting other ways of dealing with the same issue. I think that's true for any tech articles, right, Charles? Like, every time you post a solution,
Charles Max_Wood:
Oh yeah.
Lucas_Paganini:
people are going to comment, like, I would do differently. And that's fine.
Charles Max_Wood:
People have opinions on the internet? No.
Lucas_Paganini:
You see, man.
Charles Max_Wood:
I've never experienced that, but you know.
Lucas_Paganini:
That was a surprise to me too. And what happened is, I had many comments saying that we should just use the async pipe on Angular if you want to manage
Charles Max_Wood:
Uh-huh.
Lucas_Paganini:
observables and automatically unsubscribe to them on destroy. And my answer to that is that it's absolutely correct. That is the best way, at least the way that I would most recommend. The problem is we're not always in the template, right? So if you are in the template and you just want to pipe async to handle an observable, that's great. That's the easiest way to do it because it's natively supported by Angular. It has docs. It's the popular solution. You don't have to install or do anything else. It already comes with the framework. So of course, that's the best solution. But there are two scenarios, at least, that I can think of where this would not be such an easy decision. The first
Charles Max_Wood:
Okay.
Lucas_Paganini:
is, well, of course, when you're not in the template, right? So what if you want to automatically unsubscribe on Destroy, but you're just in TypeScript? You're not in the HTML template. That's one situation where you can't use the async pipe. And the other is when you need a middle step to get to the async pipe. Like, sometimes, I would hope that the audience... not get that, but I think that they're gonna understand what I mean. When you're working in a legacy codebase, sometimes you can't just go directly to the solution that you know is the best one. So the code sometimes is so messy that you need a middle step before you get to the final solution. So before you refactor everything to use the async pipe, you also need something to use in the middle. scenario or while you're refactoring everything. And that's where the solution that I propose really shines. So we'll get to my solution in a second. But as promised, I think that we can talk about how I got there. So we would have to talk about the dependency injector now. So basically, the dependency injector as the audience. Chanel is a fundamental concept in the Angular framework. It is responsible for providing dependencies where they are needed. So for example, you wrote a messaging service, and it depends on an email service. So you use the Angular dependency injector to provide the email service inside the messaging service. Nothing here is news. The audience probably already knows all that. But bear with me for one minute, because we will go deeper into the concepts here. There are two roles. in the dependency injection system. We have the dependency provider and the dependency consumer. We can't consume if there's no provider. You can try it out to see what I mean. If you just use the at injectable decorator in a class but don't provide it anywhere, you will get an error when you attempt to inject that class in a consumer. I know this all sounds obvious, but when people start working with Angular, there's this boilerplate when creating a service,
Charles Max_Wood:
right.
Lucas_Paganini:
which is... at injectable provided in root. I'm sure the audience is familiar with that. Maybe some listeners have typed this boilerplate five or even ten times just today. That boilerplate works. It is what you want in 99% of the cases. So it becomes so common that people don't stop to understand what's actually happening under the hood. And that's why I'm taking us back to the concepts. So We have the dependency provider, dependency consumer. For you to consume, you first have to provide it. But how can you provide a dependency? And then, oh, look, that's obvious. You just gave away the answer. You just have to add provided in root. Yeah, that's one way of doing it. It's not the only way. According to the Angular docs, there are three ways of providing a dependency. The first is that the application root level. which is what we do when we use provided in root. But we can also provide something at the ngModule level. And lastly, there's also the directive and component level. And that one, the fact that we can provide something at the component level, this is what allowed me to find a way to automatically unsubscribe to observables when my component is destroyed. without having to write ng-ondestroy and without extending any other classes. And by the way, that list, that tree item list, it is complete and not complete at the same time because we can also provide dependencies in the platform level, which is above the root level. But in a way, both the root and the application levels are simply ng-modules. So... The only thing that makes them special is that they are way up in the injector hierarchy. So
Charles Max_Wood:
Right.
Lucas_Paganini:
at the end, we only have two. Really, we only have two ways, right? We have, we can provide at the engine module level or at the component or directive level. But we can talk about the platform and route levels later, because I think that's a topic in itself, right? I don't want to confuse the audience by getting into that. And... Well, okay, so let's clarify in practical terms what it means to provide a dependency in each of those three levels.
Charles Max_Wood:
Right.
Lucas_Paganini:
If you provide in the root level, that means providing in the app module. The app module, which is the initial module that contains everything. By the way, in earlier versions of Angular, maybe the audience is familiar with that, we didn't have provided in root. What you would have to do is go in the app module and actually add what you wanted to provide in the list of providers of the app module. So that was clearer. It was clearer that... the thing was being provided in the app module. And then we came up with provided in root, but it's functionally the same thing. There is a benefit to using provided in root, which is that Angular can tree shake it. So if you don't use the dependency, Angular removes it from the bundle at the end. So it becomes smaller. But having a service that you are writing provided in root is the same thing. as going in the app module and adding that service to the list of providers of the ngModule decorator. And by doing that, the service, the dependency, becomes available to everything that is inside the app module. But it so happens that your whole application is inside the app module. So this ends up creating a singleton, a single instance of that dependency. available for the whole application. So that's the first level, providing in the root level. Then we can go to the second level, which is when you provide a dependency in the engine module. Everything
Charles Max_Wood:
Mm-hmm.
Lucas_Paganini:
that is inside the module gets this dependency. So let's say that you have an accounts module and you provide a dependency there. Everything that is inside accounts will have that dependency, but everything that is outside will not have it.
Charles Max_Wood:
Right.
Lucas_Paganini:
And the same thing goes for component and directive. Everything that is inside the component or the directive gets this dependency. An important note here to have a clearer understanding of how we can leverage that to create something that will automatically unsubscribe to observables when the component is destroyed, is that... the dependency lives as long as the provider lives. That's
Charles Max_Wood:
Right.
Lucas_Paganini:
the secret. So, if you provide something en route, when the whole application gets destroyed, the dependencies will get destroyed too. If you provide something in an ngModule, like accountsModule, when the accountsModule is destroyed, every dependency provided by the module is also destroyed. And when you provide something in the component level, when the component is about to get destroyed, the providers of that component are also destroyed. So that's the secret. Just
Charles Max_Wood:
Mm-hmm.
Lucas_Paganini:
saying that, I basically spoiled the solution, right?
Charles Max_Wood:
Right.
Lucas_Paganini:
And so what you can do from there is, you can, knowing that, you can create a service that you provide in a component, and
Charles Max_Wood:
Uh
Lucas_Paganini:
then
Charles Max_Wood:
huh.
Lucas_Paganini:
you listen to when the service is destroyed. Because when the component is about to be destroyed, the service gets destroyed first. But it's very close to each other, so it's basically the same thing. the moment in which the service gets destroyed is practically the same as when the component is destroyed. It happens a little bit earlier because the dependencies are destroyed before the component is destroyed, before the provider, but it's basically at the same time. It's just a matter of the order of execution of functions. And knowing that, we can leverage the lifecycle hooks of a service. A component has many lifecycle hooks. We have ngOnInit, ngOnDestroy, afterViewInit. A service doesn't have all that, but the service has one single lifecycle hook. And that's all we need. That's
Charles Max_Wood:
Right. Yep.
Lucas_Paganini:
perfect, which is ngOnDestroy. So we have all the pieces of the puzzle. We have the lifecycle of a service that tells us when the service is about to be destroyed. And we know that. if we provide a service in a component, when the component is about to be destroyed, the service is destroyed. So that was my idea. I created a service called unsubscriber service. This service emits a value when the service is about to be destroyed, when ngOnDestroy is called in the service. And I listen
Charles Max_Wood:
Right.
Lucas_Paganini:
to that in the component, in the component that is providing that. and I can use the take until operator from RxJS
Charles Max_Wood:
Uh-huh.
Lucas_Paganini:
to complete and unsubscribe to my observables when the service emits an event saying that it will be destroyed. That's the secret. And from there, you can create more abstractions. So for example, I created a method in the service that already has the take until operator. So I don't have to import take until from RxJS all the time. I already have a method in the service called take until destroy. So imagine that you have a property that contains a property in your component that contains... a observable. You can, from that property, you can do a dot pipe. You can pipe that observable and you can add unsubscriber service dot taken to destroy. Done. You don't have to write anything else. This observable will automatically complete and unsubscribe when the component is destroyed. To be actual like when the service is destroyed, but the service... is provided by the component. So
Charles Max_Wood:
Uh huh.
Lucas_Paganini:
when the component is destroyed, the service is destroyed too. Basically the same thing. So this is how the magic works.
Charles Max_Wood:
Awesome.
Lucas_Paganini:
Yeah.
Charles Max_Wood:
So
Lucas_Paganini:
Yeah.
Charles Max_Wood:
one thing that I'm not clear about is... And mostly it's just because when I'm writing Angular, I'm not really thinking about it. If I destroy an observable, I just don't do anything. So what actually happens if I destroy it but does it not automatically unsubscribe?
Lucas_Paganini:
What do you mean by destroying an observable?
Charles Max_Wood:
Well, when you were talking about, in fact, I tend not to do that either, right? But the article is about, you know, you unsubscribe observables on destroy. And yeah, I mean, most of the time I just, you know, if, if I remove a component, you know, or hide it or something like that, I just kind of leave everything on. Am
Lucas_Paganini:
Gotcha.
Charles Max_Wood:
I doing it wrong or?
Lucas_Paganini:
Yeah, actually you are
Charles Max_Wood:
I mean, I just leave it, right? I just like, okay, it's, yeah, I don't see it anymore, so I don't think about it, right?
Lucas_Paganini:
Sorry for the bad news, but yeah, the problem is that you can have memory leaks, right?
Charles Max_Wood:
Uh-huh.
Lucas_Paganini:
If your application lives long enough and you have too many observables, they stay there because their subscriptions are still active. So you can do
Charles Max_Wood:
I
Lucas_Paganini:
this
Charles Max_Wood:
gotcha.
Lucas_Paganini:
test, you can create a component and use the timer function from
Charles Max_Wood:
Uh-huh.
Lucas_Paganini:
RxJS to emit a value every second.
Charles Max_Wood:
Right.
Lucas_Paganini:
And then you can... subscribe to it and console log every time that it emits a value. Even
Charles Max_Wood:
Uh
Lucas_Paganini:
when
Charles Max_Wood:
huh.
Lucas_Paganini:
you destroy the component, it's still logging the numbers. So it's still there. If you
Charles Max_Wood:
I
Lucas_Paganini:
do
Charles Max_Wood:
gotcha.
Lucas_Paganini:
a memory profile, you will see that the observable is still there and it's consuming resources.
Charles Max_Wood:
Uh-huh.
Lucas_Paganini:
It's just that most times, most applications don't use observables that much. I know that this is... weird because we're talking about Angular and Angular uses observables for everything, but
Charles Max_Wood:
Yeah.
Lucas_Paganini:
we don't use observables for everything. Like if you
Charles Max_Wood:
Right.
Lucas_Paganini:
were using NGRX
Charles Max_Wood:
Uh-huh.
Lucas_Paganini:
or any other data store management that uses observables, then I think this issue would become more apparent because you would have
Charles Max_Wood:
right.
Lucas_Paganini:
components like listening to all the users in the system, listening to all the assets in the system. from a data store, and the components are destroyed, but the observables are still there, subscribed. So you would notice the application getting slower.
Charles Max_Wood:
Uh-huh.
Lucas_Paganini:
And that would be one of the causes to it. I'm sure there are others too, like just using the automatic change detection from Angular is also a huge performance bottleneck. Using
Charles Max_Wood:
Mm-hmm.
Lucas_Paganini:
on push is also a huge thing that you can do. But those memory leaks, they... also aggregate and they become this monster that eventually the application is so slow. But if you reload, it's all good again. So this is why.
Charles Max_Wood:
Right. Okay.
Lucas_Paganini:
The solutions this far, the solutions already exist. Even if you read the Angular docs, maybe they have updated the docs. But I remember that I was once reading it, and they had examples where they were saving the subscription so that
Charles Max_Wood:
Mm-hmm.
Lucas_Paganini:
on ngOnDestroy, they could call and subscribe.
Charles Max_Wood:
Okay.
Lucas_Paganini:
That's the default approach. Most
Charles Max_Wood:
Right.
Lucas_Paganini:
developers, their components subscriptions array,
Charles Max_Wood:
Mm-hmm.
Lucas_Paganini:
which is
Charles Max_Wood:
Yep.
Lucas_Paganini:
a property with all the subscriptions that they did. And they have an engine on destroy that is basically a for each in that array. And I'm subscribing to all of those subscriptions.
Charles Max_Wood:
Yeah.
Lucas_Paganini:
That used to drive me nuts. I was like, I hate typing that because I was just copying and pasting that everywhere. But the solutions that I could think of... we're all bad. For example,
Charles Max_Wood:
Uh huh.
Lucas_Paganini:
the most obvious solution and it's a shoot in your foot, but it's more like a shotgun in your foot, is creating
Charles Max_Wood:
Right.
Lucas_Paganini:
a base component class and all components extend that class. I've seen that happening many times and it hurts to remember because this becomes such a monster later on. It starts by... Oh, I have this logic here, which is saving
Charles Max_Wood:
Uh huh.
Lucas_Paganini:
the subscriptions and unsubscribing to them on Angular Destroy. I have it on almost all components. So what if I use object-oriented programming to solve this? I can just create a base component class that has this logic.
Charles Max_Wood:
Right.
Lucas_Paganini:
I extend this class everywhere. I'm good. It does work when you implement, which is another huge problem, which is it works so you think it's all good. But... There are many downsides, so some of them are that, well, when you extend a base component class that has ngOnDestroy, if you try to use ngOnDestroy on your component, you overwrite the parent
Charles Max_Wood:
Right.
Lucas_Paganini:
class ngOnDestroy. So if you're overwriting it, you would have to remember... to call the ngOnDestroy on the parent
Charles Max_Wood:
Hahaha
Lucas_Paganini:
class, or you could call super.ngOnDestroy, but you know that people are going to forget that eventually, and then boom, the logic that you had to deal with memory leaks is gone. That's the first thing.
Charles Max_Wood:
Right.
Lucas_Paganini:
It's so easy to accidentally remove logic because you had to overwrite the ngOnDestroy method.
Charles Max_Wood:
Uh-huh.
Lucas_Paganini:
That's the first issue. Another issue... is that sometimes you do have to extend a class from a library. Like there are third-party libraries that you have to extend a class to implement it in your component. I try to avoid those libraries to be honest. I always prefer composition over inheritance. But
Charles Max_Wood:
Right,
Lucas_Paganini:
some
Charles Max_Wood:
I
Lucas_Paganini:
third-party
Charles Max_Wood:
do too.
Lucas_Paganini:
libraries, yeah, yeah. But some third-party libraries don't give you that option. Sometimes you have to extend the class. And then you can't because you're already extending the base component
Charles Max_Wood:
something
Lucas_Paganini:
class, so
Charles Max_Wood:
else,
Lucas_Paganini:
you have
Charles Max_Wood:
yep.
Lucas_Paganini:
to somehow make that class extend the base component class so that you can extend the class that it already became hell. And the third issue is that it never stops at the initial problem that it was intended to solve. As soon as you have the base component class, right now it may only handle unsubscriptions on the destroy,
Charles Max_Wood:
Uh
Lucas_Paganini:
but
Charles Max_Wood:
huh.
Lucas_Paganini:
if you... take a vacation and look at it when you're back, it's gonna have more things because you're basically giving permission to all the developers on your team to say, hey, we have this base component class, so everything
Charles Max_Wood:
Right.
Lucas_Paganini:
that you want to reuse, just throw it up here. And then it, not even joking, it can become a 1,000 or more class, a 1,000 lines of code class.
Charles Max_Wood:
Right.
Lucas_Paganini:
I've seen that happening. I refactored
Charles Max_Wood:
I love
Lucas_Paganini:
that
Charles Max_Wood:
maintaining
Lucas_Paganini:
it was not
Charles Max_Wood:
those.
Lucas_Paganini:
an easy...
Charles Max_Wood:
Those
Lucas_Paganini:
It was
Charles Max_Wood:
are
Lucas_Paganini:
not
Charles Max_Wood:
so
Lucas_Paganini:
easy.
Charles Max_Wood:
fun. What the flip is going on here?
Lucas_Paganini:
That was indeed the feeling. I had a situation where the component would extend a class that was responsible for list components. So imagine that you have
Charles Max_Wood:
Mm-hmm.
Lucas_Paganini:
many page-level components that
Charles Max_Wood:
Right.
Lucas_Paganini:
just show a list of assets. So...
Charles Max_Wood:
Uh huh.
Lucas_Paganini:
they abstracted that into a list component. So all the page level components that had some kind of list of things that they would show, they would extend this list component. And this list component would extend a base component. So it was indeed very hard to refactor that and to justify it, right? Because it takes away time off the business. So the business, the company needs to spend money. to fix those things and sometimes they're like, but it's working, why do you want me to put a developer to rewrite 300 components just so that they don't use inheritance? How can you justify that to the business owners? And it's really hard, right? So you have to lean on future issues like, oh, this is a tech debt. If you keep that, the team, the development team will become slower and slower. and then it will become more expensive to develop.
Charles Max_Wood:
Right.
Lucas_Paganini:
So, but it's so hard to justify
Charles Max_Wood:
That's the definition
Lucas_Paganini:
that.
Charles Max_Wood:
of technical debt, right? That stuff that slows the dev team down. It's funny cause folks are like, I talked to people about this and not, not this particular instance, but yeah, it's, it's a, Hey, it makes it harder to reason about and that's your technical debt. You know, they, they put technical debt as, Hey, we want to upgrade to the newest version of whatever. And it's like, yeah, but that's not affecting your team.
Lucas_Paganini:
I zakli.
Charles Max_Wood:
So yeah,
Lucas_Paganini:
I zakli.
Charles Max_Wood:
yeah. And yeah, that's, that's where the rubber meets the road.
Lucas_Paganini:
It's funny that you said that developers sometimes confuse tech-depth with upgrading to the latest versions of all the dependencies,
Charles Max_Wood:
Yeah.
Lucas_Paganini:
because I think that's a great hook for us to go into a different solution that developers could have for this issue of unsubscribing to observables on Destroy. And this solution was
Charles Max_Wood:
Uh huh.
Lucas_Paganini:
only introduced on Angular 14. So
Charles Max_Wood:
Okay.
Lucas_Paganini:
you have to be on the latest version too. to have that.
Charles Max_Wood:
There we go, let's smash the FOMO button a few more times.
Lucas_Paganini:
Exactly. So if you're not listening to all the episodes of Adventures in Angular as soon as they are released, you're
Charles Max_Wood:
Right.
Lucas_Paganini:
missing out. Wait, I mean, you could have
Charles Max_Wood:
Yep.
Lucas_Paganini:
triple your salary if you knew all the latest tech. So keep up, folks. You have to listen to the episodes as soon as they are released.
Charles Max_Wood:
You said it, so I don't have to put a disclaimer on it. Ha ha.
Lucas_Paganini:
Oh yeah, I'm here to help, man.
Charles Max_Wood:
That's right.
Lucas_Paganini:
So okay, so what happens is Angular 14 introduced a lot of things. I hate the slogan that I'm about to say, but Angular 14 was a game changer. A game changer is such a, yeah, such a sales slogan, but it is because it does have some things that... change the way that you code your Angular application. I also made a video and article about that if anyone wants to see it. Maybe we can put that on the links afterwards. But out of all the things that were released on Angular 14, one thing that people talked about a lot is standalone components.
Charles Max_Wood:
Right.
Lucas_Paganini:
I don't care about that, to be honest.
Charles Max_Wood:
Aww.
Lucas_Paganini:
Yeah, I'm going to play the other side. I'm going to say that the most interesting thing on Angular 14 was not standalone components. To me, I think it was the inject function.
Charles Max_Wood:
Uh-huh.
Lucas_Paganini:
The inject function to me is much more relevant because standalone components, they are not allowing you really to do anything that you couldn't do before. they're just allowing you to have less boilerplate.
Charles Max_Wood:
Right.
Lucas_Paganini:
Well, kind of. You're just throwing everything that you would put in the module, you're putting in the component. So it's still there. But you type less. There's one less file. You don't have to have a module. But you could already do everything that you did before, you could still do it. Now the inject function. That's interesting because it allows you to do things that you couldn't do before. it allows you to use functional programming more. And I am a huge fan of functional programming. I've been actually writing a book about that for three years. It's a start and stop, start and stop. Eventually it will come out. But the inject function is kind of like React Hooks. Well, not kind of like, it is React Hooks for Angular. React Hooks was a big... shift for React developers because it allowed them to have functional components that also used the state.
Charles Max_Wood:
Mm-hmm.
Lucas_Paganini:
It has a bunch of caveats. For example, they have to be executed in order, so if you have if conditions, sometimes you have big issues because internally the magic that React uses for hooks relies on them being executed in the same order, but they work. They work. Some people could say that you're cheating because you're using a function
Charles Max_Wood:
Ha ha ha
Lucas_Paganini:
that is not really pure, it changes a bit, but it works.
Charles Max_Wood:
Eh, whatever.
Lucas_Paganini:
Angular did the same thing with the inject function. So, for those that are not familiar with that already, Angular introduced a function that allows you to do injection, but you don't need a constructor. Because thus far, if you wanted to inject something in a class, you needed to... do it in the constructor. Now, you don't. Now you can have a function that inside this function, it calls an injected dependency.
Charles Max_Wood:
Uh huh.
Lucas_Paganini:
So let's say that you have a function that wants to get a route parameter. Like the route parameter is the ID. And you want to create a function that you call this function, and it gives you back an observable of the route parameter ID. You would need. to give this function the active route, the active route, so that it can listen to the parameters and give you the observable of the parameter that you want. You don't need it anymore. You can create the same function and not take any arguments. It can be a function that doesn't take any arguments, and somehow, magically, it gives you an observable of the ID route parameter. How can this be done? Internally, this function can call the inject function. and inject the activated route internally.
Charles Max_Wood:
Hmm
Lucas_Paganini:
So that is something that we couldn't do before, and that allows us to create more reusable functions.
Charles Max_Wood:
Right.
Lucas_Paganini:
You can create... I have myself created a function that takes the ID of the route parameter, and it gives you back an observable of the route parameter.
Charles Max_Wood:
Mm-hmm.
Lucas_Paganini:
And that way, you can reuse that in all the components that want to listen to the route parameter. The... Caveat here is that same as React, there are very specific conditions that have to be met for it to work properly. In React,
Charles Max_Wood:
Right.
Lucas_Paganini:
the hooks need to be executed in order. In Angular, they don't have to be in order. You can inject whatever you want in any order that you want. I'm not going to say that this means that Angular is better than React. I'll leave the audience to... reach that conclusion themselves. But the caveat here is that you can only use the inject function in the constructor. And
Charles Max_Wood:
Ah, okay.
Lucas_Paganini:
yeah, because the issue that we had before, which is you needed to be in the constructor to inject something, still exists.
Charles Max_Wood:
Uh huh.
Lucas_Paganini:
You can
Charles Max_Wood:
Right.
Lucas_Paganini:
still only inject something in the constructor, because that's the moment in which Angular, the dependency injector, instantiates the dependencies and injects them. doing the constructor.
Charles Max_Wood:
Uh huh.
Lucas_Paganini:
But I was just saying that we can now do things, do functions that are not in the class. So why am I again talking about the constructor? How can we run a function in the constructor if it's just an isolated function? It's not even a class.
Charles Max_Wood:
Right.
Lucas_Paganini:
So the thing is, you can write those functions, but when you use them in your component, you have to use them in the constructor. And one way of using that in the constructor is by... instantiating immediately. So when you have, for example, public, userId equals to, and then you call the function that gives you the observable of the userId route parameter. That is just synthetic sugar from TypeScript. At the end, when you instantiate properties in your component directly, what's happening under the hood is that this is being done in the constructor. So if you transpile...
Charles Max_Wood:
Uh huh.
Lucas_Paganini:
TypeScript to JavaScript, those properties that you're instantiating as soon as you define the property, they're just being instantiated into the constructor. So you can call those functions when you instantiate your properties, or even to be more explicit, you can actually in the component constructor call those functions. You should try to call them at any other point. It's going to fail. The function is not going to be able to inject the dependencies internally. So... There are some situations where it can be a problem. And another huge problem is that if you don't have a consistent way of knowing which functions use the inject function internally, you can call a function outside the constructor because you didn't knew that it was
Charles Max_Wood:
Uh-huh.
Lucas_Paganini:
using inject internally. So I even use a convention with my team, which is we always prefix... the functions with the word use, just like React. When you're creating a React hook, you prefix it with use. So use,
Charles Max_Wood:
Mm-hmm.
Lucas_Paganini:
state, use,
Charles Max_Wood:
Right.
Lucas_Paganini:
user ID, whatever. So we prefix all the functions that use the inject function internally, we prefix them with the word use. So that way we know that we can only use that function in the component constructor.
Charles Max_Wood:
Okay.
Lucas_Paganini:
So that was a long road, but that's all to say that... With this function, we have a different way, a different alternative to solving the issue that I proposed. So the issue, just to recap to everybody, is we want to automatically unsubscribe to an observable when our component is destroyed to avoid
Charles Max_Wood:
Right.
Lucas_Paganini:
memory leaks and other performance issues. But we don't want to copy and paste an ng on destroy everywhere. We don't want to extend another class. So... The inject function allows us to do that in a different way. And I can't take the credits for that. The other solution that I'm about to talk about here, I'm about to talk about, this other solution was proposed by Nathaniel Bazal. I don't know if I'm pronouncing
Charles Max_Wood:
Uh huh.
Lucas_Paganini:
his name correctly,
Charles Max_Wood:
Right.
Lucas_Paganini:
but he has awesome articles about Angular. And what he made an article talking about the inject function. And in this article, he was showcasing examples of what you can do with this function. And one of the examples that he used is creating an until destroyed observable. So you can, I'll link his article too, but basically you can create a function called until destroyed. I would call it useUntilDestroyed, just so that we
Charles Max_Wood:
Right.
Lucas_Paganini:
know exactly that it's using the inject function internally. So imagine that you're creating a function called useUntilDestroyed. This function takes no arguments,
Charles Max_Wood:
Uh huh.
Lucas_Paganini:
and internally, this function injects the change detector ref. And when you're in a component, the change detector ref is a view ref. but you can't inject the VIEWREF. So the VIEWREF uses the ChangeDetectorRef token to be injected. So if you want to get the VIEWREF, you need to inject the ChangeDetectorRef. But anyways, you inject the ChangeDetectorRef, you type it as VIEWREF, you can even have TypeGuard if you want to make sure that
Charles Max_Wood:
Uh-huh.
Lucas_Paganini:
it is a VIEWREF. And if you have the VIEWREF, it has a method called OnDestroy. which takes
Charles Max_Wood:
Uh huh.
Lucas_Paganini:
a callback function. So the ViewRef introduces... This is also new. I don't know if it was introduced in Angular 14, but I know that this is also new. The ViewRef introduced this onDestroy method that takes a callback. And what
Charles Max_Wood:
Uh
Lucas_Paganini:
happens
Charles Max_Wood:
huh.
Lucas_Paganini:
here is that when the view of the component is about to be destroyed, it's going to call this callback function. So the same principle that we have, you can apply it here. But if you do it this way, you don't have to provide a service in the component.
Charles Max_Wood:
right.
Lucas_Paganini:
You can just use the function without worrying about providing anything. So technically, it is a cleaner solution. In practice, I had issues with it because, well, first, it's not always that you're in a component or in the constructor. So... that can lead to errors. You have to be aware that you're using the inject function and you have to know the caveats about using it. But also, when you're dynamically instantiating components, sometimes that just doesn't work properly. I have
Charles Max_Wood:
Uh-huh.
Lucas_Paganini:
in my LucasPaganini.com website, I have dynamic components because I don't just render regular Markdown with my... my articles, I render Markdown
Charles Max_Wood:
Right.
Lucas_Paganini:
but with Angular elements on them. And when I render the Angular elements, I am not using the Angular converter to convert the Angular components into HTML elements. I'm not using that because I want to actually also have server-side rendering. So I'm actually rendering the Angular components. So I grab the module, instantiate the component. Everything that Angular does to render a component, I'm doing that
Charles Max_Wood:
Uh huh.
Lucas_Paganini:
manually. And when I'm doing that... like dynamically rendering Angular components from a markdown file. Sometimes using the inject function blows away everything.
Charles Max_Wood:
Mm-hmm.
Lucas_Paganini:
be honest, it's probably my fault. I don't know why
Charles Max_Wood:
Ha ha ha
Lucas_Paganini:
that happens yet. I haven't found a bug. I'm sure it was my fault. I'm sure it was my fault, but
Charles Max_Wood:
Yeah.
Lucas_Paganini:
I haven't found the bug yet. So that's something to be aware of. And if I'm using the unsubscriber service, it works. So I'm still using that there.
Charles Max_Wood:
Nice.
Lucas_Paganini:
Yeah.
Charles Max_Wood:
Well, yeah, it definitely sounds cleaner because yeah, I can customize it for each of the components, but.
Lucas_Paganini:
Yeah. Yeah. You can also, for example, one complaint that I had in a real code base where we were using the unsubscriber service
Charles Max_Wood:
Uh
Lucas_Paganini:
is
Charles Max_Wood:
huh.
Lucas_Paganini:
that other devs complained about the fact that you can sometimes forget to provide the unsubscriber service in the component and sometimes it still works because a parent component can have it. And then,
Charles Max_Wood:
Right.
Lucas_Paganini:
like, it works, it is going to unsubscribe, but it's going to unsubscribe when the parent component is destroyed, which
Charles Max_Wood:
right.
Lucas_Paganini:
sometimes is a feature, sometimes that's what you want, sometimes you just forgot to provide in the component that you have.
Charles Max_Wood:
Yep.
Lucas_Paganini:
But even that, you can work around it in a native Angular way. I think maybe the workaround word was not the best one here because it sounds like I'm going to propose a hack, but the... Yeah.
Charles Max_Wood:
Ha ha ha ha ha.
Lucas_Paganini:
The dependency injection system has many tokens to customize how it works.
Charles Max_Wood:
Right.
Lucas_Paganini:
I imagine that people are going to be familiar with the optional token, which is when you want to provide something, but you don't know if it really is being provided. So you want to use the optional decorator because if it's not there, you don't want an error. You just want it to be null. Okay. By the way, it's really interesting to know how that works. It's interesting because... We have the root module and on top of it, we have the platform module and on top, we have the new injector. So when it goes all the way up, the new injector injects new or chosen error. But anyways, another topic. What happens is... I lost myself. That's the problem with getting into other topics, Charles.
Charles Max_Wood:
It's
Lucas_Paganini:
I lose
Charles Max_Wood:
all
Lucas_Paganini:
myself.
Charles Max_Wood:
good.
Lucas_Paganini:
We were talking about the... Oh, right. Sorry. We were talking about the ways that we can customize how the dependency injects our dependencies. So we have
Charles Max_Wood:
Right.
Lucas_Paganini:
the optional decorator, which is a very popular one, but there are others. There is a self decorator, a skip self. host. I think that's it actually. I don't think that we have others other than that. And what you can do to make sure that the instance of the unsubscriber service that you're getting is the one that was provided by your component and not by a parent component, is you can use the self decorator in front
Charles Max_Wood:
Oh,
Lucas_Paganini:
of
Charles Max_Wood:
okay.
Lucas_Paganini:
it. So when you inject, you can say like private, underscore unsubscriber service is equal to the type unsubscriber, not equal, but...
Charles Max_Wood:
Right.
Lucas_Paganini:
And then you can type it and Angular is going to inject it and you can use the at self decorator. And if you do that, if the component itself doesn't provide it, you're going to have an error. That's good because you will know that, oh, shit, forgot to provide it in the component. So that's something that you can do. to mitigate any issues. But it's good to know that because sometimes you do want to get the unsubscriber service from the parent.
Charles Max_Wood:
Right.
Lucas_Paganini:
But now it's an option. It's not because you forgot and did it wrong. So that's something that can be done, too.
Charles Max_Wood:
Cool! Now, are there good ways of testing this?
Lucas_Paganini:
Yes. Actually, something that I forgot to say is the audience doesn't have to recreate that. I wrote this unsubscriber service, and I added that service to my Angular Utilities library, which is published on NPM, and it does have tests. So you don't have to worry about testing that because I'm already doing that in the library. But if you
Charles Max_Wood:
Okay.
Lucas_Paganini:
want, you can also look at the source code and see how it's being tested. But if you just want to use it, you can just npm install at Lucas Paganini altogether, no spaces, slash angular-utils. So, and from there you can import the unsubscriber service. But the test that I have internally is, I have a test component that provides the unsubscriber service. And this test component is being rendered on another test component. So it's a child of another component. And this parent component is using ng-if to create and destroy the child component. So the test that I do is, when the parent component destroys the child component, does it get an event from the unsubscriber service that it was destroyed? Yes or no. So that's the test that I do. And it works just fine. So... That's the only task that I needed.
Charles Max_Wood:
Cool. Well, we're kind of getting toward the end of the time that I've got. If people want to learn more, they want to reach out to you, see what you're working on or hire your company or anything like that, how do they find you?
Lucas_Paganini:
Nice. Well, as a content creator, they can find my content on lucaspaganini.com. Even if you want to go to my YouTube channel, it's probably easier if you just type lucaspaganini.com because from there you can find links to all
Charles Max_Wood:
Mm-hmm.
Lucas_Paganini:
other social media platforms. And from there, you can also subscribe to my newsletter, which I know that it sounds like I'm just plugging something here and just trying to get email subscribers, but it's... we're making it more and more valuable.
Charles Max_Wood:
Uh-huh.
Lucas_Paganini:
I don't want to give spoilers now, but our email subscribers will get extra content than the audience that just watches our content and is not subscribed to our email newsletter. And it's also free. We don't send spam. We just don't want to depend on YouTube or any other platform to deliver our content, right? That's like a huge dependency. So we don't want that. If you're interested in that, you can go to LucasPaganini.com slash newsletter, subscribe to that. So as a content creator, you can find me there on Twitter and Instagram at LucasPaganini2. And if you want to hire my company, you can go to our website is unvoid.com. So U-N void.com. And from there you can find. contact form you can find more information about what we do how we do it so that's also another channel that you can contact me and hire my team to do everything and make your Company your product awesome and as good as your backend is
Charles Max_Wood:
Awesome. All right, well let's go ahead and do some picks and then we'll wrap up. You've listened to the show so you understand picks so I'm not gonna explain it. I'm gonna start it out though. So today actually and tomorrow I'm gonna be at a board game convention. It's called Tim Con and it's just a local one here in Provo. And essentially what you do is you go in and you play board games all day. with strangers and you can borrow games from the convention. The reason I'm going is because one of my really good friends, he's one of my neighbors, he's part owner in a board game store here in the north end of Utah County called Gamers Inn if you want to go check them out and you live out here. But what they do is they, at Timcon, they run like five or six tables. with games that they've chosen. And then people can come and they can sit at the table and they have volunteers who teach the games, right? And so this evening from four to eight, I'm gonna be teaching these five games. And they're, I mean, they're relatively simple, almost all of them are, but if you have a local board game convention and you like board games, go check it out. I mean, it's funny because I got into board game stuff off of Ruby Rogues, our first episode of Ruby Rogues, one of the hosts picked like five board games and I realized there was this deeper world than Scrabble. So anyway, and I probably would have fallen into it at some point one way or the other anyway, but anyway, been really, really enjoying that. I get together with a bunch of friends and we play board games every once in a while. So We're going to be doing that and then the rest of the time, yeah, I'll just be finding groups who are playing games or vendors who are demonstrating games and we'll, you know, we'll check them out. So I'm going to pick that and then. I've also been listening to a book series. My wife's best friend introduced us to them. They are kind of on the juvenile end in the sense that, you know, they're not... How do I put it? So like there's some books I listen to and it's like, yeah, these are kind of written for adults. These particular books are not written for adults. They're written for, you know, basically teenagers and preteens. So the reading level is a little lower. The story complexity is a little simpler, right? That kind of a thing. But the characters are fun, the plot's fun. You know, you're discovering new things about this different world. And so it's a fun set of books. The first book's called The Keeper of the Lost Cities. I'm hearing rumors they're gonna make a movie out of it. I don't, I don't know. It's on IMDB, but there's nothing there other than I guess Ben Affleck is putting it together. But... Anyway, so if you're looking for a book like that or if you have, the main protagonist is a 12-year-old girl when you start. And so, you know, if you have kids about that age, they'd probably enjoy it because they probably have friends who are, you know, the goof off or the cute boy or whatever, you know, kind of some of the characters that are in there. And then, but yeah, it's been fun. I've been enjoying it. Right. It's not like my favorite set of books, but it's been really fun set of books. So I'm going to pick those and then I'm just going to let folks know. Um, I am launching the top end devs membership, um, and just to give you an idea of what we're doing. So we're going to have two calls every week for about an hour. And I'm going to, I mean, I've been podcasting in dev for what? Like 16 years. And so I'm going to be bringing in a lot of the people that I know from the development community over the years. And we're going to have two one-hour calls per week that are about sort of general topics. You know, one or two of them every month will be Q&A probably with me or with people that I know that are experts in some area that I know people have questions in. But for the most part, the rest of them, I'm just going to bring somebody in and they're going to kind of show us or... help us understand or answer questions about a particular topic, right? And it's going to go beyond just technology, right? So some of it's going to be career focused, you know, networking with people, things like that. Um, or how do I manage my 401k or retirement plan? You know, and then, yeah, some of it's going to be, how do I deploy my apps? Right. And, and they'll teach some of the common principles there. Right. So it'll be, it'll run the gamut and then. What I'm looking to do is every month have a one hour call for each of the areas that we cover on our shows. So there will be a one hour call every month on Angular. And I'll invite, you know, Shai Resnick or, you know, whoever, right, to come and do a presentation and answer questions and help people with Angular stuff. Right. And so that's, that's what I'm looking to put together with the membership. And then beyond that, I'm also looking to add. weekly 10 minute videos on some concept in whatever, right? So in Ruby or JavaScript or Angular, right? And that'll all be included. And then we'll also have premium feeds for all the shows. So Adventures in Angular, you can get it without the sponsor spots in it, right? And then it'll also have bonus episodes where we talk about some concept. So that's ultimately what I'm looking to put together. Some of the content areas beyond the calls may take me a little bit of time to get together, mainly because the biggest shows are JavaScript and Ruby. So I'm going to be focused on getting the bonus content together for that first. But you can still come join the conversation about all the other stuff. Right now, if you sign up, you can get it for thirty nine dollars. And I'm going to leave the price there until my birthday in December, which is December 14. At that point, I'm raising the price and there will be two levels. So you're getting the premium level for $39. If you sign up after that, it's going to be $150 for the premium level and $75 for the basic level that just gets you the two main calls and one content area call every, you know, every month. So, uh, you know, you won't get a lot of the other extras. So anyway, that's what we're putting together. You'll also get access to some of the courses as part of the deal. So yeah, and you'll get member pricing at the premium level on our summits. So anyway, um,
Lucas_Paganini:
Nice.
Charles Max_Wood:
I just wanted to put that out there cause that's what we're doing. But what I found is that when I was new at programming, I wanted a group of people that I could just come and nerd out about this stuff with on a regular basis and I'd go to the meetup groups, but they were like once a month and I wanted something more than that. And most of the time I was working with coworkers that just weren't that invested, right? They wanted to be good enough to get their paycheck. You know, they wanted to look good at work, but that was it. And so, and I just love this stuff and I love talking about it. So I wanted to create a place where those folks can come and be part of it. So anyway, that's what I'm putting together. You can go check it out at topendevs.com slash sign up. It'll take you to the right place. And yeah, Lucas, what are your picks?
Lucas_Paganini:
Yeah. Let me help you on that real quick because people sometimes say, oh, but it's going to be expensive, $150. But the thing is, oh, I can get this information for free elsewhere. Every information you can get for free somewhere. The
Charles Max_Wood:
Mm-hmm.
Lucas_Paganini:
thing is just about how long it's going to take. Every time you make an investment on a good course or in a good membership such as what you are offering, you just jump ahead. You take shortcuts and not in the bad sense. It's a shortcut because you're not having to learn something and then afterwards conflicting information with a different instructor like somebody says do it this way and then you watch another free content and somebody says do it this other way. you get, what should I do? And also, how can I get this information in a structured way that actually takes me to where I want to go and it goes outside of the basic content? Because you can find a lot of basic content out there, but what about the in-depth, what comes afterwards? So every time you make an investment on something like that, you can't just think about the fact that there's the free content online. You have to think about how long it would take for you to find... and consume and figure out which of those free contents are actually good and which should be ignored. So it is a steal. The whole world created this barrier of if it's over $100, I'm not going to invest in it because that's too much. And maybe that's part because of all the course platforms that sell courses for $5 and they created this... weird situation where people devalue the knowledge that they can get from a good course. But if it's a really well done product, like somebody put their time and energy and the knowledge that they got from their lives into it, to me it's worth much more than $100. So I think that's something that the audience needs to consider too. If they need that knowledge, you should also consider that. What would be the price? of getting that knowledge for free, technically? What would be the price of getting it without paying dollars if you try to get it yourself from the free content? How many hours are you gonna spend on it? What's the value of your hour, right? But yeah. So.
Charles Max_Wood:
The other thing I'll add is that I'm getting you in the room with these people, right? Because we're going to do like Zoom calls is what I'm looking at. So you know, if we have Kent Beck and you're on the call, I mean, we're getting you in the room with Kent Beck and with
Lucas_Paganini:
Exactly.
Charles Max_Wood:
people like him. So anyway.
Lucas_Paganini:
There's a match working price too, right? Okay, but my picks. So I noticed that some people pick technology, others pick
Charles Max_Wood:
Mm-hmm.
Lucas_Paganini:
fun. So I was very conflicted
Charles Max_Wood:
Yep.
Lucas_Paganini:
there. So I brought
Charles Max_Wood:
Do both.
Lucas_Paganini:
both. Yes,
Charles Max_Wood:
Yeah.
Lucas_Paganini:
exactly, I brought both. So in terms of tech, I am picking Flavio Almeida's angular courses. I'll be honest, I don't know if they're available in English, but I just, I had to give a shout out to Flavio Almeida.
Charles Max_Wood:
Uh huh.
Lucas_Paganini:
On Twitter, he is Flavio H. Almeida because when I was starting out, I learned so much from his courses. So this is one of those examples that we were talking about when you pay for a course and you learn so much from it that it's well worth the investment that you made. awesome instructor, great didactics, learned so much from him. And I'm also going to pick Thot Tram. I don't know if I'm pronouncing that correctly, but it's Thot, like from Thot and Tram, like T-R-A-M. They have blog articles about Angular and their articles are very in-depth. I don't think they are very well recognized. for the content that they do. But I have learned in more than one occasion very in-depth things with their blog articles. So I'm going to also pick Toftrim. They have a very good article about portals. It's from them that I learned how to dynamically create components and elements with Angular. So highly recommend. both. If you happen to understand Portuguese, Flávio Almeida's course is awesome. I'm sure that he probably has content in English too, but I'm not so sure. But if you understand Portuguese, definitely check out Flávio Almeida's courses. And if you just understand English, Lucas Paganini seems to also be very good at Angular if you want to check it out.
Charles Max_Wood:
He's a good guy from what I hear.
Lucas_Paganini:
Good guy from what I hear. For fun picks, I will pick Overcooked. If you are tired of being frustrated with code, you can now be frustrated with your gaming and cooking skills.
Charles Max_Wood:
Uh-huh.
Lucas_Paganini:
I love that game. I'm always playing that with my brother. It's very popular, but it's one of those games that you just enjoy so much being frustrated at it that you just can't stop. The idea is you have dishes that you need to prepare and you just you have to do them faster basically managing a kitchen, right? So you need to cook the dishes and give them to the customers as fast as possible so that you can get better tips. It's a very, very nice game. You can play. I'm always playing offline. So you can play with up to four people locally. So that's nice. And you can do that with only two controllers. I thought that was really interesting. They divide the controller. So even if you only have two controllers, you can play with up to four people because two people can use the same controller. The right hand side of the controller goes to one person and the left side to another. Those very interesting, very creative way to deal with this. constraint and I'm also picking Game Night, which is a movie. You can watch it on HBO, the streaming platform. Very funny. So if you want to actively engage with something, overcook it. If you want to just passively watch a movie, then Game Night. I had a lot of fun watching this movie. It's one of those cheesy... comedy movies, but it's just there are some particular scenes that you're like, that's great. That was so funny. So I highly recommend that that movie was one of the best comedy movies that I watched in a very long time. I had a lot of trouble laughing at comedy movies, but this one was on point.
Charles Max_Wood:
Good deal. Yeah, Thought Ram is Pascal Precht, who's been on the show before, in his group. So yeah, good stuff there. Yeah, I'll have to check out those movies and stuff. Well, let's go ahead and wrap up. Thanks for coming, this was awesome, Lucas.
Lucas_Paganini:
Thank you. Hope to be back in the future. There are a hundred more topics that I'm sure we can explore. There
Charles Max_Wood:
Oh
Lucas_Paganini:
are
Charles Max_Wood:
yeah.
Lucas_Paganini:
only, between us, Charles, there are only three topics that I feel good talking about that I feel like I have enough depth to talk about them, which is
Charles Max_Wood:
Uh-huh.
Lucas_Paganini:
Angular TypeScript and functional programming. So if you want to talk about Angular,
Charles Max_Wood:
Those
Lucas_Paganini:
I'm
Charles Max_Wood:
are
Lucas_Paganini:
available
Charles Max_Wood:
pretty broad
Lucas_Paganini:
with you.
Charles Max_Wood:
topics. I think we'll, I think we,
Lucas_Paganini:
Yeah.
Charles Max_Wood:
I think we can find stuff.
Lucas_Paganini:
I
Charles Max_Wood:
All
Lucas_Paganini:
think
Charles Max_Wood:
right.
Lucas_Paganini:
we can. I think we can.
Charles Max_Wood:
All right,
Lucas_Paganini:
Thank
Charles Max_Wood:
well,
Lucas_Paganini:
you.
Charles Max_Wood:
until next time folks, Max out.
Lucas_Paganini:
Bye.