Apollo + React Hooks + TypeScript = 🥰 by: James Reggio, Web Platform Lead, Convoy

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments

i particularly like the graphql codegen workflow shown in the middle and would love to put it into practice. wonder if /u/stolinski has a vid that covers this, i’m quite behind in my tutorial watching

👍︎︎ 3 👤︎︎ u/swyx 📅︎︎ Jul 19 2019 🗫︎ replies
Captions
again my name is James Reggio I'm the tech lead on the web platform team at convoy I really appreciate the apology m-- inviting me to speak here today they've been a great partner to us convoy was a company that was founded right around the time that graph QL was announced on the scene so we've actually been able to embrace graft you all from the start specifically Apollo and grow with them as you can also probably see from the title of my talk I'm gonna be taking us back to the front end I saw earlier from a show of hands that maybe 20% of the people here have worked with hooks but would you give me another show of hands if you've ever worked with Apollo and react on the front end great ok so that looks more like 50% of of y'all have worked in the front end what I'm gonna be doing with this talk is I'm gonna try to tell a story using some practical examples of code that I pulled from our apps about the way that we evolved the way that we write graph QL for the client at Conway there's been sort of three distinct patterns that we've embraced and they've always been sort of the best practices at the time but the you know that the transition from each has to sort of be motivated in order to justify the refactoring work involved so I'm going to explain with some code samples how we made those decisions and what benefits we witnessed before I get into that let me just tell you a word or two about convoy convoy is a Seattle area tech startup founded four years ago we are basically out to revolutionize the trucking industry in the United States and the best way to think about what we do is that we provide a marketplace for truckers and carriers there sorry for shippers and carriers to connect so on one side of that marketplace we have hundreds of enterprise businesses they tend to be pretty large like Niagara or Unilever or anheuser-busch and then on the other side of the marketplace we have tens of thousands of small business owners who actually own the trucks and move the cargo we build the marketplace and we we focused particularly on reducing waste in the trucking industry most people are pretty familiar with the fact that like every single package good that we consume here in the United States gets to them by a truck and that trucking is really important to the US economy but the thing that a lot of people don't know is how wasteful it is according to recent estimates almost 40% of trucks on the road are running empty with no cargo in the back and that waste is terrible for the environment it's also terrible for our economy because it drives up the cost of consumer goods and it means that people aren't making as much money as they could be so we're focused on reducing that level of waste to speak more about the technology at convoy we actually just this week surpassed the hundred engineer mark and as I said earlier we started the company about four years ago and we at that time decided to embrace the JavaScript and typescript ecosystem so our entire stack is some amount of JavaScript or typescript when we've been converting more and more towards typescript over time the the let's see so we have about a half dozen apps out in the wild their mixture of react and react native and we also have a roughly 20 to 25 services in our service-oriented back-end so we're growing fairly quickly there were 30 engineers just a year ago so you can imagine that we need to think about how we scale our practices and I said a moment ago that we were early adopters of graph QL what was great about the timing was that we basically chose to embrace Apollo right when it was released and we chose it because it had both the client and a server offering we chose it because it offered more flexibility than what Facebook had to offer with relay and we chose it because the team behind Apollo was incredibly transparent about the roadmap the shortcomings and what what they intended to do with the product we have no regrets about it but as most people know JavaScript moves really quickly and I would contend that client JavaScript moves even faster than the rest of the ecosystem in general so every three months it felt like there was something new showing up some new shiny way to write a client JavaScript to connect the graph QL database to or the graph QL API to our front-end over the past three years we've seen a huge number of Apollo client features released we've seen major evolution in tooling which we heard about earlier today we've also had like evolution and so industry best practices and just last November the react team kind of turned the whole world on its head and introduced react hooks so we're a business even though we're still fairly small like any large company and we need to be able to justify the changes that we make to our development model and so on the web platform team we tend to think a lot about whether the the features that are have been released to the market that we could consider adopting are going to increase the robustness or the ergonomics of the development experience we want to see like a major step change function in both before we choose to adopt and just to clarify what I mean by that with robustness I'm speaking of like general correctness and the facilities and the code to make sure that you're not writing and introducing bugs and an ergonomic speaks to just is it fun to write code in this environment so we do pay attention to both of those I'm what I'm going to do is we're going to hop over to code editor and we're going to take a look at three distinct phases of a component as we sort of began as we would have written it back in 2016 and then sort of as we began to move into some of the technologies that were available last year and then finally what it would look like today and our code bases we begin to embrace hooks my hope with this is not necessarily to explain how all of the older technologies work if you've encountered them then you've probably some of the pain points will may resonate with you but lecture the older technologies were deprecated because they're difficult to understand and explain so I'm not going to spend too much time on that instead what I'm hoping you'll gain from this is you know maybe maybe you'll see where your company is or you'll see like the code base that you're working and represented in here and what you'll see is some of the benefits that may may occur should you migrate forward because we always want to be justifying it with very specific value propositions so I'm gonna move over to my editor now hopefully I'll have a better better luck presenting with these color scheme how does that look and everybody read that all right thank you so let's why in the clock clock back to 2016 in 2016 just as Danielle said there was a like a huge there was massive adoption of redux for managing client state and react was was popular it was solid at that point and everybody was basically refactoring the code base to use this concept called higher-order components higher-order components are this nice encapsulation technique that maps to how react handles api's at the component level the idea was basically that you'd separate a concern out of your components maybe it would be local state management or global state management or API API data fetching and you put it in another component that injects that data into your component it's this nice approach to encapsulation but it had a lot of rough edges so what I'm going to do is I'm going to walk you through sort of a mock component that you could have seen in one of our apps and we're gonna see how this component evolved first from with using Hawkes onward to to to other iterations so if we look at the left pane we're gonna see this shipment details page and there's a lot of things in here that actually look exactly like they did in Danielle's talk you'll see that we're having some props passed in that contain the results of a query down here we're also grabbing some functions out of the props that we're going to pass onward and these functions actually map to mutations we have that common boilerplate in the middle which is like common to every single iteration of this component which is that we have to handle all these sort of edge cases around errors loading States and maybe some business logic errors around like a shipment not being found and then ultimately we go and we render some other child components in this case we have a shipper summary a carrier summary and a little stops editor that would allow us to visualize and aggregate stops to to the shipment this is fairly standard reactants I will say that like this was a major step forward not having to worry about data logic and any kind of fetching logic in this component was it was a huge step forward from the past where you'd usually use some kind of lifecycle method like component did mount to make a fetch to some REST API and then parse it and store it in the state like we're not doing that anymore and that encapsulation was a major win let me show you now though how the the fetching does occur as I scroll down here we're going to see a bunch of the higher-order components each higher-order component here is represented with a call to this graph QL method this was basically the way the only way to bind to a graph QL API when Apollo client was launched back in 2016 it was modeled after what Redux was doing with the connect higher-order component you'll see that we have one in here that that defines a query and then we have these two others that are injecting some mutations into our component it seems pretty reasonable at first glance but there are some really pointy bits about this that would oftentimes lead to a good half an hour to half a day of debugging to try to figure out what went wrong the first thing about it is that these higher-order components don't naturally layer on to one another they all define props and they pass through the props that they receive and then add some more but if you have multiple mutation higher-order components for instance you might actually find that one of them is going to override the other unless you give it a unique name this is something that actually like led to I've lost plenty of time to trying to debug this especially when the higher-order components themselves are defined in another file it's very easy to layer on a couple and then realize that you're not getting all the information you expect another problem with them is that it's really really difficult to type them when we began we did consider using typescript but there wasn't much value to it because it was so difficult to express typings for higher-order components even the tools that will do code gen nowadays don't really give 100% accurate types so you don't have any ability to statically verify say that you're getting all the props that you expect or that that you're not doing something illegal or or error-prone one of the other things that is unfortunate about this kind of in the category but not necessarily a showstopper is that when we when we want to specify values for the variables to these queries and mutations we reach into the props but we do it here way down on the page like outside of the component itself you typically think about props right alongside the ponent and when you think about refactoring props he'll usually do it right here in the component but it's really easy then to forget that hey I need to come down here and change the usage of the props again this is exacerbated when you factor these out to other files so that's that's less than ideal there's one other thing that is unfortunate about higher-order components which is that if you wash up the the reactive bugger you're gonna see that each one of them actually inserts a component into the visual hierarchy and so when you look at your debugger in a graph QL app oftentimes you'll see more sort of more higher-order components than you'll see visual components and that's just more or less a nuisance there's nothing really painful about that except for when you start using this in react native we have a react native app and obviously react native runs on mobile phones but one of the things about running react native is that you actually are using a like let's say there's kind of an it's a kneecapped form of the the the JavaScript runtime it's not able to jet compile your code so there's a lot of there's a whole class of performance benefits that you're not able to enjoy when you're running react native code and we actually did see that this increased component hierarchy depth would lead to performance degradation and our app so it was something that was actually a little problematic and we spent time trying to reduce the number of queries we use and like make more complex mutations and things to work around that which isn't really how you want to think about it because then we start breaking the encapsulation there's one positive thing I forgot to cover right up front so I'm gonna I'm gonna backtrack for a second and speak to that before we move on and see how we can actually improve upon the bad and the myth and that is that we embrace this concept called component local fragments which is something that we borrowed from relay relay is Facebook's graph QL client API and like I said earlier we decided not to embrace it because it wasn't part of a broader ecosystem and it was too inflexible for the use cases that we envisioned but one of the things that it did well was that it encouraged you to break up your queries and put little fragments of your queries alongside the components that use the data so what that looks like in practice here is if I go into the carrier summary component let's see what I mean the curious summary component has a very uninteresting render method it just takes the carrier and it renders the name and the rating but what I want to show you here is that we're also attaching this graph to elf fragment to the carrier summary component that specifies precisely what fields were expecting on the carrier type this is the fragment is like the the most basic form of reusability within graph QL and the idea of co-locating it with the UI that depends on that data is something that is very powerful because it gives developers confidence that they're going to get the data that they asked for and when they're refactoring it makes them confident that they can remove a field the latter is really important because I'll say that I've worked in code bases where all the fragments queries and you tations are basically in one central file you might have something like a shipment summary and then full shipment fragments or something along those lines those things tend to become append-only and over time you end up with something that approximates the rest api because developers tend to feel very uncomfortable removing something that might feel that might have an impact on some other bit of the UI so we did embrace this approach to co-locating the data dependencies with alongside where they're used and the only downside to that is that they're a little bit error-prone speaks to the selection sets being error-prone we have a little bit of a problem where we if we were to remove rating right here there's nothing that would prevent us from using it in the response and that's where like typescript is going to come in and really save us so this is what things look like this was the state of the art in 2016 I would say that we were on all the best practices at the time and in that we definitely were able to find great productivity with this approach but there was a lot that left that could have been improved most notably we really wanted to get on the typescript so as the as the years went by and our code bases became more complex and we were constantly re-evaluating whether it was time to maybe migrate forward and find another approach two things happened the first is that the react community started to frown upon higher order components they're really difficult to understand it's very like the you know the ergonomics of this are not great and when you look under the hood at what's going on here it becomes even more confusing so there was a move towards making these a little bit more explicit and moving them directly into the render method and that concept was called render prop components so that happened and another thing that happens simultaneous to that is that code generation for typescript became a little bit more mature I'm gonna swipe right here and take us over to what that looks like in 2018 you'll see the same component the shipment details page but now we have all of instead of having all the higher-order components at the very bottom they've all been hoisted up into the the render method that component itself and I think that like what you probably just saw is that we're now back in callback hell right like if you've ever developed for node before promises were a thing this should look familiar you basically have all these little function calls that eventually take a callback that takes a function that takes a callback text function now we're eight layers deep before we're doing any useful logic it's definitely a pain point although it's not necessarily like a functional problem this approach did solve a number of different things the most important thing that it did was it solved the problem around typing these query and mutation components are much easier to type and there's a tool that we used called a graphical code generator that actually generated them for us so I'm going to show you that real quick just because I think it's kind of interesting the this isn't the same I'll say this this isn't the same code generator that the Apollo team released they released the the code generator a little bit after this and we had already sort of gotten comfortable with this one and in the templates and the type formats that it provides but the one that Apollo provides is just as good so I'd say you should definitely check that out but I'll say that like what's what's simple about the code generator is all you have to do is just point it for both of the code generator just pointed at your schema you pointed out where all of all of your graph you all documents are which is to say like every type script file check it for check it for fragments queries mutations and then you say we want the the typescript package with react Apollo integration and what that would do for us is it generates generates this big file that has all of the different types from our API represented here what's nice is that that's all type information so it's gonna get compiled out and it won't won't blow at your ultimate bundle size but this is really nice because we can start having type safety around around the queries and also around like the variables that we pass into them and one of the neat things about it is it solves this problem around around checking that the fragment for a given component agrees with what we're using so I'm gonna do actually is I'm going to comment out rating and save and you'll see down here that this watcher is going to regenerate the types and then we get the red squiggly on carrier because rating is no longer on the carrier summary fragment this was extremely powerful it enabled us to begin to introduce typescript without having to go and model and duplicate a bunch of types in our API and this was extremely valuable development one of the other things that it did for us is that our that the code generator does for use it generates typed components for every operation so this shipment details component actually has the shipment details query in it similarly this mutation this mutation so now we all have we have all of this inside the render function the overhead of understanding higher-order components is gone the only bad thing about it is that we have this nasty like callback hell and the component hierarchy remain remains extra deep there's also this nuisance around all this common code for managing the edge cases but we weren't able to improve upon that in that iteration we can fast forward now though because this was in mid 2018 at the end of 2018 in November of last year the react team announced hooks which was what they were actually inspired by the the migration towards these callback components or these rendered prop components somebody had built a babel plugin that would flatten this out for you and do a syntax transform that would turn these into function calls and in simple little imperative functions and that the team said well we don't really want to use a syntax transform for that that's not robust enough but maybe we can figure out a development model that brings forth the same kind of ergonomics so that's how hooks were born I'm going to show you now what that component looks like any using hooks you can see that everything is sort of moved back to the left the left gutter we're only one level of indentation you can also see that instead of having those those individual components for each operation we now just have some simple function calls and these function calls were were generated by the same code generator that we're using earlier that graph GL code generator so there are automatically going to have all the typing information you want so if I start typing you know shipment here it's going to have carrier ship shipper stops the fragments that we specified we have all this nice type of safety and you know everything's nullable which is kind of a pain to deal with but at least as daniel said you're aware of the fact that you need to do that null checking one of the other nice things about this is that there was another concept that was introduced to react that allowed us and it allowed us to remove some of that boilerplate error handling you know something called air boundaries the the concept of an error boundary is that you can put a component in your visual hierarchy that will catch errors that are thrown or exceptions that are thrown from any child component and then perform some kind of behavior like render an error message so we took advantage of that as we begin to migrate towards hooks and the way that that looks I'll show you I'll walk you through how that works if you look at our app this might be like where the router would be if we had a router we added a component here called error boundary that just sort of wraps the page that were rendering inside the air boundary it's a really simple little feature called there's a little simple static method that you can add that's called get derived State from error it basically will catch any error that was thrown by any child component and allow you to set some state so what we do here is we just take the error we set some state and then if we have an error we render something different it's really simple and obviously like what we do in our apps is more sophisticated we look at the source of the error we look whether it's transient like a network failure or maybe more like a 500 and render different things but that enabled us to eliminate one of those conditionals from this list we don't have to think about error handling in here anymore and the way that we're able to do that in the query itself is that we override it the way that the use query hook or so with hooks it's a lot easier too it's a lot easier to extend them and build meta hooks and and add some like your sent some of your own business logic to them all you really have to do is override the built in one and then modify the behavior as you see fit and return the same result so we were just looking for an error from the API and if we have when we throw it it's really really simple there's just like one little thing you have to do and the code generator config to say hey import my custom used query as opposed to the one from the client library so what's really nice about this and now we're going to stop in a place where all of the bad things that we had identified from 2016 have been addressed and the only thing that we haven't really been able to address is that the loading state the loading state requires a bit of boilerplate what's interesting about that is that the react team already has something for that it's called suspense it's something that I haven't released quite yet so I'm not recommending you use it obviously and there's a lot of problems with it I see somebody shaking their head haven't released it it's definitely not robust but there's some something about this development model that is really interesting and I suspect that we'll have something akin to this at some point at some point this year or everybody sort of suspects that we'll see the idea though is that similar to the error boundaries all we have to do is go to our app and add a different component that says hey anything that suspends beneath here should render some fallback UI the only thing this is used for right now is actually for lazy component loading but you could see how it might be usable for fetching the data for a given page and what i'm doing here is is importing that and rendering the loading indicator if if we're suspended so the final final shape of this component ultimately looks like this where we have a couple of operations here from Apollo we're able to thread our props directly in using just some imperative function indications there's no crazy like composition of higher-order components there's no really deeply nested hierarchy of components here like this all reads very nicely and what's nice about that is it means the frameworks getting more and more out of our way as we progress there's less a like Karen feeding of the framework involved and developers with this level of clarity can focus more on the business logic that is like the essence of what we're trying to build I'm going to go back to my slide deck here and just say that we don't know what else is coming in the future maybe suspense right but what this is showing hopefully is that there's been a clear and consistent drumbeat of innovation on the front end both around urban economics and just like making it easier to write the code as well as around making it less error-prone to write client code attaches to a graph QL API convoy continues to want to we continue to try to innovate ourselves we've built certain things for a graph GL like our own client cache and we do have some additional little bits of tooling here and there but I'll say that every time we we build something ourselves the Apollo team comes around and build something even better like six months later so it's been a really good ecosystem to be a member of and the I think that's sort of all I have for you today [Applause]
Info
Channel: Apollo GraphQL
Views: 9,245
Rating: undefined out of 5
Keywords:
Id: IxmrRiA9Gso
Channel Id: undefined
Length: 25min 36sec (1536 seconds)
Published: Fri Jul 19 2019
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.