Web3 Frontend Pitfalls - @grod220 at @ETHDubaiConf

ETHDubai 2022 · 31 Mar 2022 · 16:30

Gabe Rodriguez examines maintainability problems in Web3 frontends, from TypeScript strictness to wallet state coupled to React hooks. He advocates separating business logic from components, exposing framework-agnostic wallet stores, and using caching, backend services and URL state to reduce client-side complexity.

Speakers

Topics

From ETHDubai 2022, hosted by DeFi Dubai.

Transcript

howdy folks yup my name is gabe i'm at one of the core devs at sushi doing all things front end so for those of you who are developers here this is going to be more of a kind of technical talk so if you like things like relative react state management react hooks and the pain associated with it this talk is for you i have a theory depending on when you created your web app the distance from when defy summer began determines how happy you are with the app if you're me and you're working on one of the og protocols our web apps are quite painful and here's the ultimate question i'm trying to get out of here how do we make our web 3 apps more

sustainable how do we make it so that when we're creating apps they have longevity to them the developers want to work on them for long periods of time and this is what this talk is essentially going to be about kind of a quick aside in the ethereum world we're really obsessed with client diversity right but us front end devs when we go to uh grab a framework for web3 app uh what do we grab for right react right and not just react we're probably using next gs probably not just next yes we're probably deploying diversal huge diversity here actually i wanted to verify that in some extent so i went through the top protocols and defy lama down to the top hundred and yes indeed 84 percent of us are using react apps now we could probably go

through the implications of what that means is that there's not a lot of diversity with our web apps however for the most part you can rest assured if you're a front-end dev in this space you are experiencing pain in the same way that many of us are kind of as aside i actually sent these apps to the build with api and there's not a ton of diversity as it relates to hosting and even worse when it comes to dns all right let's get back you're starting a web3 app for the very first time and i have a theory which is the destiny of your web app is highly determined by the conditions and the defaults that you set as you actually first bootstrap it a lot of us are using what clies right to

bootstrap our next.js app we're adding some typescript to it if you're developing without typescript nowadays you're probably doing something extremely reckless however read the fine prints please in your boilerplate code typescript strict mode is very often off by default typescript strict mode if you're not familiar with this this is a whole collection of rules that basically make typescript typescript and the fact that this can't even be off sounds me but this one specifically strict null checks is one that you really really need uh to have uh here's an example we have an interface dog it's got a method bark we're instantiating it and we're calling bark

should this compile any thoughts you know without typescript strict mode it will happily uh compile uh with strict mode of course it should blow up because this should be possibly undefined please set very strict defaults the strictest of strict defaults as it comes to your web3 apps this is a riveting talk i got one like uh on this you could be the second please when you're bootstrapping your web3x for the first time use the strictest of defaults this will come to bite you if you don't it's very simple go to your ts config add in true when i first joined sushi i did this and boom the whole thing uh somewhat

exploded 1500 type errors in our main app these are 1 500 runtime errors bugs how do we fix this yeah well we can go one by one right through each one of these spent an entire engineering month to fix this or we could do kind of what we did go through and spend an entire day commenting out the code with something obnoxious that says please please fix this to get our app to compile at the very least this ensures from that moment on these hype errors won't creep in please get some strict defaults all right for the rest of this talk it's going to be gabe's rants on why he hates hooks

we'll get this however let's go back in time to the mvc world has anyone even know what that means anywhere has anyone even worked on a django or php app in here okay someone knows what that is right so the back end was this like atomic unit right the unit of which all of the business logic in our app was contained right and it did things like call back ends call the database and then you have the view layer right this very thin layer that's only job was to collect data from the back end and display it now in the web 3 world we have our back end smart contracts why wouldn't we why would we need anything more than this and we have what we would

call a small small uh web app view layer right it should be only responsible for clearing the blockchain sending transactions rights requests it shouldn't be big should it should it my god our web apps in this industry are colossal monsters they're single page client bloated nightmares let's be honest we're not in uh the best of state now what are we trying to do when we're creating a web3 app yeah we're trying to query the blockchain we're using some of these libraries we're using some of these providers these web wallets we want to authenticate transactions by sending authenticated requests to the blockchain and we have these helper libraries in

fact some of you might be here working on some of these helper libraries thank you for that but this is a new authentication primitive that only we in the web 3 world in the front-end world are currently dealing with it's something new an authentication in the back end old world nbc was something more simple right we get a login page it gives us a cookie back we then send authenticated requests with this cookie and our backend says yep this person can actually get the data somewhat simple but now we've got in the smart contract world this little sidecar attached to our applications a client-side authentication primitive of which we're

deriving the wallet state we're issuing queries it's serving as our transport and authenticating the user kind of gives us a logged in state so we have these helper libraries that us front end develops developers are using and they're exposing something with it right they're exposing react hooks well let's talk about react hooks if the central primitive of which all app states is being derived from a hook in your application and you might know anything about reg act hooks only hooks can call other hooks so you have hooks calling hooks calling hooks calling hooks and your entire application then becomes a state

monster basically derived from the central primitive authentication primitive uh of a hook why is that a problem there's a lot of reasons why that is a problem and why gabe has a beef with hooks one it's making us into worse developers honestly it's introducing new and odd programming patterns that we've never really had to deal with and it's a little bit unique to web3 that our authentication primitive is making us do this what you can't do this is an example if you can't do right you can't conditionally call it you couldn't you can't put a hook in a hip claws you can't loop over hooks you find some very odd patterns for us trying to get away around this fact that we can't loop over hooks you can't do this you can't put it

in the jsx it can't be called uh when you want it on demand once it has to be at the top level member of your component and in theory must be running every time it re-renders even though you need it once uh very odd patterns it can only be used in react context as well you can't use it in your state manager another reason why gabe doesn't like react hooks here's an instance yep this represents a value of a token that we're trying to get and if again it's calling folks calling hooks turtles all the way down until you get to the central authentication primitive now what if we have many of these examples many of these components are your hooks being intelligently

shared the instance anyone know is it reusing the instances in the memory no every component gets their own copy of their react hooks and they're isolated and that causes you to go to the performance tab and i challenge anyone here to be able to understand what these hieroglyphics mean but it's bad like took very long i have an m1 mac this thing could put a man on the moon with ease but it can't run my web app use memo you forget one used memo somewhere down this hook hook hook train it is punishing and it will punish you hard to test react hooks i uh run just config adjust coverage on many

of your apps and uh your coverage is not very good either if you have so much state bound into the hook world it is very difficult to test and this is embarrassingly low code coverage one of our apps very often we're console logging right in our components in our hooks why are things re-rendering we're trying to be a detective very difficult with hooks and essentially it boils down what i'd say to this we are not properly thinking through the separation of concerns there is too much stuff in our components our components are too smart when they should be dumb all right so what should we do about this

well if the chief issue is that our wallet state our authentication primitive is being injected and tied to the react render cycle let's get it out let's inject it into our state manager let's put it in a state that is completely agnostic it does doesn't matter it's vanilla js it could be used outside of the react context this would be far more ideal and now it's not so profound that i've come up here and basically said you have to use you should be using some state manager but let me say that all of these patterns here represents vastly superior paradigms for managing your wallet state composing with your wallet state deriving data from your wallets that you get redux

global store functional paradigm you got the mobx mutable classes recoil you got atoms and selectors state machines all of these are better to be handling your app state than being stuck and react hook world what should your components look like in my opinion if you look at a component like this and 80 of it is basically the jsx with state being injected at the top this is what your component should be like now if you go and look at your component and way before you get to the jsx you have a ton of different stuff doing business logic in your component i would say that is a code smell and you're doing something wrong yeah why is this a problem though

uh why can't we do this right now well as we said before the way that we're interacting with our web wallets are reliant upon hooks and they cannot be injected into a non-react state so if you're working on one of these libraries if the chief outcome of this talk can be anything is one please please please do not be making your web wallet libraries natively and react please make them framework agnostic vanilla js and then at the very last second then you can expose your react hooks and even better please expose your stores expose your stores in such a way that we can subscribe to them

and even better we can inject them into our own state manager so that allows us to compose from that layer not the uh deep view layer a couple of us that sushi are running into this issue uh so much so and painfully so that it's not sustainable in our architecture that we're working on actually creating adapters that allow you to take web3 react and use it outside of the react context and actually any type of state manager uh that you're using here's an example of zoo stand all i want is to be able to compose within zoo stand please if you're working on one of these libraries expose a zoo stand slice that i can just put in and then later and separately i have access to that i can compose within the non-react world now

if you want to be doing this transitioning yourselves to the composing within state managers here's an example of what you could do you can write a component whose only job is to run the hooks of your of your wallet and sync them to your state manager it's a little bit of a hack but it does work and then you tell the rest of developers never use these hooks again compose at the state manager level please please please now we're going back to the central uh premise how do we write more sustainable web apps this might not be super popular among front-end apps that you know ipfs it must be pure javascript you can't have any back-ends i would contest right there's certain

things that back-ends allow you to do that front-ends really shouldn't be doing super heavy client-side work also all the work that's being done in our huge bloated front front-end clients are not being shared whereas back-ends can do http caching and i would suggest to you that we can evolve our thinking a little bit on this right but i think we can use the back-end for example next js serverless functions i would qualify that as some degree of a back end for the sake of that it's easily deployed across a many different services right i would kind of qualify that as yes you should be using that we should open our hearts a little bit and count that within the centralized decentralized camp i would even say that if you go as far as making a docker image that

represents your entire application there's so many different platforms that can deploy docker images please let's consider a separation of concerns and consider using some of the back ends i was uh checking out this tweet from one of the engineers on lyra finance last month and he also said something kind of interesting and we're talking about the idea of us in this industry are not managing wallet state properly and there's ways that we can evolve our thinking on this set he's basically saying why do we need the wallet at all right if the wallet only exists to issue right transactions every other use of it which is reads let's not rely upon that context let's use our own node provider really really thoughtful i saw this tweet from last

week this flash of when it says connect and then it turns off right it's kind of annoying for a user it's even more annoying especially when i go to an app and it makes me log in with my web well before i can even use it please stop doing this right the reason why we're doing that is that our philosophy and our coding patterns on the front end as it relates to managing state is uh not developed enough we can do better as far as sushi's concerned we're also thinking about this right how do we manage state better what if we make the state of the application more stateless let's inject the chain id into a sub-domain let's inject a address into the url

that's an idea another idea is considering going old school why don't we cookie the user once we understand the state of the application and then perhaps even using local storage that could be you know an option as well regardless all of us and i'd love to talk to some of you after this about how do we make our web apps more sustainable and a key a key answer to this question and my assumption is we need to manage the wallet state better yeah thank you [Applause] you