Writing Clean Http Service Methods With Walid Bouguima - AiA 365
Walid Bouguima is a Software Engineer at Hilti Group. He joins the show with Chuck, Lucas, and Subrat to discuss his article, " Angular Clean Http Service Methods: Handle Your Backend Communication With Ease". He explains his goals and reasons why he created this method and what advantages it may bring to developers in the Angular community. Moreover, the panel shares their own perspective and some tips about Walid's article.
Special Guests:
Walid Bouguima
Show Notes
Walid Bouguima is a Software Engineer at Hilti Group. He joins the show with Chuck, Lucas, and Subrat to discuss his article, " Angular Clean Http Service Methods: Handle Your Backend Communication With Ease". He explains his goals and reasons why he created this method and what advantages it may bring to developers in the Angular community. Moreover, the panel shares their own perspective and some tips about Walid's article.
On YouTube
Sponsors
- Chuck's Resume Template
- Developer Book Club starting with Clean Architecture by Robert C. Martin
- Become a Top 1% Dev with a Top End Devs Membership
Links
- Angular Clean Http Service Methods: Handle Your Backend Communication With Ease😎
- axios - npm
- GraphQL
- NestJS
- lucaspaganini.com/web-animations
- unvoid.com
- Walid Bouguima
Picks
- Charles - The Game | Board Game | BoardGameGeek
- Charles - RedCircle
- Charles - Disney Mirrorverse: Home
- Charles - Slack | Top End Devs
- Lucas - Reaper
- Lucas - For Perfectionists - Produce Live Content
- Subrat - Clean Code: A Handbook of Agile Software Craftsmanship
Transcript
Charles Max_Wood:
Hi there and welcome to another episode of Adventures in Angular. This week on our panel we have Subra Mishra.
Subra_Mishra:
Hello, hello.
Charles Max_Wood:
Lucas Paganini.
Lucas_Paganini:
Hey.
Charles Max_Wood:
I'm Charles Max Wood from Top End Devs. This week we have a special guest and that's Walid Bugima. Walid, do you want to introduce yourself, say hello, let us know why you're famous? Can't hear ya.
Walid_Bouguima:
Hello, and thanks a lot, Charles, for the invite. My name is Walid. I'm from Tunisia. I'm working as a software engineer at Hilti Group in France. I have been lead front-end developer at Lamy Insurance Technology, Lamy Global Holding, which is a fintech and insurance company. And I'm very delighted to be with you guys today on the podcast.
Charles Max_Wood:
Yeah, absolutely. Now, we invited you because you wrote an article about basically how to write clean HTTP service methods. And it's a relatively short article, but this is something that we all do with our Angular apps. And so I thought we could talk about, hey, how do I talk to my back end? What's painful about it? What's great about it? What's not great about it? And then we can dive into some of the tools and libraries that are out there that may make it easier. So I'm kind of curious, because you start with sort of the native way that Angular gives you with the HTTP Client module. And you talk about how to clean it up. So let's start there with the HTTP Client module and talk about what people do right with it and wrong with it. And then we can move on to some of the other libraries that we may or may not be using for this kind of thing.
Walid_Bouguima:
Sounds good.
Charles Max_Wood:
So for people who are newer, do you want to just kind of give an overview of what the HTTP client module is and does? And then we can talk about how people get it wrong.
Walid_Bouguima:
Yep, sure. So HTTP client module is out of the box module provided by Angular. So if you install Angular, you don't need to basically use any third party libraries to manage your communication with the back end. It allows you to establish communication for handling crowd operations, create, read, update, and delete, like communication with database. It basically uses observables under the hood to basically establish this communication. I have been using HTTP Client Module since I started with Angular without using any third-party library external to Angular. So that's almost it. It has also HTTP Testing Module as well. if you want to create test files for your HTTP verbs, let's say, or calls to the backend. So it is like fully fledged libraries inside Angular. And it is very handy to basically handle communication even at large scale. It is just a matter of organizing your code to basically leverage this HTTP client module built-in methods.
Charles Max_Wood:
Gotcha. So your article talks about an anti-pattern that people use for the HTTP client. Do you wanna just walk us through that, like what people are doing wrong and then what you do to clean it up?
Walid_Bouguima:
Um, it is just my perspective on what is right and what is wrong. Uh, probably in large scale projects, you wouldn't like to violate the, don't repeat yourself principle, dry principle. And thus you
Charles Max_Wood:
Mm-hmm.
Walid_Bouguima:
want to have this kind of, uh, encapsulated, um, logic that is reusable, um, in all your services. And probably very simple project. You have just, um, handful of HTTP calls. But in a large scale project, you probably reach 100 calls. For instance, now in my current project, we are using GraphQL, but we are also using HTTP client as well. And we have a similar pattern as the one that is available in the article. So we don't repeat ourselves in terms of handling errors and managing the responses from the backend. So we have kind of central abstract service. that does all the job and all the consumer services are basically using this service to handle this communication. So that allows us basically to have a clean code, but also to have a central place in which you can basically establish the communication. And if there is any bug or something, you know where to go. Because if you have, let's say, 50, 60 files of services, and all of these services have different patterns of communication with the backend using a Shippy Client Module. You don't have consistency inside the code base, and the maintainability of the code base becomes very hard. So if you have this kind of pattern that I implemented in this article, probably that would be very helpful in terms of don't repeat yourself principle, for instance. Yeah, so that's one of the things that I started to notes in my old company. As we were growing, we were leveraging REST API, different endpoints. And every single developer was handling the backend the way he or she sees fit. So when I looked into the code base, there were different implementations of the exact same thing. which is communication with the backend, you'll find different implementations of the get request, of the get verb, of the post verb, of the update verb. So we decided to just basically build a service file that basically handles everything communication-wise with the backend. And if you want to establish communication with a particular endpoint, you just use the method that are inside the service without inventing the wheel.
Charles Max_Wood:
Right, so the approach is effectively to build a wrapper around HTTP client module and then have everything use that so that everything's consistent across your entire app.
Walid_Bouguima:
Exactly, yes.
Charles Max_Wood:
Cool. Does that square with your experience, Subrat or Lucas?
Subra_Mishra:
Yeah, if I remind myself like most of the HTTP client we call nowadays, it's jumbled with a lot of RxJS operators. Like you pipe all them with different operators and mostly as you told, like we handle, like suppose the get all the valves of HTTP, get, put, post, delete to a separate service, just call them and the response will be an observable. And then we pipe them with the different different operator and then subscribe that either directly as in async pipe or or in the in the component. But what I about the one's while you're talking. One thing I came to my mind was Do not reinvent the wheel or do not repeat yourself. We we use lot of interceptor like
Walid_Bouguima:
Yes.
Subra_Mishra:
to handle the error you use an interceptor and that will handle the error itself and if you want to add some suppose a header which will be common for a lot of calls and then do that in an interceptor instead of calling that. So there are some basic things which can be handled by different services or different interceptor and try to segregate them.
Walid_Bouguima:
Exact.
Subra_Mishra:
I think also if someone starts with NGRX and also some other library, they are kind of going on those directions like segregating the work to a particular place and do what needed on those places.
Lucas_Paganini:
I also had a question while I was reading your article. So one thing that I think needs to be clear to the audience is what are the conditions that allow you to do such thing in your code base? I say that because sometimes you just don't have access to the backend. And if the backend is not consistent in the way that they return, the error messages or whatever you're abstracting, then you can't really do that. This can actually be more detrimental than helpful because it, well, I tend to use this for everything, which is developers, they are always trying to not copy and paste, and it feels the right thing to not copy and paste, but it actually depends. because if you use the wrong abstraction, then you would be better off just copying and pasting because you'd be able to do the necessary changes that you need to make it work. So one scenario, which I happened to be a few months ago in a project, was the backend returned errors in different structures. Like sometimes the backend would return an error wrapped in an object and the error message would be in a property called error. Other times it would be a property called err. Other times it wouldn't return an object just a string with the error message. So it was very inconsistent.
Charles Max_Wood:
That sounds so fun.
Lucas_Paganini:
It was awesome.
Subra_Mishra:
Yeah,
Lucas_Paganini:
And
Charles Max_Wood:
Ha ha
Subra_Mishra:
I'm
Lucas_Paganini:
we
Subra_Mishra:
just
Lucas_Paganini:
did
Charles Max_Wood:
ha
Subra_Mishra:
like...
Lucas_Paganini:
not
Charles Max_Wood:
ha.
Lucas_Paganini:
have access.
Walid_Bouguima:
Haha
Lucas_Paganini:
Yeah, we just couldn't do anything in the backend because we were limited in scope to the front end because... Well, my company is basically an outsourcing of developers to another country so that you can have premium quality in a country that has a cheaper currency. And so some companies just, they don't feel comfortable outsourcing their whole repository. Sometimes they just outsource the front end because the front end is something that at the end of the day, everybody can have access to your front end. You can just inspect the element and you see everything. So... It happens that sometimes we simply don't have access to the back end. We only have access to the front end So we can't make the necessary changes to the back end to make it consistent in the way that it handles successes and failures so since we can't do that and When we have inconsistencies in the back end we can't use an approach such as the one that you suggest Because if we were to use this abstraction there would be places that this abstraction wouldn't work and then we would have to go inside of it and make changes to allow for such edge cases and then you end up having an abstraction that is taking care of way too many scenarios and it starts becoming a risk because every time that you add treatment for an edge case you may also be handling wrong some of the other endpoints. So I would say for everyone that is listening to this is every time that you have some kind of standard in your whole application, front end and back end, you can abstract that. But if at any point you have inconsistencies, then I would rethink that. Maybe you can use an abstraction in, if there is a common pattern, it may not be 100% consistent, but there are many endpoints that follow this pattern. Okay, so you can use an abstraction for those endpoints, Don't try to put everything in the same box. Like if you don't have an API call that you can use that abstraction, like just don't use it. That's okay too. I think the developers sometimes they get too hung up on, I need to use this abstraction. I made this code to reuse everything so I have to use this function everywhere. And that's not the case. Like you need to make your application work. Okay, that's your goal as a developer, it's just that. So if you have an abstraction that you can use, that's great. But if the abstraction doesn't fit your needs, or the particular endpoint that you're handling is different from the rest, that's okay too. Don't try to abstract that. You can always use the HHV client directly, or any other APIs that you need. So something to keep in mind.
Charles Max_Wood:
So I'm going to push back here a little bit because, and granted, I haven't seen this backend, right? I'm trying to imagine how awesome this backend
Walid_Bouguima:
Ha ha ha
Charles Max_Wood:
is. But anyway, so part of the deal is that I think you can compose a wrapper around the back end, right? So let's say it's this one that's got these inconsistent issues. You can encapsulate some of that stuff so that, for example, you have a response handler and then you have an error handler and then you have a, right? And I'm thinking more object-oriented and I know that JavaScript doesn't always lend itself that way very easily. Sometimes it does, right? Sometimes it's like, hey, this fits really neatly into the boxes that JavaScript gives me, but not always. But then what you do is you pass your request or your response into some kind of function that just initializes an error object that's consistent and it can take all those different kinds of inputs and give you a consistent kind of interface. And so there are ways to build these. Yeah, depending on the circumstances, it might be slightly over engineered for what you're dealing with. Right? Or you might have so many edge cases that it's just, yeah, you know, even that initialization is messy. But what I found is that as I've broken things up and composed things and, you know, figured out what the right responsibilities are for the right, whether it's classes or prototypes or you know, in TypeScript, you know, different, you know, things there. What I found is that, yeah, there are ways to work around this. so that you can have that nice clean consistent interface. Because at the end of the day, having that driver and having that place to go for that common code is there are huge, huge benefits to it. And so, you know, it's got to be just so horrendously inconsistent that it just doesn't make any sense whatsoever to count on any kind of common structure in order for me to not want to try and do what. we're talking about here.
Walid_Bouguima:
Yeah, I agree. Like it is kind of trade off. Because as, as, as Luca mentioned it, sometimes the backend is not as responsive as you may expect, but it is just a matter of convention between front end and backend to build
Charles Max_Wood:
Yeah.
Walid_Bouguima:
the system the way it should be. For instance, when I joined my new company, I found kind of different conventions than the ones that I have been. So, I think it is just a matter of conventions and then you can build the abstraction. So, you need to accumulate the knowledge of the redundancies in the system, both front end and back end, and then try to reduce them as much as possible. And that's what we are trying to do even here in this new setup. to basically build as much abstraction as possible in order to leverage the dry principle and avoid replications in code base, knowing that we have like dozens of libraries inside in the next workspace. It is very critical to have this kind of abstraction.
Charles Max_Wood:
Yeah, one other thing I'm just going to point out, because I think Luca is right, that there may be just a handful of edge cases don't fit, right?
Subra_Mishra:
Yeah.
Charles Max_Wood:
That's the other side of this, right? And so if there are just those handful, right? So everything uses the abstraction we wrote. And then, yeah, there are these three or four that just, you know what? There's just not a good clean way to stick them into this abstraction, right? Then what we do is, you know, I hate comments in code. But I would put a comment in there explaining, this has a structure that does not work with the interface we have. And so we're handling it here to make sure that we capture the error or whatever. So just give a good explanation in the code as to why you're doing it the other way.
Walid_Bouguima:
Exactly,
Charles Max_Wood:
And then,
Walid_Bouguima:
yes.
Charles Max_Wood:
yeah, if you find that edge case occurs in a handful of cases, then you can abstract that into a different interface. and tell people, hey look, if it's this way, it's this one, and if it's this way, it's the other one.
Lucas_Paganini:
What you can also
Charles Max_Wood:
And
Lucas_Paganini:
do...
Charles Max_Wood:
then you may be able to put a facade in front of it even at that point and say, you know, request handler, right? And then request
Walid_Bouguima:
Exactly.
Charles Max_Wood:
handler is smart enough to look at the structure you get back and say, you're going to go through this pipeline and these other ones will go through the other pipeline. And then you can clean it up that way.
Walid_Bouguima:
Exactly, yes.
Subra_Mishra:
Eh.
Lucas_Paganini:
What I would
Walid_Bouguima:
I
Lucas_Paganini:
also...
Walid_Bouguima:
think... Sorry for cutting you.
Lucas_Paganini:
Sorry, go ahead Walid.
Walid_Bouguima:
What I was trying to say is I just Charles point triggered kind of saying of one of my previous engineering managers who was basically saying like it is always too good to focus on patterns, patterns extraction before like solutions, abstraction. So you have to extract the patterns, then you build the solution abstraction. So, yeah.
Lucas_Paganini:
Yep. Something that you can also do to help on what Charles was saying, do those other methods, for example, if you are in this scenario, use this abstraction. If you're in this other scenario, use this other abstraction. One thing that I really like that helps with that is to use functional programming and always break things in very small abstractions. Because for example, Let's say that you're creating an abstraction for all API requests. This abstraction can be either a single function that does all the abstractions that you need, or it can be a function that internally calls others. So it's a function that is composed by other functions. So the more granular you can get in the responsibilities of your individual functions, the more you can reuse them. So even if you are in a terrible situation, such as the one that I found myself a couple months ago, you may not be able to use the whole abstraction everywhere, but there are parts of it that you can. So for example, if you know that a particular endpoint is going to return a string in case there's an error, you can create a function that looks at the return. looks at the return data from the API, and if it's just a string, treats that as an error, if it's an object, returns it as success. If a different endpoint treats errors differently, so for example, a different endpoint might return an error wrapped in an object with a property called error. Okay, then you can create an abstraction that can take the response data. and see if it's an object with the error property or if it's not. If it's not, then it's success. If it is that, then it's an error message. So you can have different functions that extract the response to see if it's a success or a failure. And then you can plug that into the rest of your abstraction. So you have a part of your API endpoint's abstraction that is the part of it that is responsible for identifying. if the response was a success or a failure. And what you can do is, if you isolate that check into another abstraction, then you can swipe out the abstractions as you need them. So this particular endpoint, you need to use this particular error extractor. This other endpoint, you need to use another error extractor. So this way you can make your abstractions more flexible because you can also internally customize them. So that's a way to go around that. But again, we're just talking about like a case that I hope most developers never get to. So I know that the case that I brought up was very, very specific. And I completely agree with what Charles said, which is there are gonna be many consistent things in the backend, even if there are many inconsistencies, there will also be many things that are consistent. So you should still create abstractions because they will benefit you. Even if you can't use them everywhere, they will still benefit you. It's just, I think it's really important to bring that up because I found myself in the strap before of having a scenario that doesn't fit a particular abstraction and then trying to make it fit. And you shouldn't be wasting time on that. You should use the right abstraction. So if that abstraction doesn't work, Either you make it more flexible, in the example that I gave of giving
Charles Max_Wood:
Mm-hmm.
Lucas_Paganini:
an error extractor so that you can customize the way that it identifies if it was success or failure, or you can just create a different abstraction. So just don't ever waste a lot of time trying to fit your use case in the abstraction that you already have. If it fits, okay. If it doesn't, then just do something else.
Charles Max_Wood:
Yeah. Yeah. I think you're presupposing a little bit that people have and take the time to refactor. Right. I think that's the other piece of this. Right. So yeah. You know, you're like, look, this doesn't fit. I'm going to eject. I'm going to use just the, you know, HTTP client module and I'm just going to go raw HTTP call on it. Um, what, what you need to be doing then is going back and looking at that periodically and saying, Is there a way that I can make this better? Because if you can make that easier to follow, make it easier to read, make it easier to reason about, then you get to the point where, yeah, somebody else can come along and maintain the code better. I also want to point out that, Lucas, your situation was a little bit different in that I think most developers on most teams that are doing Angular are either working on a third party back end API that is reasonably consistent. Not always, right? I mean, I've worked on some third party APIs that are really, really heinous. I've also worked on some that are just not well documented and that makes it hard to. Um, but most of the time you're either working on something like that where the API has kind of a deliberate design or you're working with a backend team that is internal to your company so you can go to them and say, Hey, you know, What you're doing is making it really hard for us to maintain on the front end. And if you could standardize on these three things, it would solve a lot of our problems. And so I want to just point out that in either case, communication may be your friend here, right? It may not be a technical solution. It may be a people's solution. And you may just need to go talk to the people who are providing you your data and saying, Hey, you know, have you thought about doing this? Cause it would make it a lot easier. And if it's a third party API and it's a solid suggestion, I mean, I would hope that most product companies would appreciate that. And then if it's an internal thing, you know, hopefully you have a healthy enough culture to where they just look at you and say that that makes a lot of sense. Right. We are building this to service what you're writing. So we'll solve that. But it sounds like in Lucas's case, um, those weren't really options that he could pursue aggressively.
Walid_Bouguima:
Yeah, exactly. Just probably to build on top of what Charles just was saying is the importance of documentation, like if you are building abstractions, it is very important also to document this very well. Because for instance, when I joined the new code base, I found a lot of built-in abstractions inside the code base. And sometimes it is very hard to reason about them. And sometimes you just opt to use the. the native capabilities of the frameworks just to leverage value as fast as possible without spending much time understanding why this person did this abstraction, right? So I think like the other side is documentation is very important when you build abstractions.
Subra_Mishra:
Yeah, and also like I just thinking when when all the discussion happening is coming to my mind all the methodology all the architecture and everything is always like always depends on the situations. Like if you if you have architecture or have a methodology and you have a complete different situation, you can't just grab a methodology and put in your situation like put in a situation that you should not expect it's going to behave pretty good. Because like, like the what Luca said in in his situation, like suppose there are a lot of variables are different, a lot of there's continuous back and forth is going on with the back and front and a lot of things. So that then it's might be better to go with a normal approach then. But in most of the most of the scenario where we have a solid back end object, what you are getting and Then we can implement all those like happy, happy path scenario. And then you can have a lot of implementation by not considering the, like it's kind of, if you're creating some methodology, after you are thinking like the backend should give something because suppose in the front end, if you are doing this dot something in the, if that, if the backend change the name of dot to something else. This is going to break no no matter what we'll do like we can't go out and write abstracts on every day like just to change the name every day and just talk with them. So that would be a contract between the front end and back end. I know in the ideal scenario like it should be there but in a lot of scenario it's it's like pretty hard to get sometime. So always what I might suggest or like. first check your scenario of why, what is the problem in your code, then try to solve that with a better methodology or better abstraction, which will suit for your particular use case. But what Walid is saying, I think it will, because I haven't experienced this kind of problem because fortunately I never, I always worked on both side. front end and back end. So I have the control on both, but I also I know that some of my friends worked on, but they always have a communication like they all have a swagger file path to check what the back end gives. But I think most according to me, at least 90 to 95% of time valid approach will going to work. But some 10% might need to find a. way around on that and try to fit something else.
Charles Max_Wood:
Right.
Walid_Bouguima:
Yeah, I think like
Charles Max_Wood:
So one thing I'm curious
Walid_Bouguima:
it is very
Charles Max_Wood:
about,
Walid_Bouguima:
good point in terms
Charles Max_Wood:
oh, go
Walid_Bouguima:
of,
Charles Max_Wood:
ahead.
Walid_Bouguima:
yeah, I think the last point is very critical because also communication is important, right? Between backend and frontend. I mean, like it's not like the technical communication between frontend code and backend code, but the human communication between developers to establish these kind of conventions. I think there is like kind of low, like Conway's low. which basically states that the design system is a mirror of the communication strategies inside the team, right? So if the communication between team members is broken, then you cannot build a solid, resilient system, right? So you cannot build an abstraction around Angular, a Shippee Client module if you do not have a standard backend responses. and agreements on the response's shape. And also I think TypeScript helps a lot in terms of interfaces as a convention between API responses and front-end code. So that's also a good point also to mention.
Charles Max_Wood:
Yep. Now, one other thing that I'm curious about is do you all use the HTTP client module to make your HTTP calls or are you using some other third party library that gives you a cleaner, nicer, you know, I guess more natural to you interface?
Walid_Bouguima:
For me, actually I use it to use the GPClientModule for a while, I would say since I started with Angular, but with my new setup, GraphQL is kind of front time system that
Charles Max_Wood:
Mm-hmm.
Walid_Bouguima:
sits between front end and back end. And the GPClientModule wouldn't work here because there is also a wrapper around the GraphQL to establish communication, which is Apollo, right? So Angular, Angular Apollo is... a very handy library that we are using here. And as far as I know, the whole system is using Apollo Angular to handle communication with the GraphQL runtime. And it is kind of an abstraction as well around the Chippy Client module. And it is very clean and it has a lot of parts that are keen to... to GraphQL system as well, like for instance, fragments, you can like make a query to the backend with the fragments and these fragments can be reused in other parts of the system. So for me, like I was not really expecting it to be as mature as it is because I think GraphQL is kind of new to the ecosystem but Apollo is kind of strong skatable with Apollo Federation, for instance. And it is like a topic that is studied now inside the company. So I think it is also a good option to use Apollo. But inside Angular, I think there is also NGRX, right? With the effects, you can also establish communication
Charles Max_Wood:
Mm-hmm.
Walid_Bouguima:
with the backend. So that's also something very useful that I had the chance to work with.
Charles Max_Wood:
Yeah, I think GraphQL alleviates a lot of these issues, right? Because you have to give responses back with a certain structure. You can make certain assumptions about what you're going to see and how you're going to see it. And so at the end of the day, it, yeah, it solves a lot of this and those interfaces are looked at by, you know, hundreds of developers and they tend to you know, be kept clean and give you specific ways of doing specific things. And so I think it really kind of, it obviates a lot of these problems. It just makes them not really exist. You know, you have different issues, you're making different trade-offs, but if this is your problem, you know, it makes this particular problem go away.
Walid_Bouguima:
Exactly, yeah.
Lucas_Paganini:
On that question, Chuck, about using or not HTTP client, I do have something that I consider really important to say, which is even if you want to use a different abstraction because of a cleaner interface or you just prefer a different syntax, be sure that this other interface, this other abstraction internally uses the HTTP client. So for example, Waleed gave the example of NGRX and also Apollo Angular. I have never used Apollo Angular myself, but I would bet that internally it uses the HTTP client. That's important because Axios, for example, Axios by default uses the Fetch protocol, the native browser Fetch protocol. And that can be a problem if you're in Angular applications. because that means that you're making a request outside of the framework. It may sound like a small thing, for example, oh, but what am I losing? Am I just losing HTTP interceptors? I don't need HTTP interceptors, whatever. It's not just that. There are other things that Angular does, and it can only do if you're using the HTTP client, because the HTTP client kind of... It's kind of... You're making... an HTTP request and it's going from inside the framework. So the framework is aware of it. And one of the things that it can do, for example, besides HTTP interceptors, is if you are running your application server side too, then you will need the HTTP client. Otherwise, Angular will not know if your components are already stable and ready to be given to the front and ready to be rendered. So in the back end, you will need to be using the HTTP client if you're using server-side rendering with your Angular application. And it can also serve as a caching layer. So if you are using server-side rendering in Angular, then once your requests are made in the back end, they don't have to be made again in the front end. So when the back end gives the rendered front end back to the client, they can already give the cached responses for the HTTP requests that it had to make. And then when the front end loads and tries to make those calls, it just gets the cached result. So it doesn't have to make those HTTP calls again. So that's a small detail that you can only achieve if you are using the HTTP client. So it's not a problem if you prefer a different interface, a different syntax than the one that the HTTP client gives you. Just make sure that whatever abstraction you create internally uses the HTTP client so that all your HTTP calls, they go through the internals of the Angular framework and Angular is aware that you're making those calls and is aware of the responses that you got because Angular does some things with that information.
Subra_Mishra:
yeah I think Lucas was absolutely right on on the basis of if like that anchor is not only making a HTTP call it's going through a process like the upward and then coming back again to the to the component but I I would suggest like I have used like what like for the Charles question to other HTTP client so I uh, directly fetch. So in those cases, suppose one of the scenarios, if I'm calling something from the worker and I would don't want the execution to be flow, uh, then I use fetch there directly so that I may not need to pass the context and all. And so it will do the work and just, uh, get, get the result back in instead of going through the whole angular And also similar case if you want to run something outside Angular, you don't want to run the change detection with it. I know that is rare. If you want to run something and you want to call the server, getting it back. In those scenario, you can either fetch or other XHR request to get a result without informing Angular and just push your updated data to the Angular change detection or Angular. angular dom you can say.
Walid_Bouguima:
Yeah, I think
Charles Max_Wood:
Yeah,
Walid_Bouguima:
like
Charles Max_Wood:
that does
Walid_Bouguima:
if,
Charles Max_Wood:
sound like a little extra work.
Walid_Bouguima:
exactly, yeah.
Subra_Mishra:
Yeah, if it's like performance is the if you are counting on milliseconds then
Charles Max_Wood:
Okay.
Subra_Mishra:
Then it might be
Charles Max_Wood:
So, so that's the trade you're making, right? Is performance
Subra_Mishra:
Yeah,
Charles Max_Wood:
versus
Subra_Mishra:
yes, performance was here.
Charles Max_Wood:
simplicity, I guess.
Subra_Mishra:
Hmm.
Charles Max_Wood:
What were you going to say Walid?
Walid_Bouguima:
I was about to say like, you can even build this kind of wrappers around not only classes, but the verbs themselves. Like if we are familiar with Jest, for instance, not Jest, Nest.js, which is
Charles Max_Wood:
Mm-hmm.
Subra_Mishra:
Yeah.
Walid_Bouguima:
like Angular in the back end, right? They have this kind
Subra_Mishra:
Mm-hmm.
Walid_Bouguima:
of decorators to handle post add delete, and then you just fire the observables with these decorators. So I attempted actually to build this kind of decorators with HTTP verbs on Angular and just using the decorator pattern, and it works very well. Actually, you just have like a function, name it add get or name it whatever you want. And then internally it uses HTTP client. And then in your services and your classes, you just call this function or import it. And then you just pass the endpoint to it. And then in the decorated function or method, you just pass the response. And it's, I think, way cleaner than basically handling this with a class wrapper around the HTTP client module.
Subra_Mishra:
Yeah, I think Nest nailed it with, I think they did this. They got the concept from, what I got it by working in Nest is they got all the concept from Spring Boot, all the concept from Angular, I tried to merge them and did a very good job.
Lucas_Paganini:
I'm gonna do the opposite opinion here. Sorry, but I really tried. I really tried to use Nest because I like Angular so much that in Nest just fits so well. If you're in an NX workspace, like it integrates well with all the other libraries in your monorepo that I so wanted to use it and the documentation is so well done. They have so many stars, I was outshined by all the greatness of Nest. But I really didn't like using the angular approach in the backend. And I think in my case, it's because I feel like object oriented programming really fits well in the frontend. I myself don't like object oriented programming too much. I've... prefer functional programming, but I try to be pragmatic in my choices and it feels like object-oriented programming really fits well in components. When you have the mental model of a component, you think of a component having state. So this to me is an indicator that object-oriented programming works well for components. I think of a class when I'm thinking of a button, when I'm thinking of a card component, it really makes sense. But when I'm in the backend, I feel like functional programming works best. It's easier for me to understand the flow of the application. If you're in the front end, for example, there are way too many scenarios for you to interact with something. you can have three buttons and those three buttons can activate the same action. The backend you don't really have that too much. You generally have one endpoint that does what you need. If you need that thing you call this endpoint. So it just feels like using functional programming in the backend feels like the right choice to me at least. And Nest didn't provided me with ways to use functional programming in the backend. Even though in the docs they say that they are object oriented and reactive functional programming, I feel like they are much more object oriented than functional programming oriented. And this was really hard to me so I really tried using that. Everybody from my team hated it, to be honest. Right from the start they were like... Really, I don't think this is the right pattern here, but I was like, no, let's try, let's try more. And we really pushed after all the hate and the hate just stayed there. I thought it would slow down while people get used to it, but we just didn't get used to it. It always felt like the wrong approach for backend. So that was my experience with NASDAQ. If you are listening to this and you are getting very angry at me, I'm sorry. I tried.
Charles Max_Wood:
Well, I think that's the wonderful thing about programming is that we all have different things that we like. The other thing is, is you may have picked up something that, you know, it's like, I'm going to build this in Nest and it's just not a good fit for Nest, right? I mean, there are a million reasons why it may or may not have worked for you. But I mean, that's the great thing is, you know, it's like, hey, this just, you know, I just My mental model and Ness mental model just don't jive. And so I'm going to use something else. And that's awesome. Right. We have so many other good options, you know, like rails, uh, which is
Walid_Bouguima:
Exactly.
Charles Max_Wood:
my backend of choice, right? I love writing in Ruby, you know, or you may want to go pick up, um, express or sales or something else in JavaScript. Right. Because that's your cup of tea and they all work and it's cool. So yeah. Um, I mean, I would recommend it to anybody if you're doing Angular to at least try it, right? And then from there, you can say, you know what, this one's not for me, right? No harm done? But yeah.
Walid_Bouguima:
For me, from my experience with Angular when I wanted to try the back-end work, NASJS was the smoothest transition possible for me towards back-end. Even though Angular is kind of object oriented, shifting towards Spring Boot or Java is kind of painful compared to NASJS. At least the same mental model. inside Angular is in Nest.js. So I did not really find it difficult to build API endpoints with Nest.js. The same concept, the same design, patens, decorators, the singleton, you inject the service inside constructors. So it was exactly the same. If you have kind of familiarity with Angular, Nest.js is, from my perspective, a good option in the backend.
Subra_Mishra:
Yeah, it's always a
Charles Max_Wood:
One
Subra_Mishra:
debate.
Charles Max_Wood:
other thing that I'm just gonna... What was that?
Subra_Mishra:
I'm saying a good framework bad from us. It's always a debate.
Charles Max_Wood:
Yeah. Yeah.
Walid_Bouguima:
Yeah.
Charles Max_Wood:
One thing that I will say though about back ends relative to our discussion over HTTP calls and things like this is that certain, you know, and I've like Express is a little more freeform in my opinion, right? You can kind of give a response
Subra_Mishra:
Yeah.
Charles Max_Wood:
back that looks like anything, you know, and then like Rails, they give you a default where everything looks, all of your responses are going to have the same format, right? And others, you know, or somewhere in between. And so that's another thing just to keep in mind. And some of them also, like, I think there are some libraries in Express that actually um, sit on top of it and kind of push you toward a consistent format in your responses. And so, um, you know, however you put that together, just keep in mind that, yeah, there are libraries and, or frameworks for the backend that are going to make the, the front end backend consistency. You can start making a whole bunch of assumptions about what it looks like and what it's going to do under certain circumstances so that you're getting what you expect. And then, um, the other thing that I would, uh, push to is, um, and I've done this, especially when I was consistently getting responses from a backend on my front end that I, that, that I couldn't, you know, I didn't expect it to be, or it was changing on a regular basis. Cause the backend team was working on that particular endpoint and change stuff or change the structure of the objects it was giving back or what have you is I've actually written API tests for my backend and put them into my test suite and then just run them every week or something so that I have that consistent feedback. Oh, this changed. I got to fix it right before it becomes a customer calling up and going, Hey, it doesn't work anymore. Right. And so I mean, there are things you can do to mitigate a lot of these things from the backend and the front end side. And don't be afraid to go reach for some new library tool, technique, idea, and, you know, and implement it either through testing or, you know, some kind of convention in your code.
Lucas_Paganini:
And that connects really well with our last podcast episode, which was with Marek. So if you haven't listened to the last episode, after you finish this one, go check it out
Charles Max_Wood:
Mm-hmm.
Lucas_Paganini:
because we talked about how to break your frontend into smaller pieces. And one of the pieces that we suggested was an API client. So it's a part of your frontend application. that has the singular responsibility of connecting the front end to the back end. So that's the perfect place for you to do integration tests and make sure that your calls to the back end are being done to the correct endpoint, that you are treating errors correctly, that the data structure that you're getting from successful responses is correct. So go check out this episode. because it links really well with everything that we're discussing here.
Subra_Mishra:
Yeah, and I guess about what Walid also mentioned little before, like, and trying to adopt the annotation to the different verbs. So like to touch, I think that will be a good, like, would like to touch a little more on that. Like Walid, if you can explain like how you came on approach on that, like, and how it helps you to mitigate. Reduce the lines of code in a code because that's like sounds good for me because you don't need to create multiple service. Just create
Walid_Bouguima:
Exactly.
Subra_Mishra:
annotate faster, pass the URL and.
Walid_Bouguima:
Exactly. Yes. So as I mentioned, since I tried Nest.js, one of the main differences between Nest and Angular is the usage of the method decorators, like get, put decorators. So I said, probably this is possible with Angular, knowing the decorators is just TypeScript pattern, and you can probably build a function like this. and then use it with the CP client module. And then you decorate a particular method inside your classes, and you don't need to make injection of services with a singleton pattern. You relay on the decorator pattern, and you have like probably one file that exports these functions, like add, get, add, delete, add, boot, add, and then use, just use or import these functions inside your consumer files. or components directly, and then you fire the HTTP requests from the components themselves without relying on the service. So I tried that, and
Subra_Mishra:
Mm-hmm.
Walid_Bouguima:
it worked well. But I did not try it in production code base.
Subra_Mishra:
Mm-hmm.
Walid_Bouguima:
But it is just kind of inspiration from Nest. And I was just wondering why probably this is not an option inside Angular, knowing like
Subra_Mishra:
I was about to ask that. Yeah.
Walid_Bouguima:
Yeah.
Subra_Mishra:
I think a lot of options are there. You can maybe, um, uh, people what might come into my mind right now is, uh, we don't, we, we not only pass the only the URL, sometimes we pass a lot of verbs like HTTP headers and some keys.
Charles Max_Wood:
Mm-hmm.
Subra_Mishra:
And those things that might be different for different methods and different calls. Uh, might be that, uh, to making a common annotation, uh, for all, or, or we can create multiple annotations like what we're doing next and just add, add, add. And then, then you'll get a bunch of annotation and that will pass the whole whole process.
Walid_Bouguima:
Yeah, there is kind of evolution inside the framework. The last two releases, I think they introduced the inject function, for instance. You don't need to basically inject your services in the constructor, right? You just the inject function. And I see kind of evolution towards more functional programming inside Angular, more than object oriented, right? Even the routers now are kind of functional. You don't your guards this way. You can just inline declare function and handle the option of having these decorators.
Subra_Mishra:
Yes, the same net nest you can share your modules and those things are there. But I think Angular also doing standalone components. So Angular is kind of going towards functional as you told. I think a lot of my if I remember Java is also trying to so all every every fema is also trying to like adapt functional functional way programming because that's how makes a lot of things easier. Instead of going strictly object oriented you can create function pass it around and do a lot of things with it.
Lucas_Paganini:
And it also doesn't have to be one or the other. I
Subra_Mishra:
Yes, both.
Lucas_Paganini:
use a lot of functional programming inside Angular, inside classes.
Charles Max_Wood:
Mm-hmm.
Lucas_Paganini:
There are methods in your classes that can be reused. So sometimes you have many different components that have a particular method that can be isolated in a function. So there you can see the two patterns coming together. You can isolate a particular class method in a function and reuse that. So I. I am personally really happy with the direction that things are going in all languages. I think that functional programming is indeed the right path to all languages and for modern software development. I think there's way too much to make more popular yet inside functional programming because... We still talk about functional programming just inside the scope of creating small functions. And this is, well, one of the main benefits, but it goes so much deeper than that, like way, way, way more deeper than that. And then you have the more beginner level, which is, oh, it's map, filter, and reduce. Also not just that. goes way deeper than that. Then you have intermediary level, which would be like trying to keep everything immutable, using const, using data structures that allow you to have immutability. But still, there's just so much more, so much more than that. And if people really understood all the different patterns that functional programming gives us, I think that... You really can't go back. After you see the level of abstraction that you can have with functional programming, you really can't go back to any other styles of software development. You get hooked into that. It's so much easier after you get the hang of it. But just like Angular, it's a very steep learning curve. If you get any functional programming book, not gonna say any because there's too many things in the universe. but most of them, they do I.O. at the end, because I.O. is a monad, and it's difficult to explain what's a monad. So they start with a lot of other things, but they don't teach you how to do a Hello World, because Hello World is super difficult in functional programming, because it means that you need side effects, and side effects are difficult. So it's a steep learning curve because of that, but if you... Oh man, if you go through it, it is worth it. I really recommend.
Charles Max_Wood:
Awesome. All right, I'm going to push us toward picks here. We've been talking for almost an hour and I think we've pretty well covered this. Real quick, Waleed, if people want to follow you on social media or GitHub or things like that, where do you typically hang out? Awesome. Well, if you want to put those into the forum, we'll make sure that those wind up in the show notes. Now, I'm gonna stop telling people that this is a new segment and I'm just gonna go for it. We're gonna do the self-promotion, what are you working on stuff. Lucas, why don't you start us off?
Lucas_Paganini:
Okay. The fact that I'm starting the self-promoting section always feels like I'm the salesperson. But anyways. I'll start it next time, I'm sorry. I was just talking about the
Charles Max_Wood:
I'll
Lucas_Paganini:
person on
Charles Max_Wood:
start
Lucas_Paganini:
the
Charles Max_Wood:
it
Lucas_Paganini:
end,
Charles Max_Wood:
next time then I'm sorry
Lucas_Paganini:
not
Charles Max_Wood:
I always just pick the person on the end that's not me
Lucas_Paganini:
me. That's okay, I don't mind. But it is funny. I am going to promote the same thing that I promoted last time, which is my web animation scores. I am really pumped about this course. Today I'm gonna record two more lessons to it. So it's not ready yet, but there is a waiting list. So if you go to lucaspaganini.com slash web animations, you can join the waiting list and guarantee a discount price when it gets launched. And basically I am covering transitions and animations in the web from in CSS and JavaScript. So I'm starting things with no libraries, just the native technologies, what you can accomplish with just native CSS and JavaScript and really going deeper into web animations because I think most web developers, some point in their careers, they have done some kind of transition in the front end, but most developers don't have a strong mental model of how that works. So this is... the gap that I'm trying to fill. Really giving you the right mental model so that you understand how transitions and animations work in CSS and JavaScript. And then if you have that strong mental model, then you can create whatever you want with it. So there's that and there's also a lot of practices, a lot of exercises. A lot of them, I'm just putting them for free on YouTube. So I am... releasing, for example, let's do a switch toggle animation, let's do a different card hover animation, so I'm putting those kinds of tutorials on YouTube, but if you want a step-by-step learning process, you can check out the scores on WebAnimation, so just go to LucasPaganini.com slash WebAnimation so that you can join the waiting list and guarantee a discount price when it launches.
Charles Max_Wood:
Awesome. How about you, Subrat?
Subra_Mishra:
Yeah, I would like to promote my YouTube channel, which is fun of heuristic. So please go and check that. I know I haven't posted a video since the last six months. So finally, I did last Monday. So go and check and check the video. And I'm promising you guys I will keep continue posting video now onwards. Yeah, for now, this will. I will promote this.
Charles Max_Wood:
Awesome. I'm gonna throw out, so I just finished putting together the raw videos for the resume course. And I've been talking to a bunch of people, they're either stuck and they're trying to find some place that'll take better care of them, I guess, or you're seeing a lot of big companies here in the US that are laying people off, or people are quitting Twitter because they don't like Elon Musk, or for other reasons. I'm not gonna dive into the politics of that. But if you're looking for another place to be, the course covers cover letters and resumes. And it's a little bit different approach from what most people do. So I'll just give you kind of the elevator pitch. Most people, what they do is they go on a job board, they look around, they see what's out there, they put together a resume that they think will get them an interview, and then they blast it to everybody on the job board. And the problem is that... what you wind up doing is you wind up sending out resumes that aren't really optimized to get you an interview with any one particular company. And so what I walk you through in the course is effectively how to... So I give you my resume and the template that I use, and then I walk you through how that's put together. And then I walk you through, hey, here's how you build that baseline resume that everybody blasts everybody in there. their mother. And then what I walk you through is how to research the companies you're applying to. And you can do it in about 10 minutes. You can get a pretty good feel for who they are and then effectively how to use the information that you're picking up in order to write a resume that includes the stuff that you know they're looking for and then how to write a cover letter that puts your best foot forward and also explains to them how you are the person that fits the kind of person they're trying to hire. And that one piece in the cover letter is really hard to put across in the resume. And so, or the CV, people call it a CV too, if you're wondering what a resume is. But anyway, so yeah, so the point is, is effectively, then you've got a resume that gives people all of the qualifications you have for their job and allows them to tick the boxes like you have a college career or you have 10 years of experience. And then you give them the cover letter that explains. I am a really good fit for your company and here's why. And your company's a really good fit for me and here's why. And if you can explain those two things in your cover letter, then you are in a much better position because then they know that you're interested and they can start to validate that you are a good fit. So anyway, uh, go to topendevs.com slash courses. It's listed right there. Um, I'm working on the, the keep current and learn quickly course now. Um, so you can pre-order that. and then get the lessons as they come out. If you just want my resume template, here's the last one. You can just go to topendevs.com slash resume and you can get the, it'll just email you the template. So anyway, and that's free. So yeah, that's what I got. Walid, what are you working on? Awesome.
Subra_Mishra:
Then you'll have another episode, what I'm saying.
Charles Max_Wood:
There are also a, go ahead.
Subra_Mishra:
What I'm saying, then you'll have another episode on that.
Charles Max_Wood:
Yeah, right. Yeah, we did some episodes on JavaScript Java about Core Web Vitals. So we might get some of the Google engineers to come on and do that. Because that's a really good idea to talk about it within the context of Angular and how that works. But yeah, cool. Let us know when those articles are up, and we'll let people know about them. All right, well, let's get to the picks. Lucas doesn't want to go first anymore. So Subrat, what are your picks?
Subra_Mishra:
Yeah, I think this we have looking onto the book called Clean Code. I think it's a pretty famous book. How it should learn and also watch a video of the author of Clean Code and like how he explained why we need to write and that that is that is good. Like the approach. This that's What he is saying is if you don't write clean code, politicians will come inside and they will make some rule how you're gonna code and it will be bad. So just go watch the video. I think it's pretty easy to search in internet and just have a look on a book called clean code.
Charles Max_Wood:
Very cool. We're actually reading clean architecture for the book club for
Subra_Mishra:
Mm-hmm.
Charles Max_Wood:
Top End Devs. So feel free to join us. Uncle Bob is going to be there tonight as we record this. He came to the first one and I think he's gonna come to the rest of them. And you can go sign up at topendevs.com slash book club. Lucas, what are your picks?
Lucas_Paganini:
My pick will be Reaper. This is a free to use audio editing software that I am actually using right now to record my microphone and I just really like that it works in all platforms so all of you Linux fans you can also use that. You don't get stuck in the environment of using If you hand that off to your videographer or audio editor, they might be running Windows and this might not work. So Reaper is a really good software for audio editing and you can just use it for free if you want to. So this is going to be my pick number one. My pick number two is going to be if you're a perfectionist, do a podcast. Like I have... improved so much my perfectionism since I joined this weekly podcast. You have no idea. Like the... It's funny because you don't know the behind the scenes of my mind, Chuck, but when you invited me to be the co-host, I was calm and saying, oh yeah, sure, that would be awesome. Thank you. But internally in my mind, I was like, holy shit, that's going to be live content. Like if I say something wrong, I won't be able to edit that later. I mean, what if I say something completely wrong? Oh my God. And so doing this podcast has helped tremendously. I'm even producing way more content than before. I was polishing my content way too much. I have a video on Angular 15 to be released for three or more weeks now. And it started by, let me try to put it to do a three minute video. And then it became a. 20 minute video with animations and like every single thing that is new in Angular. And I always do that. I get something and I just can't rest until it is really, really, really high quality, which can seem like a good thing, but it's actually not because there's a point where the quality is already high enough that you should focus more on like outputting more content instead of just trying to... polish something eternally, avatar movie. But yeah, that's a good example.
Charles Max_Wood:
HAHAHAHAHAHA
Lucas_Paganini:
Yeah, sometimes you just gotta put out the movie in less than 10 years of difference, you know? So yeah, I would highly recommend if you're a perfectionist, like it doesn't have to be a podcast, but something that is live and it's gonna be published for everybody to see. and you do that in a frequent basis. So every week or I think every week is better. So if you have some kind of thing that you create content every week in a live format, that helps so much to reduce perfectionism and just get things done. So that's my last pick.
Charles Max_Wood:
Awesome. I'm gonna go ahead and throw out my board game pick. So it's called The Game, the card game. Yeah, it's a terrible name. It's like code written in code. But the name of the game is The Game. And what it is is you have cards numbered one to 100 and It's a relatively simple game, but what you do is you, I'm trying to find it on BoardGameGeek, but... Yeah, it's hard to search for on BoardGameGeek because the name sucks. But anyway. I'll find it. But anyway, because I want to tell you what the weight is on board game geek, but Oh, here we go. So anyway, what you do is you you have like two or three basically lanes of cards and you can start them at one or 100 and then you stack cards on and you can stack cards that count up, you know, so you can put cards that are higher than the number if you started at one or lower than the number if you started at, at a hundred. And then what you do is there are certain rules, like you can put a card that is exactly 10 lower, 10 higher than the other card and stuff like that. And so you, you know, if you manage to skip a number, right. So let's say you skipped 93, right. You had 96 and then 92. And then you have 88, then you put 98 on and you can, you know, you can keep counting down or up. And the whole point, it's a cooperative game and you're trying to get all of the cards placed. Um, it takes about 20 minutes. I played it with a couple of my friends. It was super fun, super fast. We played it like three or four games, uh, times in a row. Um, board game geek rate rates it as a weight of 1.25. So it's a really, really simple game. Definitely a game that I could play with any of my kids. My youngest might have a little bit of struggle with the strategy, right? When to put what card where, right? And, oh, that's too big a jump to go from 53 to 33. But other than that, that's kind of where you go. And you're drawing the cards as you go. So sometimes you don't have a choice, but to make a bad play. But yeah, there are those other ways of mitigating, you know. going back or trying to put the cards on another stack. So anyway, that's my pick this week is the game. And then another pick I have, this is something that I'm just moving things to now. So the podcasting setup that we're using at the moment is something that I built in Rails, right? And it works pretty well. I'm actually really, really happy with it. It does everything I want, right? Well, eventually it will do everything I want, but right now it does a lot of the things that I want that I just couldn't get out of any other system. but we are looking at moving to Red Circle for our media hosting. And so I'm gonna pick them. If, you know, Lucas talked about starting a podcast. By the way, I am planning on launching in the first quarter of next year a podcast course. I guess we're not doing self promo. Anyway, podcastplaybook.com is where that's gonna be at. But anyway, so yeah, they're doing the media hosting and they're gonna manage the RSS feeds. The thing that's nice about them that I didn't really want to build is they do the automatic ad insertion. If I have, let's say that we're doing Top End Devs conference next month, and I want to promote that or I put out the podcast course, I can put the ad in and I can tell it to insert it in all of our back episodes. And so if somebody decides, I'm going to listen from number one to number 567, I think is what we're on on JavaScript Jabber, right? It'll put it in there and they'll get current ads, right? For current products, right? And so then if I have a sponsor from five years ago that goes out of business, it's not a, you know, it's not a dead link, right? And, uh, anyway, so that's. That's something that I'm kind of excited about. And then the other thing is, is I do want to pick our Slack. If you go to topendevs.com slash Slack, you should be able to get into the Slack channel and you can chat with us. And yeah, I love getting the feedback from people. So I'm going to pick that as well. And then... Yeah, I've gotten into this game on my phone that's probably a giant waste of time, but I'm going to pick it too. It's called Disney Mirrorverse. So they've got the Disney characters, except they're slightly different, right? Because they're from alternate dimensions. And you do battle. It's a pretty mindless game, but I'm enjoying it. So I'm going to pick that. All right, Waleed, what do you got? What are you going to pick? All right, cool. Well, thanks for coming, Walid. This was really fun. All right, we'll wrap up here. Till next time, folks, Max out.
Subra_Mishra:
Bye bye.
Lucas_Paganini:
Bye.
Writing Clean Http Service Methods With Walid Bouguima - AiA 365
0:00
Playback Speed: