Anti-patterns in React with Jonas Herrmannsdörfer editorial edits === [00:00:00] Hi there, and welcome to PodRocket, a web development podcast brought to you by LogRocket. LogRocket helps software teams improve user experience with session replay, error tracking, and product analytics. Head over to logrocket. com today and try it out for free. My name is Paul, and joining us is Jonas Herrmann Stoffer. Jonas is a freelance senior software engineer focusing on React, and specifically anti patterns in Reaction. Today we're going to delve a little bit into talking about, one of the most widely used data layers, you could call it out there, GraphQL. And Good ways to use in the not so good ways to use it. So welcome to the show. Jonas, excited to have you on. Yeah, hi Paul, thanks for having me. Okay. Anti pattern, what would you is an anti pattern Jonas. And in your mind, if we're going to step into this, ~it things like you just shouldn't do is ~there things you see a lot [00:01:00] that maybe people shouldn't do ~is the ~things that you should do that put you into a hole sometimes. Yeah, it depends. So basically like things that you shouldn't do, but sometimes things that you must not do at all. So it really depends. Some of the anti patterns are a bit~ yeah, ~way worse to do. And some are okay ish to do. And sometimes it depends how much time your engineering team has quick wins, like quick time wins but performance loses, yeah, no, is and helping people overcome those anti patterns before it bites them in the butt? What was your journey to getting here? Were you an educator? Are you an [00:02:00] educator now? so basically I'm just a normal developer and just, Working with different companies and mostly staying at different companies for quite some time and working together with teams and fixing some issues. Together. I'm not the only person that, that is doing all of the things and also the anti patterns I learned about, it was not all me that fixed them. We fixed them together as a team and I learned by working with other really good individuals together that, that helped me found some of the anti patterns. And basically what we are talking about and the talk I gave at some conferences about anti patterns is just a summarization of some of the issues I. ~I learned to yeah, I ~learned about it. Some of my projects I've worked on. Do you find that anti patterns are something that people have no idea that they're stepping into? Or ~is it ~is there like the sense of Hey, like the team's going, I don't know if this is a good idea, but they do it anyways. Like how much do you feel that anti patterns you find when you're working with these companies [00:03:00] blindside people completely? Or is it not the case as much? yeah, I think it's blindsided. So most of the time, ~no one would, I guess ~no one I know would do it intentionally, like to do something that is hurting the performance. So most of the time it's just a lack of knowledge of what you can do with the, for example, with craft QL or with your caching library, like all the possibilities that you have. And as soon as the people ~like ~heard about what they. Could do or how they could improve it. They were really happy to integrate it. Yeah. So most of the time Okay. Gotcha. when you hear about it, like the first time and then you know how to do it, it's not that difficult to do it. It's just important to understand what you can actually do and what could happen if you like, don't do some of the things. Now like I mentioned, some of the specifics that we're going to be getting into relate to GraphQL as an example. It has a caching layer built in. It's widely used in the industry. We actually had a podcast a few weeks ago where we had a show about how GraphQL sometimes maybe isn't used in the right places. And the person who you were talking to was talking [00:04:00] about how it really is a data layer a lot of times, and you'll find it at these big companies because it solves. problems of scale. So when you're working with GraphQL yourself, Yonas, and looking at these anti patterns, do you find that they're cropping up indeed in that domain of like large scale users using GraphQL? Or is it all across the spectrum? ~Or is it ~Maybe on the contrary, all these anti patterns are emerging more where GraphQL is used and maybe a place where it isn't as strongly suited. Maybe it's being used in a smaller company where it wasn't as appropriate, and then it leads to anti patterns. Are there any patterns in the use cases that lead to the anti patterns you observe? To be honest, so that the companies I mostly work with are mostly quite small startups and they decided to work with GraphQL before I joined the company. So I wasn't really like deciding on if it's a good idea to work with GraphQL. To be honest, most of the times in the small companies, I think it's an overkill to use it because it also gives you a lot of [00:05:00] complexity and things that you can do wrong. And then you don't get like the big advantages of GraphQL. So in the cases I joined companies. We just, ~I don't know, ~couldn't decide on a,~ like a ~different way of getting our data from the backend. We were stuck with GraphQL. And we just tried to do our best with what we had. So I can't tell you a lot about big companies using GraphQL, more small companies, actually. But still like they also had problems and probably the same as big companies would have. And I think it's interesting that you mentioned that it might be overkill because it's not a dis on GraphQL. It's an incredible technology. It's just we're finding that there's use cases in times and places where it shines brighter than others. So just an interesting tidbit from you, Jonas and the small company domain with the tool ~sorry, what were you going to add something,~ ~Yeah. ~Yeah. I think, most of the time it's craft kill. I think also it's an amazing technology and I really like using it. I guess the last years it was quite ~Really ~popular. And because of that, a lot of companies chose it, especially also smaller companies that thought it's a good idea to use it. And because it was [00:06:00] popular and sounded nice doesn't mean that it's bad to do it, but sometimes it's a good idea to really think about why you want to use GraphQL or not something more simple, something like rest or something else. something that you can like really easily change to that's the one beauty about rest is, yeah I guess it's a double edged sword. It doesn't really matter how you implement it. ~Yeah, this is great. ~I want to lay the stage a little bit about what, what is an anti pattern, what you look for Jonas and a brief history of you and GraphQL just because we're going to hop right into talking about anti patterns through this lens of GraphQL. And a lot of people listening to this podcast, they're web developers, they're CTOs, they're engineers, they've used this tool, they've played with GraphQL. And so if you've touched it ever, even on a demo online, you know that one of the strengths is you can query one field, you can take one thing, ask for that one ID, you can ask for that one integer, whatever it is. And ~that's the. ~That's the beauty of having small bite sized queries. First thing on the list, though, that we're going to talk about is over fetching. Oh my gosh, why are we over fetching [00:07:00] with GraphQL? How did that become an anti pattern when it is the name of the game of the technology? Can you talk to me a little bit about Is overfetching even common? Where do we see it? Why do we see it? Yeah I saw it in a lot of places. I guess it is common, even though it's, when you're using GraphQL, this is the cool thing that you can actually define what you want to get back from your query. And you can specify what fields you want and what fields you don't want. And you can remove them quite easily. It's not that a new API or something has to be built. It can be done straight away in a matter of seconds. Yeah, when we think about overfetching, maybe make sense to like for the users that don't know about what overfetching is, it basically means you're asking for data you're not using in the front end. So asking for too much data you don't really need. And Yeah, it actually happens that people just forget about removing fields in their queries. And then you just have the problem of overfetching because they are asking for the data you don't display in the front [00:08:00] end and it's, it sounds so simple, but it actually happens. How do you address that? Do you have to go through every server client interaction and say, what do we actually need here? Is there a more at scale way to evaluate this drift? So most of the time how I did it is, like in the teams I worked in, we just manually checked pages where we were just asking for too much data and where it seemed very slow. And then we just checked, okay, are we asking for these fields? The query, are we really displaying them in the front end and then remove them? So it wasn't like really a special project process. It was just a manual process of checking like the worst queries we had and then improving them. But in our case, It was combined with a different anti pattern ~that, ~that led to this problem because when you think about the fields in GraphQL, they're easy to spot. Okay. I'm using a field that, that ~I'm~ I'm asking for a field in the query and I'm not using it in the application. This is easy to [00:09:00] spot because when you update something, you can just remove the field if you don't use it anymore. This sounds really easy to do still happens, but what was a case for us for a lot of different companies I've worked in that we were using fragments as well. For anyone that doesn't know what a fragment in GraphQL is, basically I would just call it a variable or an object where you can reuse some of the fields that you in a query. So you don't have to type them again and again, so you don't really repeat yourself But it can be problematic to use fragments because sometimes you use fragments in different queries and then you, I ~don't ~know, in the development process, you notice, okay, I need some more fields in my front end application. So you update your queries, but what people sometimes do is they update the fragments and these fragments are then used in ~like ~different places. ~And. ~Because they are used in different places, some of these places don't even need the [00:10:00] fields and because of using the same fragments with the same fields. We have a problem of overfetching again because yeah the field should have been put in the queries itself and not in the fragment in this case but it still happens and because of that it doesn't work. It sometimes gets a bit messed up and then you have that problem of overfetching. And this was also one of the reasons why we as a team could fix it a bit easier, the problem of overfetching, because we mostly had the problem that we just were sharing fragments for queries. And then we noticed, okay, we shouldn't share all of the fields. When we went through all the fragments, we noticed the most problems. So this is why we didn't have to do like any sophisticated process ~to, ~to find the fields. We just had to go to the fragments and then we found most of the issues. Gotcha, so you're updating some more fields in one fragment, that fragment's using a bunch of queries, now the bunch of queries have extra fields, ~exactly. ~Exactly. Yeah. simple as that. A fragment [00:11:00] is cool because it's like a node. Like it reminds me of a Dom, right? I'm building up the Dom from all these little nodes. Yeah. Going in retroactively and saying, Hey, I'm going to add something to here. Of course it affects the whole tree. So if you're approaching this problem, do you, maybe in this situation, you pushed around the fragments and said, maybe some fields go here, let's rearrange it. But if you were starting on a greenfield project, and you had this database, you had another like API layer, is there any rhyme to the rhythm about how you begin doing the fragments so that you can. Maybe kick that can down the road when you have to redesign or reevaluate how that tree is composed. So you mean like how I would start when creating ~like ~new fragments? Yeah, like from scratch for a greenfield project, a new project because that process of going through how do I draw the lines to my fragments might be different than coming to a preexisting body of work and fixing it. So for me I mostly don't want to use fragments at the beginning, just when I notice, okay, I'm just like writing the same things [00:12:00] again and again. Sometimes you have in one query, different fields that have a sub selection of fields then, and they are always the same. And then this is mostly when I notice, okay, I have to write it like four or five times in the same query, then I start a fragment, but otherwise I'm mostly a bit. Hesitant of using fragments because of the issues we had with them. But what really helped me and my team and not having this issue again, is we beforehand, we had a big problem because we were storing like our fragments in just one big folder. Fragments. graphql. And there we had like hundreds of fragments. And because of that, we didn't really notice when we were updating something that like a lot of queries are actually using that fragment. So what helped me and my team was that we, when we created fragments, that we actually created the fragments in the same file ~as. The, ~as the query, or sometimes we just created a fragment in the component that is actually using this data and then we use that [00:13:00] fragment ~in, ~in a query, in a top level file, for example, the page, and there we put together the whole query, and then we just use the fragments from the components itself, and by doing that, having the data that Having the queries nearby the components, it was easier for us to really update the data straight away and don't forget about it. So this helped us a lot by like how we fix the problem of over fetching it's just putting the fragment files in the component files. I hope this answered your question. Yeah, it does. So you're physically relating the specificity of that fragment by co locating it in the right. So your brain's paying attention to, Hey, this. It was made for this, even though you might be reusing it in other places. Yeah, exactly. ~Thank you for sharing about ~do you like to start? With almost no fragments at all, because it's very pedantic and you understand the relationship between your data. I really love learning about how experts like yourself ~do ~process because approaching a problem is, arguably more [00:14:00] important than your end solution because you could take 10 years to get there. Getting there efficiently is very important. So don't use fragments. Maybe when you start out helps you organize your data mentally a little bit. Everybody's different, but I love that suggestion. Yeah, it's a personal preference, so no one has to do it like that. It's just something ~I, ~I do because probably because of the history of the problems we had performance and the anti patterns we learned about. Maybe other people would do it differently and maybe my solution is not the best approach, but for me, it works quite well. Now we're going to hop into the opposite side of overfetching, which opposite of over is under. So we're going to talk about underfetching. Before we do that, though, I want to remind our listeners that this podcast is brought to you by LogRocket. So if you're building a web application, no matter how big or how small, you can use GraphQL or not. If you want to pay more attention to what your users are doing, get things like session replay, Heat maps and have AI service issues that you might not have noticed before. You can go to log rocket. com today and check out their software for free. So you can [00:15:00] find and solve issues faster and spend more time coding. And less time in your debug console. So yeah, moving on Jonas, we talked about overfetching. Let's talk about under fetching. So under fetching, my understanding, you're just not fetching enough data. Would you add anything to that? Yeah, exactly. Yeah, exactly. OK. Yeah, you're not fetching enough data. And because of that, you have to do ~like ~additional queries. And this can be multiple queries depending on ~like ~how bad your situation is. So instead of doing one request, you have to do ~like ~hundreds or thousands of requests and your backend won't be that happy. Is under fetching like more of an issue with a GraphQL based setup than it would be with a REST based API? Or is it a, Oh, it is. Okay. What, why is that the case? I think, in our case, it was ~more, ~more like that because I think when you're working with REST, you think about ~more like ~how you want to structure ~your~ your end point and how you want to use it. And you communicate together a little bit. And the good thing about GraphQL is that you are independent from each other and you just get all the [00:16:00] possibilities in the front end to ask for the data, however you want. And because of that, sometimes it's a problem if people don't know what GraphQL can actually do that you can use like filtering, sorting, pagination to really optimize your query. And that you don't have to do like multiple queries. And because of the lack of knowledge, sometimes people, ~yeah, ~have the problem of under fetching because they just don't know how else they could get the data, at least that's what I experienced. Yeah. maybe I'm missing a page. I should have fetched two pages. You're saying, Oh, I'm doing 10, 000 queries, my brain goes to, Oh my gosh, is there like a loop that ~they like ~they could have done in one query and it's 10, 000 fold. larger, like what is the scale of under fetching that we're talking about? And maybe what's an example of something that you've seen? I just want to materialize like what the before and after could have been. ~Yeah. ~Yeah. We can [00:17:00] think about, I guess the GitHub API, everyone knows about ~like ~how GitHub is structured. You have like repositories, each repository has some issues, maybe that people are working on and like every issue or like most of the issues have someone that is working on it. So like an assigned user and an example for like under fetching would be, We want to get like all the issues of one repository. And we just want to display in our front end only the issues that already have someone that is working on one of the issues. And maybe we are new to GraphQL and we ~don't know, ~didn't know that we can like filter on a query. And how people that don't have the knowledge would do it as they would just have, they would get like all the issues of a repository. And then they would also in that query get the assignee ~of an ~of an issue. And what they would do afterwards, or some people would do is they would just filter over just in JavaScript or whatever, like you're using in our case, it was react. So we would filter over the [00:18:00] query. We would filter out all the issues that don't have someone working on it. So no assigned user. And what then happens, we would map over ~the~ these issues. So just for example, the issue ID and we would. Pass the issue ID in like we map over them and pass the ID in each of the components. And then in each of the components, there was an additional query that would get all the important information about an issue. So as you can imagine, so first we had one query or we get like all the issues of GitHub repository GitHub repository. Then we say, for example, we get back. 100 issues, some repositories have more, but let's say 100 issues. Then we would filter all the ones out that don't have an assignee. So in the end, we would have say 50 issues left that they actually have an assignee. And then for each of these issues, we pass the ID to a component and make an additional query. So in the [00:19:00] end we have 50 and one queries. And. In some of my teams, we had some more problems because we were like asking for 200 or 300 rows of data and then didn't have a filter or something. So pass that in a query. So we had 301 queries. And the thing is, you can improve that quite easily because You can just use filter by a filter statement from graph QL and would say, okay, I just want to get all the issues that have an assignee, get the, all the information you need straight away. So you would just have one query instead of, yeah, 51 queries. So this is it's really easy to fix, but if you don't know that you have the possibilities to do that You think this is the only way you can do it. And you make it for yourself quite difficult as well, because if you don't filter it in the query itself and filter it in your code, you add a lot of complexity in your code. In this case, okay, it's just a filter statement and then a map, but then you have another query [00:20:00] in the component itself. So you have 15 to 20 lines more of code that you have to maintain. And then. Yeah. It also, it's not good to have 51 queries instead of, I think we can agree on that. Yeah. So this is how it happens. And that's, this is how the scale of that is in this case, 50 more queries than you normally have. But in other cases you could even have 200, 300 more queries. So it's like we overfetched at first because we got data we didn't need. And then even though it's a small amount comparatively, and then after that, we resulted in under fetching, because now you need to do 50 more queries on each one of those Yeah, exactly. And this is what happened to us. For someone ~like ~who's listening to that probably thinks, okay how can that even happen? But it happens easily if you don't know that you're able to do that because you just then, you're then a deaf and you think, okay, how can I fix ~this?~ This problem? I just know my tools and then this is how people are going to do them. But as soon as ~they, ~they know that they [00:21:00] can use filtering. Really easy for them and they don't have that problem anymore. is it, does it work the same way if you're getting data from a post request, if you did a mutation on the GraphQL server, do you have access to all of these like filterings and sorting and pagination to look at code that already exists and work with it in a better way rather than ending up with 51 queries? To be honest, I don't know in this case, I never used ~a ~a filter on a mutation. I'm not sure if it's possible. Maybe it is, maybe it's not. I'm just not sure. I never used it to be honest. Possible, but I don't know. Sorry for that. We, ~others ~have to look it up. Like return values from mutations in general are those you find taken at ~just like ~face value. On the queries and there's not a lot of challenges or design architectural considerations around those resolvers, the mutation resolvers. ~yeah. Sorry. ~Yeah. Maybe got that wrong. ~Yeah. ~For, for multiple values, I don't know what is coming back, but from single values, that's really cool because in GraphQL, it's the same mutations as it is [00:22:00] in queries. You can. Define what fields you want to get back. And~ yeah, ~this is also a problem we had in one of my teams is that we didn't really use these values. So we just got something back. We just returned the ID of the data we updated. And what we then did is we just refetch the data, ~but. ~This is maybe not so clever because you can define what you want to get back from a mutation. And then you use this data and just, I don't know, set it ~in your ~in your cache. If you're using a caching library like a polygraph QL or something similar. This is, ~yeah, Quite, ~quite useful to do because how we did it before is, we typed in data and then we send a mutation ~to, ~to the server and we get back a simple response just ~to~ to see, okay, it was successful. And then what we did is we just refetch the data. In the end, we have two requests and two responses, but if you use the return values of the mutation, it gets way better because then you don't have to do an additional request and response. You just have to do it [00:23:00] once and you get back all the data you want. And after a while, we even found out like better patterns to do okay, first we can improve it by not making additional requests and response by using the return values of imitation. But then we found out, okay, we can also do like optimistic updates. So basically as soon as the user types in the data and we validated it in the front end and think it's quite likely that the data works like that, we set the data in our cache straight away in the front end application and don't wait for the response of the server and. By doing that, the application just looks blazingly fast because you get the updates straight away instead of waiting for the server response. But by doing that, you also have to consider like some edge cases. One of them would be, okay, ~the ~the mutation fails. So the server is not happy with the data you send to the server. What you then have to do is you have to set back the data to the state you had beforehand. This is, for example, in Apollo GraphQL, it's quite easy because you have to state [00:24:00] the previous state and you can just reset that to that one on an arrow and there's another edge case you have to handle. So if the data is different to the data, if the data that you set In your optimistic update is different to the response of the server. You have to overwrite your data with the data of the response from the server. But this should normally not happen. If that happens quite often, you're doing something wrong and should check if the data you're setting in your optimistic update is somehow wrong. So these are the edge cases you then have to handle, but they are quite easy to handle, and then the application is even faster for the user, not even faster. It feels faster for the user, but this is a big thing. And in the end, we just want that our users are happy and by using optimistic updates, it feels really fast. And yeah, using return values of mutations is like the basics you should do. Is the optimistic [00:25:00] update the same thing as what we would call a normalized cache? Ah, no, not really. So this would be something different, which is quite cool as well. Sadly, this is something ~we.~ We couldn't use in our project because we decided to go with react query as a caching library. And react query is an amazing library. I think everyone can agree on that one, but for GraphQL, I would not recommend to use it because react query ~is.~ supports GraphQL, but it doesn't support normalized caching in GraphQL. And what normalized caching GraphQL is basically how data is stored in your caching library. So going back to the example I gave before regarding GitHub. So you have Repository and repository has issues and each of the issues ~have, ~has an offer working on that issue or someone that is assigned to that issue. And you normally have a lot of issues and these issues, sometimes like offers have [00:26:00] several issues and it doesn't really make sense to save the offer information multiple times. The author has 10 issues. So what you then would do is you would normalize the data and how this works is you don't really save the author with the issue itself, like in the same object. I would say you just save a reference to the data. So you would just. Like how the reference is normally made is you would have the type name of the data that you come, that comes back. For example, author has type name user in GitHub, and you would then also have an ID and this is how the connection would be made. So instead of having the author data in the issue data, you would have the reference to the user and the ID, for example, five, I don't know. Because by doing that you don't have to store so much data, but what is also really cool is when [00:27:00] you have multiple issues or multiple places where this data is used, and then you get an, I don't know, you're updating some data and ~one of the Offers in ~one of the queries is updated. And the cool thing is when this one offers update, because all of the data points just have a reference to that. Each data point that has this reference gets the data update for free by having that reference. Very, maybe for some people that, that are used to relational databases, it's the same way they are, right? You have you have a relation. So for example, if you have a blog post, you would store like the title of a blog post, you would store the body of a blog post, and you also have to offer. And normally you wouldn't save like the offer data in the same table, in the same row, but you would just have a reference to an offer table. And because of that you~ yeah, ~improve your data structure. ~I ~have to store less data and you basically do the same in a caching library in GraphQL. And this gives you like free performance updates, ~free Yeah. ~Free updated data [00:28:00] by, yeah, just using that feature. And this is why I would say I would not use react query in graph QL again. I would prefer using Apollo client or your QL or something completely similar. I don't know, but I wouldn't recommend using craft rec query for craft QL. I find that fascinating too, because you could write the JavaScript to reference that value. And as you're mentioning you and it's that will update. So I don't have to look into that separate structure somewhere and say, Hey, like check if this changed or it just, it's there. And it's on the query side, it's on the client side. When this data comes back and so the resolve or the GraphQL server does this all server side right with the de duping and the and the normalization of these cache values. Or is that done in Apollo client when it comes back? So to be honest, I don't know how it is done on a technical side. I just know like how to use it. But I guess in this case, it's probably done in Apollo client side, like on the. Yeah, the caching library itself, because otherwise probably React Query would support it. But I'm not sure [00:29:00] about that. I'm not sure what the reason is, why they don't support it. Maybe they, after hearing that they are happy to fix that, but I guess not. They're more focused, on REST, RPS or TRPC or something. This is great. I feel like ~we, ~we talked about four heavy hitting things. We talked about over fetching, under fetching, optimistic updates and normalizing your cache. All things that like you've been saying, it's a belong, it can belong in any app. It's things that maybe people hear us talking about and go why wasn't it in there in the first place? And ~it's ~there's a knowledge barrier. There's an experience element to all of this. So if people are listening to this, they've absorbed information about under fetching, over fetching. We talked about fragments, optimistic updates, normalizing your cache, and they want to step forward with trying to implement this stuff. Assuming that listener probably already has an existing GraphQL app or, they're still new to GraphQL and they want to go make a new one. What are some ways that people can start to practice this, [00:30:00] the more efficient dance between client and server? Would you suggest that they go read some other apps that implement this? Are there any favorite examples you have out there? Or are there any other resources that you would recommend to people? Yeah, I think there's one of the maintainers of craft QL has really cool examples. I think his name is Dominic or something, TK something on Twitter. I think he, he has some cool examples and also on the req query docu I saw some examples, but. Even better documentation is from Apollo client. Not my opinion. You can check out some of the articles they wrote. This is really recommended, but most of the time it's just about trying out and just trying the differences, what works for you in the end. And especially if you have an existing. Project. It's difficult to change everything. But what I would like, the first thing I would check out is what's caching library am I using? Am I still able to switch the caching library or am I too invested in it? Because sadly, this was the case for us. We couldn't [00:31:00] switch the caching library anymore. It would have been too much work. So we stayed with React Query. But other than that I would focus also on the structure of my application. So in my opinion, so like how I structure applications is mostly feature based. So I try to have like several features of the application in a feature folder and also like the queries. And the fragments and the mutation are also in the feature folder itself. So I just try to co locate everything together that kind of, yeah, is used together. So I don't forget about something. This really helped me and my team to avoid some of the anti patterns. And very simple things. It's just always like updating. The, yeah, your queries, when you update your front end application. This is something it's just good practice to do. And also it's important to check in your code reviews that the person you reviewed the code from did exactly that. [00:32:00] Yeah. And it's just a good idea to ~just ~read the documentation of. GraphQL, maybe a little bit of your caching library. And I think then, about most of the features. All the examples of anti patterns I just gave you are not that difficult. Yeah, they're not crazy. yeah, they seem so simple and this is what they actually are. They are quite simple, but if you don't know about them, it's just so easy to make them, so just important to get the knowledge, It's funny because on my like little sticky of show notes here We have you know, how can people? Not do the things we talked about how can they avoid anti patterns and the long short is Jonas tells you to do your homework Go read the docs. Yeah learn about some of the details about how we can filter sort and Avoid under fetching over fetching and take advantage of the caching stuff. We talked about Jonas if people wanted to hear more from you specifically Do you have a Twitter or a Mastodon or anything where you Yeah, currently I only write on [00:33:00] LinkedIn, to be honest, I just started, I just, yeah, it's a bit embarrassing, but I just started using Twitter and I'm just following people and just getting the knowledge, not sharing anything there currently. But yeah, if they want, just add me on LinkedIn, follow me there and I'm just sometimes posting some blog posts or some, yeah, good information I got from someone else or something I just found out. Yeah. And ~yeah, ~if someone has questions regarding GraphQL or some, about the anti patterns and also how we fix them, or if they need help, yeah, just reach out. I'm always happy to help. Awesome. Jonas, thank you again for your time. It's definitely been illuminating to learn about some of these basic low hanging fruits that can really change your app. So thanks again for coming on. Thank you, Paul.