Loading
Interviews with Experts Bonus 25 exercises
interview

The Evolution of Type Safety with Colin McDonnell

Colin McDonnell, a Developer Relations representative at Bun and the creator of Zod, shares invaluable insights into the world of type safety in web development. With a background that spans from medical software to tech companies like EdgeDB, Colin brings a multifaceted perspective to the table.

Zod was initially designed to enhance data validation and type safety in a complex medical application. Over time, Zod has established itself in the TypeScript ecosystem, providing superior type inference capabilities compared to alternatives like Yup.

Colin had also developed TRPC, which was later taken over by Alex Johansson, who has since made considerable contributions to the library. TRPC aims to offer end-to-end type safety and has seen its popularity surge, thanks in part to Alex's dedicated efforts.

This sets up a notoriously tricky problem, nested and dynamically arrayed form data. Colin explains how Zod and TRPC can be used to handle this challenge. He also mentions Valobot, a faster but less comprehensive alternative to Zod, while asserting his preference for Zod's developer experience.

Resources

Loading interview

Transcript

00:00:00 Kent: Hey, everybody. How's it going? Colin?

00:00:03 Colin: Not too bad. How you doing?

00:00:05 Kent: Doing great. Everybody, this is my friend Colin. And Colin is the creator of Zod. And you probably by this point in the Epic Web workshop, you've probably used Zod a bit. We use Zod a lot in this workshop series. So I think, I definitely appreciate everything that Colin has done.

00:00:25 1 thing, before I let Colin introduce himself, 1 thing I want to mention is that if you enjoy the type safety that we get across the network chasm between our loader and our UI and our actions in our UI, you have Colin to thank for that. So I was at the first RemixConf and Colin was talking to

00:00:46 me about how, listen, this generic nonsense that you're doing is not great, it can be better. Colin put his fingers on the keyboard to actually make it better. And so, We're just super grateful for Colin in doing that for the Remix community. And then also

00:01:06 Zod is just like, so many people in the web world are using Zod, whether within Remix and outside of Remix, of course. So with that little intro from me, and also all of that said, Colin's just like a pleasure to get to know and to chat with. I really enjoy hanging out and chatting with Colin. So happy to have you here

00:01:26 Colin. Why don't you give your own introduction to yourself?

00:01:29 Colin: Yeah, sounds great. I'll just spin that back at you and say you are a just phenomenal person to meet. People really got to go to all the Remix Comps, do whatever you got to do to meet Ken in person because he's just like truly as just incredibly nice and kind as You would expect based on what you see.

00:01:47 Kent: This is just like a little interview of us like saying nice things about each other.

00:01:52 Colin: Only way I know. Thank you. Don't want to take too much credit for the remix type safety bit. You guys had a system in place, I guess, maybe at the time you were defining your loaders and then the kind of recommended practice was to just kind of extract out the return type

00:02:12 of it with just the built-in TypeScript built-ins, return type is there to pull out the return type of a function. And so I think just a few, saved a few characters there by trying to support it where in the use loader hook you could just put type of loader. And that was all I did, but you guys

00:02:32 had type save. It's just a little, nothing.

00:02:35 Kent: It was way better. So for those listening who weren't back in the day, you could make a, like, you could say whatever the return type of the loader is now pipe that into the use loader data generic. But the problem was if you wanted to use return anything but like the actual object,

00:02:55 like if you want to return a call to JSON to turn it into JSON so that you could supply headers, then you're toast. And so you had to then extract the logic to create the object to a separate function and then do your generic nonsense up there. And it was not fun. No, Colin, it's way

00:03:15 better now. So thank you. So Colin, do you want to talk about really quick where you work? Cause I think people will find that interesting too.

00:03:24 Colin: Yes, I'll stop dodging the question of introducing myself. I'm Colin, I work at BUN, I'm a 2 developer relations there. Before that, I was at EdgeDB. And before that, I was, you know, working on Indie Hackery startup stuff, which is kind of a bit of the origin story

00:03:44 for Zod and some of the other, you know, like the version 0 of TRPC and things like that are some tools that I was kind of working on as I was trying to, you know, build this like piece of medical, like basically medical record software back in like 2019. And at the time, there was a kind

00:04:04 of like a transition to from JavaScript to TypeScript and to kind of like push towards like end-to-end type safety was kind of in its infancy. You know, back then, 2019, like the only time I'd even heard the term end-to-end type safety was in a random Prisma blog post, where they were kind of pushing this

00:04:25 as a new concept. People didn't really know what it meant when you said it, and the tooling just really wasn't there. So as it turns out, I just got extremely lucky to be, you know, A, trying to build like this software that involved a lot of complexity, you know, data modeling. I know you've got a whole 64 unit course

00:04:45 on data modeling here. Very hard problem to solve in the general case. And if you mess it up at the beginning, then your migration story can be really painful and messy.

00:05:00 Kent: You're gonna have to predict the future a little bit, which is awful.

00:05:03 Colin: Yes, for sure. So yeah, I just kind of got lucky to come into TypeScript ecosystem at a time where there was really just a lot of kind of green field tools to be made. Zod was not much more than YUP

00:05:24 with better type inference at the time where it launched. And there's, since now we've added some things that YUP doesn't have. But also I think 1 of the major appeals of Zot is, you know, it kind of didn't include things, you know, aspects of the YUP API that didn't lend themselves well to like TypeScript, type inference stuff. So kind of

00:05:44 like pulling out some of the chaff from this very bloated API. That was more from kind of a bygone JavaScript era, I guess.

00:05:54 Kent: Yeah, yeah, absolutely. I used YUP in those bygone days. And yeah, the type aspect of Zod is like really special. So I'm sure we'll delve into that a little bit further, but I wanted to ask you a little bit about the origin story for Zod and TRPC

00:06:15 and like what's the relationship there? I know Alex is, as far as I understand, Alex is still the primary maintainer of TRPC. And so how did that transition happen? All of that, I'm kind of interested.

00:06:28 Colin: Yeah, so This bit of software I was working on that I alluded to, I decided to be too clever for my own good. And so I decided to try to avoid some of this migration pain I was alluding to. I used Neo4j as my backend database, which is, even the Neo4j

00:06:49 team would tell you, don't do that for your core application database, because it's schema-less. It's like a graph database, and everything is just nodes with edges to other nodes, and both nodes and edges can have properties, and that's kind of the whole thing. Yeah, schema-less, nothing really to enforce

00:07:09 that the data that's in your database is at all, you know, has any kind of expected structure. Not only, you know, It's not like a node isn't even like, you can't even attach like a particular type to it. You can't say like, this is a user node. You can just say, this has the label user and it can also have arbitrarily many other labels as

00:07:28 Kent: well. Interesting.

00:07:30 Colin: So, you just accidentally insert something into your database that's both a user and like a medical condition, and your database is just like, great, that seems fine to me. Let's go with that.

00:07:42 Kent: Yeah, it definitely sounds like a tool that has a purpose, but what you're using it for is probably not that purpose.

00:07:49 Colin: Right, yeah. I was definitely like, oh yeah, you know, I was in this like, it's all, you know, this kind of like lispy, like, oh yeah, whatever, like go with the flow, totally. Like your data can be anything. I'll be able to like attach like edge properties to like implement new features and not have to worry about like actual relational

00:08:09 migrations, whatever. A huge mistake. It turns out, you know, I've learned. But you know, the, the, what this led me to is basically like I needed to validate every single bit of data before I wrote it to my database and make sure that it conformed to, you know, an actual schema that I had to find. Exactly.

00:08:31 And those schemas were, you know, I started off basically trying to define them with some of the existing tools that were out there for schema validation. None of them really like made the cut at the time in terms of type inference. And so that's the origin story for Zod. And that was kind of the source of truth for my schema information,

00:08:51 you know, for this big medical application that had like 200 different models or something. And that's, you know, that's kind of like where it came from. And then that's also why like kind of recursive types were an important part of the story because my data model, you know, medical data

00:09:11 is very like heavily connected, strongly connected. And so kind of like having like a good way to do recursive types didn't really exist in anything except IOTS, which was basically I used the same approach as IOTS for Zod. And not to, you know,

00:09:31 spoil anything, but, you know, proper recursive types that are, have a lot better developer experience than is the current API in Zod3. It's gonna be 1 of the main features for Zod4. Where you can just kind of like use getters inside of your just like z.object declaration. And, you know,

00:09:51 it turns out TypeScript is good enough with getters to just like define schemas that, you know, reference each other and have all the type inference work automatically without having to like do the thing right now where you have to actually cast it to like Zod type, like to the base class.

00:10:07 Kent: Interesting, okay.

00:10:08 Colin: That's something to keep your eyes peeled. I don't know if it'll be out by the

00:10:11 Kent: time of course for us or not. That is actually pretty cool because I've noticed that Zod is fairly stable. Like you haven't done a ton of releases, which some people are like, oh, where are the features and stuff? But others, like for me, I'm like, no, please, like keep it the way it is. It's working great. Like, It sounds like there are a couple, there

00:10:31 are some challenges with it and everything, but I appreciate the stability.

00:10:37 Colin: Yeah, it's definitely, had a lot of fantastic contributions to Zod, over the 3 and a bit years that it's been around now. But more of the feature requests that I see these days are things that I either like, and very intentionally not including, or are like, clearly too niche

00:10:57 to be, adding another 200 bytes or whatever to the bundle size to support like some kind of obscure form of UUID or something, I don't know.

00:11:09 Kent: Oh yeah, yeah, sure. So you mentioned earlier that the first time you had really heard about end-to-end, or what did you say? End-to-end type safety?

00:11:20 Colin: End-to-end type safety, yeah. Which is now like all over the TRPC website and this can talk about a little more.

00:11:27 Kent: So that was on, from Prisma. I remember hearing about that idea from Apollo years ago and the GraphQL folks, they were just constantly like, this is so amazing. And this is, I heard about this before I was really into TypeScript. It was like maybe 2017 or something. That was actually around the time I started getting into TypeScript. But

00:11:47 I saw that and I'm like, I mean, that seems really cool, but then you have to do all this stuff that requires like a GraphQL thing, which is a very serious investment, time and effort, and like, it doesn't really suit all web applications, but the DX is so nice that a lot of people just went for it. And

00:12:07 so I think that kind of leads us in naturally to TRPC and its role in, and I want to hear about its origin story as well.

00:12:15 Colin: Absolutely, yeah. You know, certainly 2019 was, you know, we were already pretty well into the kind of isomorphic JavaScript, like JavaScript everywhere, server and client kind of movement. You know, At the time, Next.js had kind of like relatively recently moved

00:12:35 away from get initial props and had their like move towards, you know, get server-side props, get static props, I think was maybe came in 2018 or something. And so it kind of like had reached a bit of its final form, at least up until now with app directory, it's kind of like a new evolution of it. But you know,

00:12:55 having just like this feeling of like, this is truly all 1 code base, like you don't have even a separate directory for your server and client. Like it's all just right there. You may have your API routes kind of tucked into the like pages slash API or whatever. But like, it really is just like

00:13:16 all just TypeScript. They did all the compiler magic for you where you could just feel like you were importing types straight from your server into your client. You've got your API route that has your Zod schema and you can just import the type from that over into your front end code, wherever you're

00:13:36 defining a form or something and using that same schema in your form. I did try using GraphQL as I was working on this application in 2019. And it basically just like, it kind of like rubbed me the wrong way. I remember at the time I had to have, you know,

00:13:58 this kind of just like a pipeline of cogeneration tools. Yeah. Which is part of the, you know, the sales pitch is like, yeah, your GraphQL schema, it's there, it's introspectable, it's like in a serializable format and you can just code gen whatever you need in any language ecosystem, which I still think like definitely a time and a place for that. And that's

00:14:18 super valuable. But when you know you're gonna be all TypeScript for your front end and your back end, and you're not planning to build any mobile apps or whatnot, it is a lot of friction in the developer experience. There's like, changes have to propagate through your code in this way

00:14:38 that felt kind of like, pain, you know, kind of just like, it felt very slow and painful. You'd upgrade your GraphQL schema, then you had to update your queries, then you had to update all your query mutations, and then throughout all of this, you'd have to be like regenerating the TypeScript types for all these things. And ultimately,

00:14:59 I just kind of bumped on it. And I had actually seen a project from a friend of mine named Kevin Kwok, and that was called Obvious RPC. And it was kind of just like a way for you to have like a file where you export a bunch of functions, you're able to like

00:15:19 kind of import all of those and extract like the return types of all of them. And then just kind of like start using those inferred types in your client side code. There was no sense of like a router or anything. It wasn't kind of TRPC like where you had like an actual like router class that you can

00:15:39 kind of like add procedures onto with, you know, change method calls, you know, like dot route, whatever, you know, in case you can't tell from Zod's API, I like method calls, I like fluent APIs. His thing was a little more magical where you're just exporting these functions and then you've got like kind of a config file to, you know, tell it like how to handle

00:15:59 middleware and things like that. I basically thought it would be kind of a nice experience to have something that looks at least kind of familiar to like an Express user or a Cobo user. You actually have like this router, it's a little more declarative And you're just kind of like adding procedures onto it. And that was the birth of

00:16:19 TRPC v0. At the time I was still working on the startup. I was using my v0 version, you know, internally, like in production, as I built this app. But ultimately at the time Zod was getting more popular by a long shot than TRPC. And

00:16:39 it was kind of like the combination of working on the startup and trying to put more effort into Zod. Basically I just kind of didn't have bandwidth for TRPC, even though I like, believed in it and you know, thought that it like really ought to be, you know, like, used more widely like this pattern in general. And so I just tweeted out saying

00:17:00 like, yeah, I've got like, a handful of open source projects that I've been working on that I have internally that I don't really have time for. And I just, you know, you can still go see this tweet. TRPC was in a list of 4 projects that I kind of like had proofs of concept of. But then Alex, you know, messaged me back and said, like,

00:17:20 I actually have something pretty similar to that, that I've been working on myself. So a lot of these ideas were kind of in the air at the time. And then he was like, kind of took over TRPC and that repo and the branding of it and put together v1 really quickly and it was immediately way more mature,

00:17:40 way more feature complete. Alex gets basically all the credit for TRPC in its modern incarnation, especially with some of the major API changes in version 10 that I think are just like phenomenal and like really like made it what it is today. So yeah, all props

00:18:00 to Alice for TRPC, he's killed it.

00:18:02 Kent: Yeah, yeah. Well, it's definitely gotten really, really popular and just the idea of end-to-end type safety is once you taste that fruit, you can't go back. Like it's just so, so nice. So yeah, thank you for your contributions on both of those. And shout

00:18:22 out to you, Alex, if you ever see this. Thank you. And all contributors, we all know open source is not built by a single person in Nebraska. It is, yeah, there's definitely a lot, a lot that goes into that.

00:18:39 Colin: Although sometimes, that guy in Nebraska, he really does, he is like the foundation for like, you know, billions of dollars in value for sure. It's the XKCD, the 1 little pillar that's supporting the entire ecosystem. That's some 4 person you've never heard of.

00:18:57 Kent: Yeah, yeah. I remember when that was going around, Sean Larkin, co-maintainer of Webpack, lived in Nebraska at that time.

00:19:07 Colin: And I

00:19:08 Kent: always thought that was kind of funny. So yeah, great. Thank you for sharing some of those motivating factors. I think that helps contextualize the ideas around these technologies that we use. In Remix, I have yet to find a use case for TRPC.

00:19:28 I don't know if you'd agree with me that there definitely could be some use cases for them, but for the most part, the loader action methodology around Remix kind of makes TRPC unnecessary. Is that right? From your perspective?

00:19:45 Colin: That's, I think certainly the loader does for, you know, for reads. I can see a scenario where people might consider setting up TRPC for mutations if like they want to break out of, and forgive me, because I'm a little behind on some of the work in Remix on

00:20:05 like, kind of like, you know, nested JSON payloads for posts, like for writes, which I know is like, you know, some, I don't really know what the current status quo is on that. I know like form data kind of just doesn't lend itself super well to that kind of thing. And that's unfortunate,

00:20:26 but it lends itself extremely, extremely well to handling file uploads and things that, you know, you need to go through that form data attraction. And so it does seem, and we've discussed this on Twitter, that there's not really like currently a perfect, a perfect version where you're able to maybe have like, you know, a nicely validated

00:20:46 kind of like nested, you know, a form that kind of produces like a nicely validated nested JSON structure and then be able to like, just like send that over to your backend. I don't know, you can speak more.

00:20:58 Kent: Yeah, yeah. So actually maybe We'll stick this segment of our interview right after we do the nested and dynamically, you know, arrays of form data. Cause yeah, in that exercise, I have this like big thing that explains why form data is so bad at this. And just cause it's super not designed

00:21:18 for that sort of thing. And Conform is the library that we use in the workshop by Edmund, and we're gonna have Edmund on these interviews too. But Conform is just brilliant and uses Zod, the Zod schema to enable these types of field sets. And so,

00:21:39 yeah, that is definitely a huge pain point. And in recent, like the last couple of months, that has been pretty well solved by Conform, which is just stellar. It's so nice. So I think, like, and then on top of that, like if you're okay going with the

00:21:59 TRPC, if that's what you want for, to solve that particular problem, you can actually still submit JSON using lower level or other APIs from Remix as well. So I do think that TRPC has a better place in other frameworks that haven't

00:22:19 quite embraced the forms or if that's not an important aspect of the web app that you're building. But Zod for sure has like just a beautiful place in the apps that I build anyway. So on this-

00:22:35 Colin: It slots in, you know, really nicely, I would say, with Next.js, pretty app-tier. And then some of the other things that are a little more hands-off in terms of just like, you know, you've got to figure out the whole data layer for yourself, which was most frameworks really until like Next.js

00:22:56 to like a limited extent and then Remix is where it's like, you know, the loader concept and loaders and action concepts are like integrated into your, like, you know, the files system structure for the framework, you know, in a way that, like is really smart and like unlocks just like all the good stuff that Remix gives you. And so, yeah,

00:23:16 we'll see if more of these, whatever, like even next-gen frameworks that are coming out, get more or less opinionated in terms of how like data fetching or mutations happen.

00:23:29 Kent: Yeah, you know, I think that TRPC had a role in the motivation behind what all these frameworks are doing. It's just like a very natural progression of, yeah, TypeScript's pretty cool. I sure wish that I had type safety over this network boundary. And that, so

00:23:49 that I think had a major influence there. So on the Zod subject, a couple weeks, maybe months ago, we had this new library come out called Valobot. At least, I'm not sure how they market themselves right now. I

00:24:09 should probably look, but when it came out, it was like smaller version of Zod and faster. And like, basically, I am Zod, but better. Which is always kind of a Funny feeling that I get when I see something marketed as like this but better but

00:24:30 I don't mind it so much if it comes from the author of the thing, but it feels kind of funny coming from somebody else. So yeah, I'd love to hear your take on Valobot. And I've got my own kind of opinions from what I've seen so far, but yeah, love to hear your take.

00:24:47 Colin: I'm very thrilled that Valobot exists. And I'd be way more annoyed. You know, when Zob came out, I would say the improvements that it provided were quite marginal on the status quo, marginal improvements over YUP, which had like a lot of weirdness in its

00:25:07 API, like things like when you declare an object schema, you know, all of your keys are optional by default, unless you do not require it on them or whatever. That's just like kind of like an incompatibility with the way we think about data modeling as TypeScript, you know, engineers. And so changing the API, you know, some little changes to

00:25:27 the API to bring it in line with the TypeScript ethos, you know, turned out to be like something that a lot of people were looking for. But ultimately, like, you know, the bones of the thing are like quite similar to to YUP or like, you know, the bones of Zod are quite similar to YUP or other existing options. I'm I love that Valobot exists because it's like a

00:25:47 dramatically different take. And it's like a very clean trade-off that was known to me when I was designing the API for Zod. It's truly a trade-off between what I would consider to be developer experience, like a trade-off between having a trainable fluent

00:26:08 API, that's like easier to learn and more discoverable and being tree shakable. And it's just like kind of 1 of these law of the universe things where, you know, I personally don't really like the idea of like importing, you know, having a separate import for like every single kind of like bit of functionality

00:26:28 that I need from a library. It's you know, it's common I think with monorepos to kind of like end up publishing different bits of functionality for your library to like different packages. This is not a great example, but you know, the like, at trpc slash client at trpc slash server

00:26:48 at trpc slash next. Like you kind of like have all these different packages and you have end up with a lot of TRPC related imports just to, you know, depending on what kind of bit of bits of functionality you need. I, For the most part, I've been building apps that are either all

00:27:08 server-side rendered or single-page applications where I kind of had already lost the bundle size fight or it was irrelevant. I haven't built like a blog or something recent that isn't like entirely statically generated or like SSR.

00:27:29 So things where like the bundle size of what you send to the client matters a lot. And these kinds of content driven sites that are common for users of Astro, for instance, they are in a scenario where 9 kilobytes to ship down all of Zod is like,

00:27:50 you know, not a worthwhile trade off, especially if you're trying to like, make sure that your site loads quickly for people who are on like, you know, 3G connections, things like that. Yeah, I'm like very sympathetic to that, but ultimately, if I redesign

00:28:10 Zod today, I would stick with the Kergan API, the Chainable API, Because I like the idea of importing everything as Z, even if I'm importing the whole package. I like the idea of, you know, if you have an instance of Zod, you know, a Zod schema instance, you know the full set of methods that are gonna be available on it. In your IDE,

00:28:30 you can press dot and then see them all listed and you can arrow through them. Yeah, discoverability. The discoverability with IntelliSense, like that feels like if you're optimizing for developer experience, which is, you know, Zod's whole thing, then that's kind of the only move.

00:28:50 I think it's basically extremely clever what Fabian did, Fabian Hiller, who also has contributed to Zod and sent me a pre-release version of Valobot and is very kind to shout out Zod on stocks and stuff. But it's very clever what he did where in Zod you would do

00:29:10 z.string to declare a string schema, and then you chain methods from there to add refinements or add a transform or make it optional, yada yada. For his API, you do z.string, that's a function, and then you pass in an array of your additional validations that you want to do

00:29:31 on that string schema. And a lot of those, like the names of, you know, you just pass in basically a bunch of little validators that you would import, you know, like have a separate import for. So something like, you know, ends with, or, you know, length or something. You can just kind of like import those in and do like z.string parentheses and then

00:29:51 pass into that your array of all your kind of sub-validations. And that lets you do the tree shaking because if you're not using the min-length validator, that gets stripped away when you do your final build just with tree shaking that's built into modern bundlers. Whereas for Zod,

00:30:12 you know, dot ends with it's like a method on the Zod string schema. And that's just all those method implementations are gonna get pulled in if you have any instance of ZodString anywhere in your code base. And then that actually gets compounded because a lot of the methods that people really rely on in

00:30:32 Zod are, they're on the base class that all schemas inherit from, things like .optional, .nullable, refine, transform, super refine, whatever, things like that. Those are on the base class and they return instances of subclasses. So like .optional returns a Zod optional instance. So

00:30:52 if you use any instance of any Zod schema, then the implementation of Zod optional is gonna get pulled in because it's used in the implementation of the dot optional method that's on the base class. So, you know, ultimately everything ends up getting pulled in. And, you know, the move for Zod is like, you know, try

00:31:12 to make the bundle size as small as possible. But, you know, that's always been a secondary concern for me after developer experience. But you know, by all means, like I think the more the merrier. I think all the tools that are out there that want to support, you know, I prefer when

00:31:32 tools don't, you know, rely exclusively on SOD, you know, third party ecosystem tools. I think it generally makes sense to try to, like TRPC does, support kind of like every possible validation library, you know, just like let people pass in any object with a dot parse method on it or something, you know, which is not dissimilar

00:31:52 from what TRPC does. And, you know, it's always good if you're going to be building something that requires runtime validation, you know, for your own user's sake, let them bring whatever they want to the table in terms of validation.

00:32:06 Kent: Yeah, I think that's such a great take. So when I was working at PayPal, this story relates, but it's gonna be a little bit long. So when I was working at PayPal, I wanted to solve some CSS problems that we had. Long story short, I created Glamorous, which is a CSS and JS library inspired by

00:32:26 styled components. And they were different enough that it made sense for them both to exist. Then later on, a year or 2 down the road, somebody who helped me with Glamorous decided to rewrite the CSS and JS implementation, which was called Glamour, written by Sunil

00:32:47 Pai, decided he wanted to rewrite that from scratch and do something else, and then built effectively what was same thing as Glamourous but he packaged it all up into 1 thing called Emotion. And that library was smaller, faster, and better in every single way

00:33:07 to Glamorous. And so when I looked at that and I was thinking, okay, so what emotion can I adopt? And I just thought, there's not a single reason that Glamorous should exist because this emotion does everything that Glamorous can do. There's no trade-off here where Glamorous comes out on top. And so I deprecated Glamorous and I said, everybody move over to Emotion

00:33:28 and Tejas put together a code mod and the rest is history, it was great. But that's not the case for Zod and Valbot. There's actually like legitimate reasons for each of these to continue to exist. And I really appreciate your breakdown of the trade-offs there. So yeah, thank you for

00:33:48 that. For me, when I saw Valobot, I feel similar about the developer experience to you. And what really made me just stick with Zod, like this was, if for no other reason, this would be enough, Conform, my form library, only supports Zod, it doesn't support Valbot.

00:34:09 And so I'm like, that does it for me, because Conform is awesome, and Zod is great. When I first started with the Epic stack, I was trying to figure out, okay, how can I make sure that Zot is only a server side thing so that I don't bring in Zot into the client? And the longer I spent working on that, the more I realized that does not matter.

00:34:30 Like It is totally fine to bring Zot along for the ride. It's really not that big. And on top of that, when you have server rendering and the user sees the whole page while the JavaScript is loading in the background, like, so what? That's fine. Everything, especially with Conform, it's progressively enhanced, so the forms will still work and everything,

00:34:50 and the validation still runs on the server, like it's all gonna work just fine. So I don't mind so much that there's so much JavaScript in the client. And Zot, it really, it's not that much. So Anyway, I appreciate that breakdown of the trade-offs there. And I'm glad that Valobot exists for those same reasons. That makes a lot of sense.

00:35:10 Colin: Absolutely, yeah. If you're trying to go 0 JS, you know, like GoHamp, Valobot's really good for it. Or like minimal JS, at least. But yeah, that's a really good point as well, where if you're, even if you are server-side rendering and then sending a bundle for hydration, the user's got something to look at as it comes

00:35:30 down. That's a good call.

00:35:32 Kent: Yeah. Well, awesome. I've really enjoyed this chat, Colin. I think we're winding down to a close. Is there anything that we didn't talk about that you'd like to mention?

00:35:42 Colin: Well, something that I put in the form as I was scheduling this is that I'm far from a diehard, actually, but I did some research on this. I was, lived about a mile and a half away from the coworking space where I usually work, up until recently. And I was looking at my options for, you know, last mile electric transport.

00:36:03 And I know that you're a bit of an evangelist of the 1 wheel. And you were giving people lessons at RemixConf last year, which I thought was just fantastic. I was on my way to the airport with my suitcase and I see a gaggle of people getting, you know, 1 wheel lessons from Ken. And I was like, I've made

00:36:23 a huge mistake. I didn't make the points in my flight. But what I ended up getting was an EUC because unfortunately they win on basically all the metrics, you know, like all the specs, except they just look way lamer.

00:36:42 Kent: I a hundred percent agree. Yeah, that's funny. Like you can go way faster. I actually, when I think about that, so, okay, actually you continue. What kind of unicycle did you get?

00:36:55 Colin: I got the 1 that was at for sale at an insane price on Craigslist. I actually not even sure what the brand name is. I like taken it out 3 times and learned like, oh, I've got a lot of catching up to do because you need to actually have like a core strength and balance to ride in the UC, which is another actually huge

00:37:15 strike against it. You know, you got to have some sense of balance for 1 wheels. The EUC, it was not coming naturally to me immediately.

00:37:25 Kent: Yeah, I've never ridden 1 before, I would like to sometime, but I know some of those things can go like 40, 50, maybe even 60 miles an hour. And it's just like, no thanks.

00:37:39 Colin: Yeah, there's like an off-road community as well of people who are just like motorcycle helmet, like all pads everywhere, just going down like mountain biking trails and stuff. It's true madness. I think the range on mine is something like 40 miles. Yeah, that's nice. I could like, yeah, I'm in Seattle, I could do a loop around

00:37:59 all the way to Redmond, Bellevue, and across the bridge, all the way back around just on 1 charge, which is wild.

00:38:06 Kent: That is super wild.

00:38:08 Colin: This is me really just putting out a plea. I don't know if you have some contacts at the Onewheel company. We gotta get the 40 mile range version of the 1 you're going.

00:38:17 Kent: That would be so nice. So I have the GT and it's fantastic. I can leave from my front doorstep and make it all the way to Ryan's house, which is about 25 to 27 miles apart. And I get to his house with 2%. Incredible. Yeah, it's

00:38:37 barely and I'm not going as fast as you are either so it does take me longer because I get up to about 20 miles an hour And that's about as fast as I can get. But,

00:38:48 Colin: That's good though. That'll, Yeah, pretty fast. Yeah, that'll be a

00:38:52 Kent: long time. I wouldn't want to go much

00:38:53 Colin: faster. Exactly.

00:38:55 Kent: But, yeah, that would be super nice to have that much more battery, so.

00:39:01 Colin: We'll get there, we'll get there.

00:39:03 Kent: We need better battery technology. Everybody's working on it.

00:39:07 Colin: That's right.

00:39:08 Kent: Yeah, well, Colin, thank you so much. This has just been such a pleasure to chat with you and from everybody watching and from me to you, just thank you for all your contributions in the web and especially your work on Bunn right now too. Super stoked about all that work, so thank you for that work too. And yeah,

00:39:28 keep up the good work.

00:39:30 Colin: Thank you so much, Kent. And right back at you. So psyched for Epic Web Dev. So yeah, thanks for having me.

00:39:36 Kent: Thank you so much. Oh, 1 last thing. What's the best way for people to get in contact with you?

00:39:43 Colin: Twitter still. I'm there, at Colin Hacks. Or Colin at ColinHacks.com. You know, good old-fashioned email.

00:39:51 Kent: All right, solid. OK, hey, thanks a lot. We'll see everybody later.

00:39:57 Colin: Bye, Ken.