1 00:00:00,000 --> 00:00:03,163 What do you mean replicate the whole data to the end client? 2 00:00:03,173 --> 00:00:03,959 Like, It's too big. 3 00:00:03,959 --> 00:00:04,719 Like, that can't work. 4 00:00:04,765 --> 00:00:06,635 So I understand the hesitation. 5 00:00:06,749 --> 00:00:10,039 But any like half step in that direction, it just a gateway to 6 00:00:10,039 --> 00:00:11,449 replicating more and more and more. 7 00:00:11,479 --> 00:00:13,469 Cause you just want more and more and more to be instant. 8 00:00:13,479 --> 00:00:17,934 So I had a very traditional mindset around it, which is, okay, we have an 9 00:00:17,934 --> 00:00:21,884 API, the API serves data and we're going to like cache some of that locally. 10 00:00:22,144 --> 00:00:24,704 And I think a lot of people are already doing this stuff, like react-query 11 00:00:24,800 --> 00:00:28,650 put you in that direction where just caching stuff and then refetching. 12 00:00:28,850 --> 00:00:32,250 It kind of gives you some of this like real time local-first feel, but then 13 00:00:32,250 --> 00:00:34,977 you start to hit the limits with that, if you're looking for stuff that's not 14 00:00:34,987 --> 00:00:38,954 literally in the exact view, you're then round tripping with the server again. 15 00:00:39,154 --> 00:00:42,547 The key thing to understand is if you're building an app that people 16 00:00:42,547 --> 00:00:46,717 are actually using every day, the initial load time is really not 17 00:00:46,717 --> 00:00:48,047 something you need to care about. 18 00:00:48,483 --> 00:00:50,593 Welcome to the Local First FM podcast. 19 00:00:50,953 --> 00:00:53,673 I'm your host, Johannes Schickling, and I'm a web developer, a 20 00:00:53,673 --> 00:00:56,833 startup founder, and love the craft of software engineering. 21 00:00:57,253 --> 00:01:01,153 For the past few years, I've been on a journey to build a modern, high quality 22 00:01:01,153 --> 00:01:02,873 music app using web technologies. 23 00:01:03,253 --> 00:01:07,233 And in doing so, I've been falling down the rabbit hole of local first software. 24 00:01:07,733 --> 00:01:10,743 This podcast is your invitation to join me on that journey. 25 00:01:11,663 --> 00:01:15,553 In this episode, I'm speaking to Dax Rad, who is using local first 26 00:01:15,573 --> 00:01:19,303 in multiple projects, including the serverless deployment tool, sst. 27 00:01:19,303 --> 00:01:23,313 dev, a healthcare app, and an upcoming personal finance app. 28 00:01:23,953 --> 00:01:29,453 In this conversation, we explore how local first simplifies app development, the UX 29 00:01:29,493 --> 00:01:34,173 and data patterns he's using, and how self hosting could empower local first apps. 30 00:01:34,893 --> 00:01:38,253 Before getting started, also a big thank you to Expo and Crab 31 00:01:38,253 --> 00:01:40,013 Nebula for supporting this podcast. 32 00:01:40,493 --> 00:01:42,313 And now my interview with Dax. 33 00:01:42,853 --> 00:01:44,273 Hey Dax, welcome to the show. 34 00:01:44,273 --> 00:01:44,863 How are you doing? 35 00:01:45,593 --> 00:01:45,963 Good. 36 00:01:45,973 --> 00:01:46,653 How are you doing? 37 00:01:47,023 --> 00:01:48,023 I'm doing great. 38 00:01:48,133 --> 00:01:49,813 Super excited to have you on the show. 39 00:01:50,093 --> 00:01:54,289 You're certainly also one of the more, well known voices on Twitter 40 00:01:54,359 --> 00:01:56,149 sharing the local-first gospel. 41 00:01:56,539 --> 00:02:00,159 So, seems like you're not just working on one project with local-first, 42 00:02:00,179 --> 00:02:04,509 but almost quite a portfolio of local-first inspired projects. 43 00:02:04,799 --> 00:02:08,119 So super curious to hear more about those, but maybe you want to 44 00:02:08,119 --> 00:02:11,879 share a bit of your story of like, what has led you to local-first? 45 00:02:12,399 --> 00:02:13,539 yeah, so my name is Dax. 46 00:02:13,589 --> 00:02:17,489 My primary project that I work on is a project called SST. 47 00:02:18,049 --> 00:02:19,909 Uh, we're a, we're a dev tool. 48 00:02:19,919 --> 00:02:21,679 Like, we help people ship applications. 49 00:02:21,679 --> 00:02:25,159 We help people deploy all kinds of infrastructure to all kinds of places. 50 00:02:25,759 --> 00:02:29,199 And we have an adjacent project to it. 51 00:02:29,289 --> 00:02:32,809 Uh, so SST users get access to this thing called the SST console. 52 00:02:33,649 --> 00:02:36,029 And that is a local-first application. 53 00:02:36,839 --> 00:02:38,319 I mean, I'm gonna say local-first. 54 00:02:38,339 --> 00:02:39,789 There's obviously, like, a spectrum. 55 00:02:39,789 --> 00:02:40,789 I would say it's a local-first. 56 00:02:41,249 --> 00:02:45,209 The least local-first thing with that you could possibly have while still, 57 00:02:45,239 --> 00:02:48,869 I would say, embodying some of the characteristics, but my history with it, 58 00:02:49,509 --> 00:02:54,179 like most people or like a lot of people, I guess, uh, it started with, with Linear. 59 00:02:54,259 --> 00:02:55,249 I came across. 60 00:02:56,014 --> 00:03:00,654 The product probably like 2018 or 2019 somewhere, somewhere around there, 61 00:03:00,654 --> 00:03:02,054 probably 2019, something like that. 62 00:03:02,384 --> 00:03:06,944 And I found them fascinating in a few dimensions. 63 00:03:07,414 --> 00:03:10,534 One, their attention to detail was just kind of outrageous. 64 00:03:10,594 --> 00:03:11,904 Like there's all these little details. 65 00:03:12,624 --> 00:03:16,094 Outside of local-first stuff, just these details that are in there that, you know, 66 00:03:16,124 --> 00:03:17,674 they're, they're like real craftsmen. 67 00:03:17,674 --> 00:03:20,324 They care about, uh, every little aspect of their product. 68 00:03:20,714 --> 00:03:24,494 I found them really interesting from a business perspective because they 69 00:03:24,494 --> 00:03:28,774 entered the most crowded and most cliche space you can possibly think of. 70 00:03:28,804 --> 00:03:32,414 Everyone has had the idea of, I hate my project management tool. 71 00:03:32,424 --> 00:03:36,104 Like I should build my own, uh, the most boring, cliche, 72 00:03:36,144 --> 00:03:37,884 non innovative idea possible. 73 00:03:38,429 --> 00:03:40,909 They enter that space and they absolutely crush it. 74 00:03:40,909 --> 00:03:42,629 Like no one really could have predicted that. 75 00:03:42,629 --> 00:03:45,469 I think you would have, if you just heard that idea, you're just 76 00:03:45,469 --> 00:03:49,389 been like, whatever, and they did that purely from this aspect of. 77 00:03:49,834 --> 00:03:52,424 Really excellent quality and performance. 78 00:03:52,724 --> 00:03:55,984 And these are things that people will love to say, like, oh, the user doesn't care. 79 00:03:56,004 --> 00:03:57,644 People, performance doesn't matter. 80 00:03:57,644 --> 00:04:00,834 Like, you know, they'll try to say that it's something that you can do later. 81 00:04:00,954 --> 00:04:05,274 And this is a great example of a company that's kind of violating that narrative. 82 00:04:05,784 --> 00:04:07,404 So I find them really fascinating. 83 00:04:07,554 --> 00:04:11,779 And I got obsessed with just digging into how They built their stuff 84 00:04:11,859 --> 00:04:13,369 initially from like a UI perspective. 85 00:04:13,369 --> 00:04:16,039 But then I was like kind of looking into how all this, how everything 86 00:04:16,039 --> 00:04:18,359 is super responsive and instant. 87 00:04:18,529 --> 00:04:21,249 And I started them so hard to the point where I think I was really 88 00:04:21,249 --> 00:04:23,599 convinced at some point that I knew more about their system than 89 00:04:23,599 --> 00:04:25,109 anybody that didn't work there. 90 00:04:25,379 --> 00:04:27,479 Like I understood like their exact protocol, like how 91 00:04:27,479 --> 00:04:29,129 they sort stuff locally. 92 00:04:29,129 --> 00:04:32,099 Uh, I kind of just kept going back to it to refer to it. 93 00:04:32,429 --> 00:04:34,969 And around the same time, my wife and I were starting a new 94 00:04:34,969 --> 00:04:39,009 project in the healthcare space, and this was a productivity tool. 95 00:04:39,029 --> 00:04:43,299 So it's the type of tool that people log into the beginning of the day, use it 96 00:04:43,299 --> 00:04:45,639 all day until they finish their work. 97 00:04:45,689 --> 00:04:49,729 So these are the places where I feel like the performance 98 00:04:49,769 --> 00:04:51,869 aspect is really understated. 99 00:04:52,539 --> 00:04:57,449 When you're using an app every single second of the day to do your work, 100 00:04:57,904 --> 00:05:01,104 There's all those little paper cuts where something takes a little bit longer 101 00:05:01,104 --> 00:05:02,574 to load, or there's like a spinner. 102 00:05:03,224 --> 00:05:04,484 These do weigh on you. 103 00:05:04,524 --> 00:05:07,164 If you talk to the user, they probably won't articulate it. 104 00:05:07,464 --> 00:05:11,648 But if you ask them the question, does it feel like a joy to do your work? 105 00:05:11,668 --> 00:05:13,228 Or does it feel draining to do your work? 106 00:05:13,478 --> 00:05:16,938 And they're going to say draining unless you push things to this degree. 107 00:05:17,348 --> 00:05:20,608 and this never shows up in like typical user research or like user 108 00:05:20,608 --> 00:05:21,878 feedback or any of that stuff. 109 00:05:22,108 --> 00:05:24,568 So because we were working on something in this category, I 110 00:05:24,568 --> 00:05:25,948 was like, okay, we have to do it. 111 00:05:26,428 --> 00:05:29,118 We have to like set the, meet the same bar that Linear met. 112 00:05:29,318 --> 00:05:31,978 And that's kind of when I started digging into what are all the 113 00:05:31,978 --> 00:05:34,488 different ways that we can enable this. 114 00:05:34,638 --> 00:05:39,978 And we started from like a JSON API using Orbit to like replicate 115 00:05:39,978 --> 00:05:43,728 the data locally, to GraphQL and Urql to do something similar. 116 00:05:44,188 --> 00:05:47,008 Um, and then we eventually ended up on Replicache after, 117 00:05:47,008 --> 00:05:48,398 like, trying a few of those. 118 00:05:48,428 --> 00:05:51,428 Uh, we also tried, I think, RxDB at some point. 119 00:05:52,088 --> 00:05:55,258 Because we knew that, yeah, we want to have almost every operation 120 00:05:55,408 --> 00:05:59,248 happen locally, if possible, so that the feedback is instant. 121 00:05:59,718 --> 00:06:02,008 You know, searching, and this is in the healthcare space, so searching 122 00:06:02,008 --> 00:06:03,398 through patients should be instant. 123 00:06:03,408 --> 00:06:05,958 Loading up their information should be instant. 124 00:06:06,058 --> 00:06:10,443 Even if we had a really large data set on the server, In terms of like, 125 00:06:10,513 --> 00:06:13,413 a single business might have, you know, tens of thousands of patients. 126 00:06:14,003 --> 00:06:16,783 An individual doctor is only seeing a small subset. 127 00:06:16,783 --> 00:06:19,713 So having the ability to like, partially sync the data that 128 00:06:19,713 --> 00:06:21,073 we know the user cares about. 129 00:06:21,283 --> 00:06:24,253 So we spent like, through the course of building this product, 130 00:06:24,273 --> 00:06:25,863 we tried so many different setups. 131 00:06:25,973 --> 00:06:31,113 And we've probably spent two years of learning and trying how to do these 132 00:06:31,133 --> 00:06:35,363 patterns before we landed on something where, one, like the tools, like 133 00:06:35,363 --> 00:06:36,303 I said, we ended up on Replicache. 134 00:06:36,303 --> 00:06:40,573 Replicache is a tool that we liked, and two, like, As people building products, 135 00:06:40,573 --> 00:06:43,983 like we understood how to like, really take advantage of it, how to structure 136 00:06:43,983 --> 00:06:45,393 things and where to pay attention. 137 00:06:45,753 --> 00:06:47,903 So that product is called Bumi. 138 00:06:48,683 --> 00:06:50,743 Uh, we actually ended up deciding to pivot away from it. 139 00:06:50,743 --> 00:06:54,063 Uh, like we have, we have some customers, but it just ended up not being a 140 00:06:54,063 --> 00:06:55,743 market that was particularly large. 141 00:06:56,133 --> 00:06:59,143 And so we wanted to switch to something that was a lot more, 142 00:06:59,243 --> 00:07:01,643 like, wide, like anyone can use. 143 00:07:02,313 --> 00:07:05,413 And something that we personally would use, I found that any product 144 00:07:05,413 --> 00:07:09,263 I build where I personally use it, it just comes out like 10 times better. 145 00:07:09,683 --> 00:07:13,023 It's just way easier to understand the problems and be motivated to fix them. 146 00:07:13,353 --> 00:07:15,483 So we're working on a new product called Radiant now. 147 00:07:15,893 --> 00:07:18,923 And that is a personal finance application, which again, 148 00:07:18,933 --> 00:07:21,333 there's thousands of, very similar to the Linear story. 149 00:07:21,883 --> 00:07:25,133 But we really believe building, like, a very power user 150 00:07:25,133 --> 00:07:27,358 productivity focused version of it. 151 00:07:27,528 --> 00:07:29,778 There's like interesting room in the market for that. 152 00:07:30,018 --> 00:07:33,578 So the one other thing just to kind of cap off the story is, uh, so between 153 00:07:33,578 --> 00:07:38,488 those two things, uh, working on SST, we also kicked off a new project there, the 154 00:07:38,488 --> 00:07:40,148 SST console, which I mentioned earlier. 155 00:07:40,388 --> 00:07:43,998 Kind of a similar story where this is a tool that you use alongside 156 00:07:43,998 --> 00:07:44,938 your day to day development. 157 00:07:44,948 --> 00:07:46,618 You're using all the time. 158 00:07:46,998 --> 00:07:51,468 Having every single thing be fast really makes a difference in the end 159 00:07:51,468 --> 00:07:56,618 feeling that users have of the product, so we decided to go with the same kind 160 00:07:56,618 --> 00:07:58,718 of local-first ish model for that. 161 00:07:58,888 --> 00:08:00,728 And that one is completely open source. 162 00:08:00,758 --> 00:08:02,548 We were really public about building it. 163 00:08:02,928 --> 00:08:07,433 I think a lot of people were exposed to the idea of This pattern, and we've seen 164 00:08:07,433 --> 00:08:12,083 people like, kind of take that project and like, use a basis, use it as a 165 00:08:12,083 --> 00:08:13,353 basis for things that they're building. 166 00:08:13,573 --> 00:08:16,983 So yeah, I think for me it's always been about delivering 167 00:08:17,113 --> 00:08:19,963 a much higher user experience. 168 00:08:19,993 --> 00:08:25,073 I really feel like at some point the web was really focused on how 169 00:08:25,073 --> 00:08:27,623 can we make the web feel native, and that was like the obsession. 170 00:08:28,103 --> 00:08:33,178 And for some reason that like, kind of went out of popularity, but I personally 171 00:08:33,178 --> 00:08:37,488 still care about that as an end user when I use products and they're slow and laggy. 172 00:08:37,908 --> 00:08:39,318 I want everything to be my browser. 173 00:08:39,328 --> 00:08:41,888 I like that and I want people building those things to care 174 00:08:41,888 --> 00:08:44,368 about those things because I'm just going to be happier as a user. 175 00:08:44,388 --> 00:08:45,398 And it's kind of been my. 176 00:08:45,933 --> 00:08:48,813 My reasoning to really like, you know, spread the word about this stuff. 177 00:08:49,203 --> 00:08:49,613 Yeah. 178 00:08:49,673 --> 00:08:52,673 Everything you've just said deeply, deeply resonates with me. 179 00:08:52,713 --> 00:08:56,953 I'm similarly also very inspired by, by the folks at Linear, how 180 00:08:56,953 --> 00:08:59,513 much value they put into the craft. 181 00:08:59,783 --> 00:09:03,363 I was actually just, uh, as a little anecdote, I was just having 182 00:09:03,363 --> 00:09:08,033 drinks last night, uh, with Julian from the, the, the Linear team. 183 00:09:08,083 --> 00:09:11,613 And we were also chatting about this and similar to what you've 184 00:09:11,613 --> 00:09:13,863 described as that it's so tricky. 185 00:09:13,863 --> 00:09:18,423 It never shows up in your user interviews, et cetera, that people say like, Oh, 186 00:09:18,423 --> 00:09:22,213 like I'm really annoyed that this button takes like 300 milliseconds. 187 00:09:22,213 --> 00:09:26,093 But if it was instant, then I think people will really, uh, share that. 188 00:09:26,363 --> 00:09:30,948 And it's basically like a, more of like a death by a thousand paper cuts, and 189 00:09:30,998 --> 00:09:35,568 it's too hard to enumerate the thousand paper cuts, but it's still kind of clear 190 00:09:35,588 --> 00:09:37,508 that the product is not very smooth. 191 00:09:37,798 --> 00:09:41,738 But once you really, once you're using Linear, then there is no going back. 192 00:09:42,098 --> 00:09:44,668 And this seems to be also still like a challenge in terms 193 00:09:44,668 --> 00:09:45,918 of communication for them. 194 00:09:46,188 --> 00:09:49,558 How do they articulate to someone who has not tried it out yet? 195 00:09:49,808 --> 00:09:51,168 What the difference is? 196 00:09:51,543 --> 00:09:55,733 It's that overall quality and, but I think they're doing a great job of 197 00:09:55,733 --> 00:09:59,733 just being sort of like the lighthouse example now of like what that next 198 00:09:59,733 --> 00:10:03,833 generation category defining product feels like and should be like. 199 00:10:04,223 --> 00:10:07,943 So I think they're, they've like bootstrapped their way out of that, that 200 00:10:07,943 --> 00:10:13,593 problem and it's very inspiring for me where I'm like my JIRA is kind of music 201 00:10:13,593 --> 00:10:18,613 apps where I am annoyed by the thousand paper cuts that you have in when you're 202 00:10:18,613 --> 00:10:21,688 using Spotify or SoundCloud, et cetera. 203 00:10:22,018 --> 00:10:27,608 So many of those supposed apps feel more like websites that really like 204 00:10:27,628 --> 00:10:32,198 Winamp was a, or iTunes back in the golden days, that was a much superior 205 00:10:32,198 --> 00:10:34,048 user experience to what we have today. 206 00:10:34,048 --> 00:10:39,528 We have maybe a richer ecosystem in terms of available music, but the actual user 207 00:10:39,538 --> 00:10:46,058 experience that has really suffered and I similarly also care a lot about how 208 00:10:46,068 --> 00:10:48,348 native can you make a web app feel like. 209 00:10:48,518 --> 00:10:53,454 And not just, end up with your ambitions on like a website level. 210 00:10:54,144 --> 00:10:56,264 So, uh, that deeply resonates. 211 00:10:56,504 --> 00:11:00,954 I think there is, it's both, uh, equally exciting to explore that from a user 212 00:11:00,954 --> 00:11:02,604 experience, what really drove you. 213 00:11:02,974 --> 00:11:06,674 But I think there's also a lot of potential from a developer 214 00:11:06,794 --> 00:11:11,414 experience point of view, where I think there's also so much stuff 215 00:11:11,414 --> 00:11:12,959 we just put up with as a developer. 216 00:11:12,959 --> 00:11:17,999 So I'm also curious to hear more on that, but yeah, you, you mentioned that you 217 00:11:18,009 --> 00:11:24,179 had a one to two years of explorations early on that, where you figured out 218 00:11:24,189 --> 00:11:27,679 how not to do it, I'd love to hear a bit more about those failed attempts. 219 00:11:28,554 --> 00:11:33,184 Yeah, so I think, the spectrum really was just us dipping a toe to 220 00:11:33,184 --> 00:11:36,254 then going further and further and further with how much is done locally. 221 00:11:36,714 --> 00:11:40,941 So, I think initially, it's, that sounds weird to everyone, right? 222 00:11:40,941 --> 00:11:45,251 Like, what do you mean replicate the whole data to the end client? 223 00:11:45,261 --> 00:11:46,091 Like, it's too big. 224 00:11:46,091 --> 00:11:46,851 Like, that can't work. 225 00:11:46,861 --> 00:11:47,871 Or like, what about this? 226 00:11:47,871 --> 00:11:48,251 What about that? 227 00:11:48,251 --> 00:11:48,721 What about that? 228 00:11:49,161 --> 00:11:51,321 Uh, so I understand the hesitation. 229 00:11:51,881 --> 00:11:55,691 But any like half step in that direction, it just kind of a gateway to like, just 230 00:11:55,691 --> 00:11:57,101 replicating more and more and more. 231 00:11:57,131 --> 00:11:59,121 Cause you just want more and more and more to be instant. 232 00:11:59,131 --> 00:12:03,586 So I had a very traditional mindset around it, which is, okay, we have an 233 00:12:03,586 --> 00:12:07,706 API, the API serves data and like, we're going to like cache some of that locally. 234 00:12:07,966 --> 00:12:09,586 And I think a lot of people are already doing this. 235 00:12:09,586 --> 00:12:13,096 Like a lot of stuff, like react-query like gives you this starts to like put 236 00:12:13,096 --> 00:12:17,696 you in that direction where just caching stuff and then like refetching, you know, 237 00:12:17,696 --> 00:12:20,246 when the window becomes active again, it kind of gives you some of this like 238 00:12:20,246 --> 00:12:24,956 real time local-first feel, but then you start to hit the limits with that, where. 239 00:12:25,173 --> 00:12:28,049 If you're like, if you're looking for stuff that's not literally in 240 00:12:28,049 --> 00:12:31,889 the exact view, you're then kind of round tripping with the server again. 241 00:12:32,409 --> 00:12:37,459 And I think the key thing to understand is, is if you're building an app that 242 00:12:37,459 --> 00:12:42,813 people are actually using every day, the initial load time is really not 243 00:12:42,813 --> 00:12:44,143 something you need to care about. 244 00:12:44,273 --> 00:12:47,046 The first time they load the app, like let's say they like 245 00:12:47,046 --> 00:12:49,316 log out or it's a new computer or whatever, they're setting it up. 246 00:12:49,756 --> 00:12:52,906 Okay, like maybe they're downloading a couple megabytes of stuff. 247 00:12:53,206 --> 00:12:57,769 That's going to be slower than You visiting some public website that's 248 00:12:57,769 --> 00:13:02,209 like optimized around like the initial load time, of course, but once that 249 00:13:02,209 --> 00:13:06,789 initial cost is paid, every single interaction that they have going 250 00:13:06,789 --> 00:13:09,599 forward from there is insanely fast. 251 00:13:09,619 --> 00:13:13,589 And that trade off is so worth it for apps that people actually use as a joke. 252 00:13:13,659 --> 00:13:17,699 I like to make out is that the web has become so obsessed with 253 00:13:17,719 --> 00:13:21,849 optimizing for websites where people visit and leave as fast as possible. 254 00:13:22,209 --> 00:13:25,284 I'm like, If you're working on something like that, totally get it. 255 00:13:25,304 --> 00:13:27,894 Like totally get all the, the SSR stuff. 256 00:13:27,914 --> 00:13:31,434 Everyone's obsessed with all the, like the infinite levels of like CDN caching 257 00:13:31,434 --> 00:13:32,514 and the little optimizations there. 258 00:13:32,514 --> 00:13:35,864 I totally understand that, like minimizing bundle size, all that stuff. 259 00:13:36,314 --> 00:13:38,694 But a lot of people work on SaaS products. 260 00:13:38,724 --> 00:13:42,788 Most of the products that I use every day are not, don't fit in that category. 261 00:13:42,788 --> 00:13:45,418 I'm using them every day, like just preload stuff for me. 262 00:13:45,418 --> 00:13:48,068 And I feel this way about some of the biggest products, right? 263 00:13:48,068 --> 00:13:49,238 Like think about GitHub. 264 00:13:49,408 --> 00:13:51,988 I'm an open source developer, like, my day to day job is 265 00:13:52,008 --> 00:13:53,508 maintaining open source projects. 266 00:13:53,868 --> 00:13:57,498 I'm in GitHub all day, clicking through issues, looking through 267 00:13:57,498 --> 00:13:58,938 commits, looking at PRs. 268 00:13:59,328 --> 00:14:03,458 It is so frustratingly slow how almost every single interaction 269 00:14:04,038 --> 00:14:05,388 results in like a page load. 270 00:14:05,748 --> 00:14:09,748 GitHub knows, okay, you're not going to send me all of GitHub to me locally. 271 00:14:10,118 --> 00:14:13,198 But you know there's these three repos I work on every single day. 272 00:14:13,703 --> 00:14:15,483 Sync that locally, sync that optimistically. 273 00:14:15,493 --> 00:14:19,033 Like that would save me so much time and frustration and energy. 274 00:14:19,173 --> 00:14:20,213 And actually scratch that. 275 00:14:20,223 --> 00:14:21,353 It's not really about the time. 276 00:14:21,393 --> 00:14:22,873 It's really about the energy for me. 277 00:14:22,973 --> 00:14:27,013 You can spend four hours doing work that saps your energy and four 278 00:14:27,013 --> 00:14:28,393 hours where you feel empowered. 279 00:14:28,443 --> 00:14:30,913 And to me, like good apps like this. 280 00:14:31,423 --> 00:14:33,803 I like feel super empowered and it's not sapping my energy. 281 00:14:33,803 --> 00:14:35,483 I'm not drained after the four hours. 282 00:14:35,623 --> 00:14:37,273 I'm like ready to go on to my next thing. 283 00:14:37,273 --> 00:14:37,543 Right. 284 00:14:37,973 --> 00:14:40,773 And yeah, some of these biggest apps that are productivity apps are so 285 00:14:40,783 --> 00:14:42,723 built like traditional websites. 286 00:14:43,533 --> 00:14:44,083 Definitely. 287 00:14:44,113 --> 00:14:44,403 Yeah. 288 00:14:44,403 --> 00:14:47,093 I mean, the, the use case that you've mentioned in regards to 289 00:14:47,113 --> 00:14:49,743 GitHub is, is an excellent example. 290 00:14:49,753 --> 00:14:51,813 Like for, like you have those. 291 00:14:52,163 --> 00:14:58,523 units that are really self contained, most repos don't have hundred of thousand 292 00:14:58,523 --> 00:15:03,418 of issues it's really easy, like takes roughly the same amount of data that 293 00:15:03,438 --> 00:15:08,334 like your initial JavaScript bundles took to just download the entire, thing as a 294 00:15:08,334 --> 00:15:13,034 SQLite database or like in another format, and then just have it there available. 295 00:15:13,224 --> 00:15:17,484 Since you're navigating so much within the scope of a GitHub repo, whether 296 00:15:17,484 --> 00:15:21,999 it's Between GitHub issues or going to like a pull request or something 297 00:15:22,259 --> 00:15:27,439 and whatever paper cuts you experience there, it really lowers your effort 298 00:15:27,439 --> 00:15:29,389 of like wanting to go the extra mile. 299 00:15:29,409 --> 00:15:32,879 Whether you want to respond to someone's like, in a GitHub comment. 300 00:15:33,129 --> 00:15:37,659 I think, uh, Jamie Kyle, actually, I think he ran a couple of experiments 301 00:15:37,659 --> 00:15:43,109 there that's literally faster on GitHub to open a new tab for a link and have, 302 00:15:43,119 --> 00:15:46,934 get the server side rendered stuff than dealing with like the, The, the rail 303 00:15:46,944 --> 00:15:50,114 style in navigation on the existing site. 304 00:15:50,194 --> 00:15:53,314 And that speaks exactly to, to the symptoms that you've, 305 00:15:53,404 --> 00:15:54,394 that you've described. 306 00:15:54,594 --> 00:15:57,194 I will also call out a project. 307 00:15:57,214 --> 00:16:00,514 I don't fully remember the name anymore, but someone on Twitter, I 308 00:16:00,524 --> 00:16:05,894 think was working on, on exactly that, like a little GitHub client that is 309 00:16:05,894 --> 00:16:10,484 local-first inspired, that pulls down your data that you're dealing with to 310 00:16:10,484 --> 00:16:12,224 make exactly these interactions fast. 311 00:16:12,224 --> 00:16:13,124 Maybe you know the name. 312 00:16:13,409 --> 00:16:15,479 Yeah, so I actually tweeted asking about this. 313 00:16:15,479 --> 00:16:17,099 I remember seeing it and I couldn't remember it. 314 00:16:17,099 --> 00:16:20,429 And I think it was, uh, by Devin, the Parcel JS. 315 00:16:20,999 --> 00:16:22,789 Yeah, so I saw him messing around with that. 316 00:16:22,789 --> 00:16:26,849 I don't know if he ever, like, finished it or released it or anything, but 317 00:16:26,849 --> 00:16:29,079 yeah, this is so desperately needed. 318 00:16:29,584 --> 00:16:32,294 GitHub isn't going to do it, I don't think, because it's so outside the 319 00:16:32,294 --> 00:16:33,494 scope of how their system works. 320 00:16:33,524 --> 00:16:36,994 But just someone, please, just build a thing that syncs the 321 00:16:36,994 --> 00:16:39,494 issues and PRs optimistically. 322 00:16:39,494 --> 00:16:40,854 And you're going to save me so much. 323 00:16:40,884 --> 00:16:42,424 I'll pay for this product easily. 324 00:16:42,424 --> 00:16:45,304 I don't know how big the market is for people that care this much, but it 325 00:16:45,304 --> 00:16:48,894 doesn't seem like that much work because it's just a single repository view 326 00:16:48,894 --> 00:16:50,464 and some of the stuff that's in there. 327 00:16:51,224 --> 00:16:52,164 And you could totally do this. 328 00:16:52,204 --> 00:16:52,664 Yeah. 329 00:16:53,284 --> 00:16:54,604 This is kind of what I was saying before. 330 00:16:54,909 --> 00:16:57,419 I'm mostly speaking as a developer, like building these things. 331 00:16:57,449 --> 00:17:00,869 But the end thing I care about is as a user. 332 00:17:01,314 --> 00:17:03,604 I just want more of this stuff out there in the world. 333 00:17:03,604 --> 00:17:04,674 So I'm not as frustrated. 334 00:17:04,994 --> 00:17:06,044 I definitely agree. 335 00:17:06,044 --> 00:17:10,464 And like, I applaud you for like going that adventurous path and that extra 336 00:17:10,464 --> 00:17:16,444 mile with SST console, since I think you had the right intuition there and it is 337 00:17:16,484 --> 00:17:21,924 paying off in terms of just how fast that feels to use and how much, like you say, 338 00:17:21,924 --> 00:17:23,784 like it no longer drains your energy. 339 00:17:23,784 --> 00:17:23,944 Yeah. 340 00:17:24,059 --> 00:17:26,009 It gives you energy using that. 341 00:17:26,409 --> 00:17:30,879 And once you had that experience, you'd really like every loading spinner 342 00:17:30,889 --> 00:17:34,879 that you see is so much more painful afterwards when you're like using, 343 00:17:35,059 --> 00:17:38,129 for example, the, Cloudflare console, it's like the same thing there. 344 00:17:38,129 --> 00:17:41,869 Like you're within a project , you have that many deployed workers and 345 00:17:41,869 --> 00:17:43,819 you just want to navigate between that. 346 00:17:43,819 --> 00:17:46,049 It's fine that my logs stream in. 347 00:17:46,379 --> 00:17:49,539 But all the metadata around that should just be instant. 348 00:17:49,719 --> 00:17:52,209 It's a tiny amount of data. 349 00:17:52,239 --> 00:17:55,819 And like the majority of apps, if you really look at what data people are 350 00:17:55,819 --> 00:17:57,699 constantly going between, it is so small. 351 00:17:58,239 --> 00:18:02,889 So yeah, you figured out like the, the patterns early on or rather that you've 352 00:18:02,919 --> 00:18:06,319 realized, okay, you started with a bit of caching, a bit of more caching, a 353 00:18:06,319 --> 00:18:10,349 bit of more caching, and you didn't quite find the right line to draw. 354 00:18:10,409 --> 00:18:11,459 So you just, okay. 355 00:18:11,559 --> 00:18:13,939 We're going to just bring over all the data. 356 00:18:14,289 --> 00:18:18,659 Did you have other sort of learnings where you had to rewire your brain? 357 00:18:19,026 --> 00:18:19,396 Yeah. 358 00:18:19,396 --> 00:18:24,633 So I think, uh, one other middle step we had was we tried it through GraphQL. 359 00:18:24,743 --> 00:18:28,253 We weren't particularly interested in the GraphQL part. 360 00:18:28,373 --> 00:18:32,213 It was, it just happened to be that, uh, Urql, the GraphQL client. 361 00:18:32,983 --> 00:18:36,768 It implemented a lot of, uh, the local-first stuff like you could 362 00:18:37,028 --> 00:18:40,168 replicate the whole database locally and because GraphQL has a 363 00:18:40,168 --> 00:18:44,331 nice, idea of like relationships between objects, the data format 364 00:18:44,331 --> 00:18:45,631 locally could be pretty intelligent. 365 00:18:45,631 --> 00:18:48,838 like, downloaded 1 thing, it knows how it's related to another thing. 366 00:18:48,838 --> 00:18:52,048 So if you query it from a different path, it can, like, resolve it locally. 367 00:18:52,158 --> 00:18:53,928 So there's just some clever things that it did. 368 00:18:54,108 --> 00:18:55,358 And we thought that was really cool. 369 00:18:55,778 --> 00:19:00,558 But what ended up sucking was we didn't really like GraphQL. 370 00:19:01,118 --> 00:19:06,428 And everything you did, even local operations, required GraphQL as input. 371 00:19:06,838 --> 00:19:07,888 which again is fine. 372 00:19:07,898 --> 00:19:10,308 It's just, it just wasn't really clicking for us. 373 00:19:10,358 --> 00:19:15,326 And again, it still had this, uh, There was a limitation of like, it 374 00:19:15,326 --> 00:19:19,116 wasn't really meant or initially designed to have all data locally, 375 00:19:19,116 --> 00:19:22,206 so it's all like, there's always like some stealing or some performance 376 00:19:22,206 --> 00:19:23,876 issue or something you run into. 377 00:19:24,346 --> 00:19:28,256 So when we went all in on having, okay, like we, the system is primarily 378 00:19:28,256 --> 00:19:30,056 designed around syncing the data locally. 379 00:19:30,306 --> 00:19:34,376 What we found actually, and I think the Linear people talk about this too, is. 380 00:19:34,524 --> 00:19:38,124 The developer experience around this became a lot more simple. 381 00:19:38,374 --> 00:19:42,994 So my wife, who I work on this stuff with, she is not an engineer. 382 00:19:43,004 --> 00:19:44,724 She does everything else outside of it. 383 00:19:44,824 --> 00:19:48,554 But in the past couple of months, we're like, why are we drawing that boundary? 384 00:19:48,554 --> 00:19:50,334 Just learn how to be more hands on. 385 00:19:50,774 --> 00:19:53,504 And so she's been learning like how to actually like write the code 386 00:19:53,504 --> 00:19:56,394 and build these things and she's making like fantastic progress. 387 00:19:56,924 --> 00:20:00,004 One of the things that's been crazy helpful is. 388 00:20:00,554 --> 00:20:01,964 All the data's just there locally. 389 00:20:02,364 --> 00:20:05,844 So for her, even though she's a beginner, it's such a simple model. 390 00:20:05,864 --> 00:20:10,014 She's not like figuring out the round trip with the server, like syncing all that. 391 00:20:10,014 --> 00:20:14,064 Like, I handle all that, and I make sure, like I figure out how the data looks like 392 00:20:14,064 --> 00:20:16,624 on the back end, and I make sure it's all synced correctly to the front end. 393 00:20:17,074 --> 00:20:21,864 From there, there's not all this weird like, loading states, or like fetching it, 394 00:20:21,864 --> 00:20:25,404 or like just a whole bunch of complexity around getting data back and forth. 395 00:20:25,829 --> 00:20:28,309 It's solved in one part of your app, and then you never have to 396 00:20:28,309 --> 00:20:29,369 think about it anywhere else. 397 00:20:29,849 --> 00:20:33,029 So just from like a team productivity point of view, like she can build 398 00:20:33,239 --> 00:20:37,629 any feature she wants, even if I didn't like explicitly think about 399 00:20:37,629 --> 00:20:40,759 it from the backend point of view, because she has all the data locally. 400 00:20:41,149 --> 00:20:43,819 She's like, I want to create a view that searches through this set of data. 401 00:20:43,869 --> 00:20:44,679 She can just go do that. 402 00:20:44,699 --> 00:20:45,419 All the data is there. 403 00:20:45,844 --> 00:20:47,144 Very, very straightforward. 404 00:20:47,304 --> 00:20:51,034 And it's actually wild how much of a productivity boost that has on 405 00:20:51,034 --> 00:20:54,364 your team, because you're not like constantly building these like back 406 00:20:54,364 --> 00:20:57,634 and forth with every new feature you're not rebuilding another way to 407 00:20:57,644 --> 00:20:59,004 like sync that data back and forth. 408 00:20:59,494 --> 00:21:00,534 and it's been amazing. 409 00:21:01,204 --> 00:21:02,504 That's so liberating. 410 00:21:02,564 --> 00:21:06,794 Uh, we talked about this also in the recent episode with Kyle, who drew the 411 00:21:06,794 --> 00:21:11,814 comparison of like going from jQuery to React where React freed you up of like 412 00:21:11,824 --> 00:21:15,964 that manual view maintenance and now going from like the, the manual state 413 00:21:15,974 --> 00:21:20,254 transfer across different environments that frees you up of like that data 414 00:21:20,254 --> 00:21:22,004 management and you can now actually. 415 00:21:22,339 --> 00:21:25,949 Focus on what matters most, like building a great user experience 416 00:21:25,969 --> 00:21:29,519 and putting the effort into the pieces that do really matter. 417 00:21:29,899 --> 00:21:35,459 And that simplification that is just so, so hard to overstate how nice that is. 418 00:21:35,539 --> 00:21:38,259 And I think that also unlocks a whole bunch of like new. 419 00:21:38,489 --> 00:21:39,099 tooling. 420 00:21:39,109 --> 00:21:45,297 So for Overtone that I co developed with the project Rffle, or now called 421 00:21:45,297 --> 00:21:48,829 LiveStore, it's always been a first class citizen to have great dev tools. 422 00:21:49,119 --> 00:21:52,509 And one of the parts of the dev tools is to have a data browser in there. 423 00:21:52,779 --> 00:21:56,359 So it basically feels like a Google spreadsheet and really it 424 00:21:56,389 --> 00:21:57,939 also acts as a Google spreadsheet. 425 00:21:57,939 --> 00:22:00,039 You have, you have like visual view. 426 00:22:00,419 --> 00:22:04,079 on all of your data, if you change something such as like a playlist 427 00:22:04,109 --> 00:22:09,269 title in that data browser, it like automatically updates in your app. 428 00:22:09,339 --> 00:22:11,959 And there's no question of like, Oh, do I not need to like 429 00:22:12,219 --> 00:22:14,299 send this to this REST request? 430 00:22:14,309 --> 00:22:18,009 But do I need to also like, Invalidate this in Redis. 431 00:22:18,059 --> 00:22:20,689 No, you just like set the data and there it is. 432 00:22:21,319 --> 00:22:21,919 Yeah, that's great. 433 00:22:21,919 --> 00:22:24,259 I mean, a local data route is actually something that we're definitely 434 00:22:24,259 --> 00:22:29,249 missing, but that's a, yeah, it's like it enables so many things like that. 435 00:22:29,399 --> 00:22:32,899 Just the debug ability and observability of what's going on and just being 436 00:22:32,899 --> 00:22:35,799 able to change something in one place and have it update everywhere, like 437 00:22:35,849 --> 00:22:38,819 in your view and in the backend, it's just so, it's so much simpler. 438 00:22:38,819 --> 00:22:42,359 And it's weird because I feel like apps used to kind of work this way. 439 00:22:42,359 --> 00:22:45,469 Like when I got started, I was building desktop applications. 440 00:22:46,159 --> 00:22:49,516 And I guess there wasn't really a cloud component in some of 441 00:22:49,516 --> 00:22:51,036 the initial things that I built. 442 00:22:51,176 --> 00:22:53,736 And they were this simple because the data was just local and like 443 00:22:53,746 --> 00:22:56,436 you'd hit a button and you like mutate the data and it's it's there. 444 00:22:56,436 --> 00:23:00,006 So yeah, to me it feels like returning to a simplicity with like 445 00:23:00,396 --> 00:23:03,456 much more power and capabilities that we didn't have back then. 446 00:23:03,956 --> 00:23:04,466 Exactly. 447 00:23:04,486 --> 00:23:07,956 Plus we now also get the power of the cloud for collaboration and 448 00:23:07,966 --> 00:23:10,316 like a lot of the, the nice pieces. 449 00:23:10,716 --> 00:23:14,496 But I think there's just been an over investment over the last 10 years 450 00:23:14,806 --> 00:23:19,816 into having everything be so cloud centric that like you built like 451 00:23:19,826 --> 00:23:24,446 even a local calculator probably as like a remote rendered server app. 452 00:23:24,976 --> 00:23:30,426 And, I think now also bringing more investment into kind of back to the roots, 453 00:23:30,536 --> 00:23:35,206 uh, in, in this way of building, building apps, I think this will also help more 454 00:23:35,206 --> 00:23:40,796 people who are not quite as adventurous as you are to, to really explore this before 455 00:23:40,796 --> 00:23:45,286 others do, that this becomes a more viable standard path that people build apps with. 456 00:23:45,841 --> 00:23:48,481 Yeah, and like there are, like a lot of stuff becomes simpler. 457 00:23:48,491 --> 00:23:50,371 There's some new stuff you have to learn, of course, like with 458 00:23:50,371 --> 00:23:52,651 any new paradigm, there's, things that are a little bit different. 459 00:23:52,731 --> 00:23:57,661 I think some of those involve things like, so in our case, in the Bumi example, 460 00:23:57,871 --> 00:24:01,721 we unfortunately had customers that had too much data, where it wasn't as 461 00:24:01,721 --> 00:24:03,151 simple as just syncing it all locally. 462 00:24:03,711 --> 00:24:08,491 So we have to think of like some new kind of like UX related patterns where 463 00:24:08,651 --> 00:24:12,394 we kind of optimistically sync stuff that we think the user will care about. 464 00:24:12,394 --> 00:24:15,494 So like the first time you visit a patient, it might take a little 465 00:24:15,494 --> 00:24:17,914 bit to load because we didn't sync all the patients locally. 466 00:24:18,384 --> 00:24:23,314 We do sync like a shallow version of the patient locally for everyone, so they can 467 00:24:23,324 --> 00:24:24,674 search through all of them really quickly. 468 00:24:25,134 --> 00:24:27,264 But to get into the full details, like you might not. 469 00:24:27,346 --> 00:24:28,826 That's too much data to send to everyone. 470 00:24:29,156 --> 00:24:31,126 So the first time you go there, it'll be a slow load. 471 00:24:31,126 --> 00:24:33,276 But from that point, we kind of flag them as, Oh, this 472 00:24:33,276 --> 00:24:34,716 user cares about this patient. 473 00:24:35,156 --> 00:24:37,006 And from then on, we'll constantly send them updates. 474 00:24:37,256 --> 00:24:40,466 If they haven't visited the patient's profile for like two weeks or 475 00:24:40,466 --> 00:24:43,176 whatever, then we'll kind of unflag it as something that they care about. 476 00:24:43,636 --> 00:24:46,256 These are like new patterns that, you know, they don't really 477 00:24:46,366 --> 00:24:47,266 exist in a traditional app. 478 00:24:47,276 --> 00:24:52,526 But this mixture of local and cloud, you can get pretty far with tricks like that. 479 00:24:52,536 --> 00:24:55,266 And we kind of have to learn some of those tricks and some of those ideas. 480 00:24:55,266 --> 00:24:58,041 Because we have a whole like We have, I forgot what we called it, but 481 00:24:58,041 --> 00:25:02,284 it's like, uh, We have like a system where you can easily flag stuff as 482 00:25:02,284 --> 00:25:03,704 a user is interested in this thing. 483 00:25:03,754 --> 00:25:06,774 And if you flag it, it starts getting synced and then it'll get unsynced 484 00:25:06,844 --> 00:25:08,414 after some window that you specify. 485 00:25:08,484 --> 00:25:10,644 So we kind of have to like, you know, think about that and, and 486 00:25:10,764 --> 00:25:11,824 create a framework around it. 487 00:25:11,824 --> 00:25:12,874 But that's one. 488 00:25:12,874 --> 00:25:15,894 The second thing is like, obviously handling, And this 489 00:25:15,894 --> 00:25:17,104 isn't unique to local-first. 490 00:25:17,124 --> 00:25:20,524 Anywhere you're doing optimistic things, obviously there can be 491 00:25:21,159 --> 00:25:22,929 errors that happen on a delay. 492 00:25:23,049 --> 00:25:24,529 Again, it depends on the type of application. 493 00:25:24,539 --> 00:25:27,639 Like a music player, probably, the syncing is probably like pretty 494 00:25:27,639 --> 00:25:32,384 straightforward, but for something that's Looks more like a traditional SaaS app. 495 00:25:32,434 --> 00:25:36,654 There might be sources of truth that can't be validated entirely locally. 496 00:25:37,204 --> 00:25:40,544 So you'll end up with situations where the user does something, then goes 497 00:25:40,544 --> 00:25:42,444 away, then the error shows up later. 498 00:25:42,464 --> 00:25:46,984 And like, you need like a whole different UX pattern when you can't block the user. 499 00:25:47,304 --> 00:25:50,704 It's worth doing because 99 percent of the time they don't hit that error. 500 00:25:51,014 --> 00:25:52,104 So it's good to let them move on. 501 00:25:52,544 --> 00:25:54,404 But you have to handle a case where, where they do. 502 00:25:54,414 --> 00:25:57,784 So there's different problems that show up, but again, it's all in the name 503 00:25:57,804 --> 00:26:00,004 of a better experience to the user. 504 00:26:00,004 --> 00:26:01,284 So totally worth it. 505 00:26:01,284 --> 00:26:03,678 So, let's say you have some kind of. 506 00:26:03,748 --> 00:26:06,918 You can create a new field that needs to be globally unique in your system. 507 00:26:06,918 --> 00:26:10,438 So let's say, uh, I mean, we can just use Linear as an example. 508 00:26:10,448 --> 00:26:12,888 Like, you can create a new project in Linear, but the name of the 509 00:26:12,888 --> 00:26:14,248 project needs to be unique. 510 00:26:14,658 --> 00:26:19,768 there's an impossibly small chance that you create it and you move on, but someone 511 00:26:19,878 --> 00:26:23,068 had created it at the same time, because they thought it was their job to do it. 512 00:26:23,598 --> 00:26:26,618 And there's like an issue, because your write maybe got rejected. 513 00:26:26,618 --> 00:26:30,893 in a typical UI, when you create the project, you would see a spinner. 514 00:26:31,388 --> 00:26:31,918 Spinning. 515 00:26:32,288 --> 00:26:33,118 Okay, created. 516 00:26:33,468 --> 00:26:36,758 Because you have a spinner there, you can, like, make sure stuff gets written 517 00:26:36,758 --> 00:26:39,638 correctly and then you don't let the spinner come back till you know for sure. 518 00:26:40,208 --> 00:26:40,748 It's good. 519 00:26:41,278 --> 00:26:43,978 Um, so anywhere with this like unique feel type of situation, 520 00:26:43,978 --> 00:26:45,328 we run into this problem. 521 00:26:45,678 --> 00:26:47,128 Our fix is actually pretty simple. 522 00:26:47,128 --> 00:26:49,978 We just have like some kind of like context thing of like pending 523 00:26:50,228 --> 00:26:51,598 stuff that hasn't been confirmed. 524 00:26:52,078 --> 00:26:55,468 And if it comes back with an error, we just pop up a toast that 525 00:26:55,468 --> 00:26:57,038 brings them back to the original. 526 00:26:57,363 --> 00:26:58,733 We, like, reload that original content. 527 00:26:58,773 --> 00:27:01,083 If they want, they can click back and go back to where they were. 528 00:27:01,683 --> 00:27:05,666 And, like, you know, change the issue that they had. 529 00:27:05,999 --> 00:27:08,369 So I think we found that pattern to work pretty well. 530 00:27:08,389 --> 00:27:11,469 Obviously, it's like, the example I gave is really stupid. 531 00:27:11,469 --> 00:27:13,479 Like, no one is ever going to run into that. 532 00:27:14,219 --> 00:27:17,519 There's some examples that are a little less stupid, where it is reasonably 533 00:27:17,519 --> 00:27:18,679 possible that it could happen. 534 00:27:18,679 --> 00:27:22,069 But we found this idea of, like, preserving the context of the 535 00:27:22,079 --> 00:27:23,769 UI and bringing them back to it. 536 00:27:24,484 --> 00:27:26,924 If the error happens, they can opt to go back. 537 00:27:27,228 --> 00:27:28,428 We found that to work pretty well. 538 00:27:28,848 --> 00:27:31,168 Yeah, I think that's a very elegant solution for this. 539 00:27:31,198 --> 00:27:34,938 I mean, another possibly even more aggressive solution to this 540 00:27:35,158 --> 00:27:39,058 would be to say to gate this feature behind being online. 541 00:27:39,418 --> 00:27:44,428 And to actually like establish some notion of like a global transaction for 542 00:27:44,428 --> 00:27:49,984 that and, only let the user pass through this intentional bottleneck if that 543 00:27:49,994 --> 00:27:54,454 has happened, but the way how you've designed this in a asynchronous way. 544 00:27:54,614 --> 00:27:56,084 I think it's also very elegant. 545 00:27:56,084 --> 00:28:00,984 but I think this is the nice thing that like local-first affords you or forces 546 00:28:01,004 --> 00:28:05,014 you to do is like, it frees you up from a whole bunch of stuff you no longer 547 00:28:05,014 --> 00:28:09,234 need to do, but it really forces you to think about carefully, what are the 548 00:28:09,234 --> 00:28:12,954 domain requirements of your specific app? 549 00:28:13,319 --> 00:28:16,969 And if your domain expert from the app says like, Hey, this is 550 00:28:16,969 --> 00:28:18,319 what's really important here. 551 00:28:18,319 --> 00:28:22,649 There cannot be two project names with the same exact name. 552 00:28:23,049 --> 00:28:26,849 Then like you can actually put in the extra efforts to enforcing that. 553 00:28:27,309 --> 00:28:29,679 And this is what makes the app worth it later. 554 00:28:29,809 --> 00:28:30,179 Yeah. 555 00:28:30,249 --> 00:28:30,439 Yeah. 556 00:28:30,439 --> 00:28:31,659 And it's, yeah, it's not all or nothing. 557 00:28:31,659 --> 00:28:32,259 You can opt in. 558 00:28:32,259 --> 00:28:34,179 So the thing that you said, we are in the SC console. 559 00:28:34,179 --> 00:28:37,059 We do that when you're creating a new workspace, we actually do have a 560 00:28:37,059 --> 00:28:41,349 spinner there because it's like weird to like, Create a new workspace and get 561 00:28:41,349 --> 00:28:42,849 kicked back 'cause the name was taken. 562 00:28:43,239 --> 00:28:45,489 So yeah, we, we hold you there And that's like, you know, a more 563 00:28:45,489 --> 00:28:49,039 traditional experience and that's fine 'cause that's like a very small 564 00:28:49,039 --> 00:28:53,049 percentage of the app where you're like creating a new workspace. 565 00:28:53,049 --> 00:28:55,449 You do that once when you sign up and you never do that again. 566 00:28:55,999 --> 00:28:59,239 So yeah, you can kind of granularly pick where you want a more traditional 567 00:28:59,239 --> 00:29:02,149 blocking approach and where you want an optimistic approach. 568 00:29:02,419 --> 00:29:05,579 And I think a lot of the people that are maybe skeptical of the local-first 569 00:29:05,599 --> 00:29:09,399 thing, I think they tend to imagine it in these extremes of like. 570 00:29:09,874 --> 00:29:12,494 You have to sync all of your data and obviously that won't work. 571 00:29:12,494 --> 00:29:14,774 Or like you have to have everything be optimistic and obviously 572 00:29:14,774 --> 00:29:18,184 everything can't be optimistic, but you can really pick and choose. 573 00:29:18,184 --> 00:29:20,374 It's more about what you default to. 574 00:29:20,384 --> 00:29:23,094 And then you opt out of It's good to default to optimistic first. 575 00:29:23,094 --> 00:29:24,274 Cause that's, what's great for the user. 576 00:29:24,454 --> 00:29:24,874 Right. 577 00:29:25,274 --> 00:29:29,424 I think in the, in your context of building SaaS apps, I think there's 578 00:29:29,424 --> 00:29:31,114 kind of layers to this entire thing. 579 00:29:31,114 --> 00:29:33,084 There's like the global system. 580 00:29:33,359 --> 00:29:34,799 That you're still in control of. 581 00:29:34,809 --> 00:29:40,239 That global system is probably not local-first by all the ideals, but once 582 00:29:40,239 --> 00:29:44,939 you create an account or once you've created a project, and now you enter like 583 00:29:44,939 --> 00:29:49,859 a smaller scope of that overall system, and that now is very much local-first 584 00:29:50,089 --> 00:29:51,769 because this is where it actually matters. 585 00:29:51,789 --> 00:29:54,049 It's okay if your users sign up. 586 00:29:54,254 --> 00:29:56,434 takes half a second to load. 587 00:29:56,724 --> 00:29:59,674 But once you're in your productivity environment, this is where you 588 00:29:59,674 --> 00:30:03,194 want to really have unlock the benefits that local-first gives you. 589 00:30:03,614 --> 00:30:04,234 Yeah, exactly. 590 00:30:04,234 --> 00:30:06,134 The data, what is the day to day workflow like? 591 00:30:06,134 --> 00:30:09,564 And that should be, that should be, you know, an excellent experience. 592 00:30:09,814 --> 00:30:15,694 I think the other area, and we talked about this a little, is there's also the 593 00:30:15,694 --> 00:30:20,644 desire for apps that don't die because a company went out of business or like, 594 00:30:20,654 --> 00:30:23,354 you know, They were forced to find a business model that didn't make sense 595 00:30:23,354 --> 00:30:24,914 for the idea that they were working on. 596 00:30:25,524 --> 00:30:27,464 And I think this does make a lot of sense, I think. 597 00:30:27,814 --> 00:30:30,624 If you think about something like a, like a video game. 598 00:30:30,624 --> 00:30:33,924 I mean, video games are different now, but like, you know, there was a time 599 00:30:33,924 --> 00:30:35,484 where you would buy the video game. 600 00:30:35,514 --> 00:30:39,214 It was a finished product, and it was on, like, a physical thing, and 601 00:30:39,214 --> 00:30:40,584 you could just run it and play it. 602 00:30:41,254 --> 00:30:41,854 And. 603 00:30:42,379 --> 00:30:43,509 You had that forever. 604 00:30:43,929 --> 00:30:47,479 So, but I mean, now you have like some games that require you to be online 605 00:30:47,479 --> 00:30:48,989 or it's a, it's a hybrid of both. 606 00:30:48,989 --> 00:30:53,249 And like, you can imagine how at some point this game won't be playable anymore. 607 00:30:53,249 --> 00:30:55,009 And that's happened to a few things. 608 00:30:55,169 --> 00:30:57,329 I think people feel that way about applications as well. 609 00:30:57,329 --> 00:30:58,189 And I totally get that. 610 00:30:58,659 --> 00:31:02,009 I personally don't work on anything where that's like the critical 611 00:31:02,173 --> 00:31:06,313 burning desire where like, you want it to like really run locally. 612 00:31:06,313 --> 00:31:08,603 You want, you care about the privacy, you care about whatever. 613 00:31:08,963 --> 00:31:10,353 I like totally get all of that. 614 00:31:10,383 --> 00:31:13,673 It just hasn't intersected with like the areas that I focus on. 615 00:31:13,843 --> 00:31:18,033 So for me, it's been more about, uh, just the experience side of it. 616 00:31:18,213 --> 00:31:22,263 And I think the reason is a little bit tricky to go to that extreme in SaaS. 617 00:31:22,818 --> 00:31:27,674 is a lot of like a portion of your value is in the end experience. 618 00:31:27,684 --> 00:31:30,044 And like we talked about, I think people are under delivering there, 619 00:31:30,364 --> 00:31:35,574 but usually it's also tapping into some kind of bigger data set or bigger 620 00:31:35,574 --> 00:31:38,214 capability that can't really run locally. 621 00:31:38,244 --> 00:31:39,864 So it's usually a mix of the two things. 622 00:31:40,084 --> 00:31:43,378 So I typically will have to mutate the data outside of 623 00:31:43,378 --> 00:31:44,588 the user interacting with it. 624 00:31:44,598 --> 00:31:47,468 So if you look at something like, uh, like Radiance, so this is 625 00:31:47,488 --> 00:31:48,798 going to be a personal finance app. 626 00:31:49,028 --> 00:31:51,678 You can totally build a fully local-first version of this 627 00:31:51,688 --> 00:31:52,838 that runs entirely locally. 628 00:31:53,278 --> 00:31:55,738 That whoever's building the app, it can be totally encrypted where they don't even 629 00:31:55,738 --> 00:31:57,368 have access to seeing any of this stuff. 630 00:31:57,368 --> 00:31:59,238 And there's like value in building something like that. 631 00:31:59,668 --> 00:32:04,801 But, you know, with all these advancements in AI and LLMs, those can actually impact 632 00:32:05,151 --> 00:32:08,821 Personal finance apps a lot in terms of like making sure that data is cleaned 633 00:32:08,821 --> 00:32:11,941 up correctly, auto categorizing, like all the things that sucked historically 634 00:32:11,941 --> 00:32:16,808 about these applications, LMS have a lot of potential to fix that, but 635 00:32:17,288 --> 00:32:20,538 there's not really a good way to do that in a local-first way, at least today. 636 00:32:20,768 --> 00:32:23,008 So that's why for us, you know, for building this thing, 637 00:32:23,018 --> 00:32:24,438 it's not going to be this. 638 00:32:25,068 --> 00:32:27,438 thing that runs entirely locally because we still want the ability to 639 00:32:27,438 --> 00:32:31,848 like process your data using tools and technologies that, you know, 640 00:32:32,158 --> 00:32:34,238 unfortunately can't run locally today. 641 00:32:34,618 --> 00:32:38,198 Yeah, I think you've touched on a couple of really interesting points there. 642 00:32:38,218 --> 00:32:43,608 So the, I think right now, the canonical definition of like, what is local-first 643 00:32:43,628 --> 00:32:48,568 software is as according to the Ink and Switch essay that lays out the seven 644 00:32:48,598 --> 00:32:53,298 ideals of local-first and I think you're, You're, nicely sticking to the first four, 645 00:32:53,298 --> 00:32:57,228 which is like about the loading spinners and that it works offline and so on. 646 00:32:57,528 --> 00:33:01,738 And I think what you've just hinted at, what you don't do yet is what 647 00:33:01,738 --> 00:33:07,138 local-first calls like the long now that your app like lives on, even if the 648 00:33:07,168 --> 00:33:09,468 creators are no longer working on it. 649 00:33:09,748 --> 00:33:11,138 And that's very understandable. 650 00:33:11,158 --> 00:33:14,548 That takes a lot of time to, and effort to put into. 651 00:33:14,883 --> 00:33:17,983 And given that you just have so much time to work on the app, 652 00:33:18,193 --> 00:33:19,783 that is not your highest priority. 653 00:33:19,973 --> 00:33:25,003 However, what I think is still nice and a glimmer of hope there for the entire 654 00:33:25,003 --> 00:33:30,323 category of local-first inspired software is that if at some point you say like, 655 00:33:30,333 --> 00:33:36,233 okay, I'm winding down development on this app, then you could still much more 656 00:33:36,233 --> 00:33:38,203 easily to put in a bit of extra effort. 657 00:33:38,748 --> 00:33:42,828 to now round up the project in a local-first way. 658 00:33:42,868 --> 00:33:46,818 I think we've seen a really nice example of that with another personal finance 659 00:33:46,838 --> 00:33:49,348 app called Actual Budget by James Long. 660 00:33:49,938 --> 00:33:56,428 And so as he no longer had time to work on that project, it was so much easier now 661 00:33:56,428 --> 00:34:00,788 to transition the app from something that he hosted as a cloud service to something 662 00:34:00,788 --> 00:34:02,538 that people can just run by themselves. 663 00:34:02,998 --> 00:34:07,898 If you build like those monstrosities of like giant Kubernetes cloud things, 664 00:34:08,178 --> 00:34:13,828 it's really, really hard to like, tell someone how to easily just download a DMG 665 00:34:13,848 --> 00:34:18,368 and run this on your MacBook, whereas if your app is local-first to begin with. 666 00:34:18,608 --> 00:34:23,181 Then, I think it's much easier to repackage the app that you've built. 667 00:34:23,551 --> 00:34:26,671 And you can trim away a lot of like the multi tenant stuff that 668 00:34:26,671 --> 00:34:30,921 you need about SaaS and just package the, the productivity 669 00:34:30,921 --> 00:34:32,991 aspect of the core of your app. 670 00:34:33,081 --> 00:34:39,141 And then I think it's actually quite nice and easy to achieve lasting software. 671 00:34:39,771 --> 00:34:40,671 Yeah, I agree. 672 00:34:40,671 --> 00:34:41,171 I think so. 673 00:34:41,171 --> 00:34:44,341 And with Radiant, we're actually, so because we can't. 674 00:34:44,523 --> 00:34:46,923 Do this thing where it's like end to end encrypted and because of 675 00:34:46,923 --> 00:34:51,533 what, what our goals are, instead, we're making it dead simple to 676 00:34:51,533 --> 00:34:54,753 fully run the whole system yourself. 677 00:34:54,793 --> 00:34:58,473 If you care about hosting yourself and you want all the data and a big part, and to 678 00:34:58,473 --> 00:35:00,613 be honest, that's a lot of what SST does. 679 00:35:00,613 --> 00:35:05,003 SST helps you ship very complex software multiple times in multiple environments. 680 00:35:05,513 --> 00:35:09,513 and so, because Radiant is an SST app, it is very easy to point it 681 00:35:09,543 --> 00:35:12,633 at your own private infrastructure and say, I'm just going to have 682 00:35:12,633 --> 00:35:14,373 a self hosted version of this. 683 00:35:14,383 --> 00:35:18,744 And it's, and we're making sure it's like, As simple as it can be to do 684 00:35:18,744 --> 00:35:23,124 that, and get as close to, like, using the hosted version because there's 685 00:35:23,124 --> 00:35:24,674 like some weird benefits of that. 686 00:35:24,674 --> 00:35:28,114 Like, so this version that we're building is going to be mostly built on Cloudflare. 687 00:35:28,464 --> 00:35:31,084 If a lot of people end up self hosting it, that's great because 688 00:35:31,104 --> 00:35:33,624 Cloudflare is paying for the usage. 689 00:35:33,624 --> 00:35:37,389 Like, The free tier is coming out of each individual's deployment. 690 00:35:37,429 --> 00:35:39,299 They're like self deploying it into CloudFlare. 691 00:35:39,509 --> 00:35:42,409 And that's like an interesting model for, I don't think for radiant, it's 692 00:35:42,409 --> 00:35:45,673 like particularly interesting, but if you look at, um, there's another 693 00:35:45,673 --> 00:35:49,933 project by, uh, Ben Vinegar, he works at Sentry, called CounterScale. 694 00:35:50,473 --> 00:35:54,073 So this is a classic, like Google analytics type product, right? 695 00:35:54,073 --> 00:35:57,003 It does like this web analytics, the basics, and it's very early on. 696 00:35:57,543 --> 00:35:59,033 But it's not a hosted project. 697 00:35:59,043 --> 00:36:01,463 It's just something that deploys into your own CloudFlare account. 698 00:36:01,873 --> 00:36:05,283 So he can have a million users using it for free without ever 699 00:36:05,283 --> 00:36:08,823 really, you know, paying for that because, you know, CloudFlare is 700 00:36:08,823 --> 00:36:10,793 much more set up to offer that. 701 00:36:11,093 --> 00:36:12,813 I'm very interested in that model. 702 00:36:12,853 --> 00:36:14,803 Uh, cause I think for a lot of infrastructure pieces 703 00:36:14,803 --> 00:36:15,873 like that, it is a nice. 704 00:36:16,191 --> 00:36:18,221 To have it alongside the rest of your infrastructure. 705 00:36:18,411 --> 00:36:21,321 I worked a lot in healthcare environment, which has a lot 706 00:36:21,321 --> 00:36:23,461 of compliance requirements. 707 00:36:23,761 --> 00:36:26,991 And oftentimes I couldn't use the tool I wanted to use because it 708 00:36:26,991 --> 00:36:29,191 wasn't hostable in my own environment. 709 00:36:29,191 --> 00:36:33,061 So, um, we're pretty excited about like letting people do more of that. 710 00:36:33,791 --> 00:36:34,471 I love that. 711 00:36:34,501 --> 00:36:37,661 And I think this is like intuitively. 712 00:36:37,944 --> 00:36:42,474 It should be easy to self host your own software, like whether it's like 713 00:36:42,484 --> 00:36:46,564 some company running it or whether I just like take the software, put 714 00:36:46,564 --> 00:36:52,148 it on my Raspberry Pi, put it on, on Cloudflare or AWS, but in reality, 715 00:36:52,168 --> 00:36:53,628 that's very much the exception. 716 00:36:54,058 --> 00:36:57,128 I'd be curious whether you can share a bit more of like the reasons that 717 00:36:57,138 --> 00:37:00,868 you see why that's so hard and how you're trying to make that easier. 718 00:37:01,413 --> 00:37:05,663 Yeah, I think, uh, it's funny because there's a weird alignment 719 00:37:05,673 --> 00:37:06,873 if you think about this. 720 00:37:07,043 --> 00:37:08,313 We are a small team. 721 00:37:08,583 --> 00:37:11,703 If our system is really complicated to run, that sucks for us. 722 00:37:12,013 --> 00:37:15,543 If we can make our system really easy to run and really low overhead and we care 723 00:37:15,543 --> 00:37:18,773 about that more than everything, it kind of starts to look like something that's 724 00:37:18,773 --> 00:37:21,073 easy to self host by anyone, right? 725 00:37:21,073 --> 00:37:24,873 So I think for us, like, a lot of times we'll choose architectures that look 726 00:37:24,883 --> 00:37:28,904 weird because they're like, Oh, that looks like the fourth option on the list 727 00:37:28,904 --> 00:37:30,334 of the ways they could have built it. 728 00:37:30,804 --> 00:37:37,898 But it's because we really, really care about, low operation overhead long term. 729 00:37:38,088 --> 00:37:41,278 So even if it's like, you know, 20 percent harder to build up front, if 730 00:37:41,278 --> 00:37:46,008 it results in like less babysitting on our end, we'll like choose that option. 731 00:37:46,218 --> 00:37:49,818 And it's because we're very committed to continuing to be a really small team. 732 00:37:49,898 --> 00:37:52,858 And so we'll, we'll end up picking those options and those options happen 733 00:37:52,858 --> 00:37:57,118 to align with like, what's, what's simplest for, for the end end user, 734 00:37:57,118 --> 00:38:00,928 if they're self hosting, I will say like there is a version of doing 735 00:38:00,928 --> 00:38:03,018 this, which we don't do, which is. 736 00:38:03,883 --> 00:38:06,943 Building your stuff in the most, like, neutral way possible, so it 737 00:38:06,943 --> 00:38:08,563 can run in literally any environment. 738 00:38:09,003 --> 00:38:14,403 I definitely get that, but you do end up having to run a lot of 739 00:38:14,443 --> 00:38:18,053 infrastructure on your own to, like, get any complicated application working. 740 00:38:18,233 --> 00:38:20,093 If you do it in a totally neutral way. 741 00:38:20,493 --> 00:38:24,833 We kind of picked a middle ground where it's like, we do rely a lot on, like, 742 00:38:24,863 --> 00:38:28,448 in this example, like, we're going to be using CloudFlare, we're going to be using 743 00:38:28,448 --> 00:38:29,913 workers, we're going to be using their queues, we're going to be using their 744 00:38:29,933 --> 00:38:31,693 PubSub, all the CloudFlare native things. 745 00:38:32,088 --> 00:38:37,218 So, yeah, if you want to go take that and run it inside, like, just 746 00:38:37,218 --> 00:38:40,258 a standard server you have, it's going to be a little bit challenging. 747 00:38:40,518 --> 00:38:42,968 And like, there are adapters and stuff, and you can figure that out. 748 00:38:43,428 --> 00:38:49,078 But we're starting with just making it runnable in your own cloud environment. 749 00:38:49,078 --> 00:38:51,418 So you can sign up for a Cloudflare account and run it. 750 00:38:51,938 --> 00:38:54,448 I know that doesn't like hit the exact extreme of like being able 751 00:38:54,448 --> 00:38:57,028 to fully run it yourself, but we think it's like a nice middle ground 752 00:38:57,038 --> 00:38:58,798 for a lot of companies, right? 753 00:38:58,848 --> 00:39:01,298 Companies typically are already using some form of this. 754 00:39:01,888 --> 00:39:03,778 Getting this stuff deployed into their own account. 755 00:39:03,868 --> 00:39:05,188 I think it works well. 756 00:39:05,498 --> 00:39:08,588 What's weird is you ask, like, why isn't this more common? 757 00:39:08,958 --> 00:39:13,118 I think it's actually common in this weird way that people don't expect. 758 00:39:13,213 --> 00:39:16,573 A lot of companies build SaaS software, right? 759 00:39:16,593 --> 00:39:20,023 They'll build like, I don't know, let's say, let's take some random common 760 00:39:20,023 --> 00:39:21,663 thing, like Auth as a service, right? 761 00:39:21,753 --> 00:39:25,143 Like, I'm going to build Auth as a service that people can use. 762 00:39:25,143 --> 00:39:28,333 And they initially launched that as like a hosted product. 763 00:39:28,923 --> 00:39:32,203 And nobody uses it except for people that have no money. 764 00:39:32,643 --> 00:39:35,323 So they have like a lot of users, but you know, these users don't pay a lot. 765 00:39:35,993 --> 00:39:38,213 They start to try to move up, up market. 766 00:39:38,556 --> 00:39:40,656 They end up with bigger companies, you know, medium sized 767 00:39:40,686 --> 00:39:42,096 companies, enterprise companies. 768 00:39:42,473 --> 00:39:45,983 They'll all love the product, but refuse to use a hosted service. 769 00:39:46,543 --> 00:39:49,493 So then they're forced to figure out how to make their stuff run 770 00:39:49,753 --> 00:39:51,943 inside the customer's AWS accounts. 771 00:39:52,313 --> 00:39:54,463 So if you do look at a lot of these companies, they kind of 772 00:39:54,463 --> 00:39:57,363 do have this hidden, like thing that they eventually figured out. 773 00:39:57,813 --> 00:40:00,633 I think companies should realize they're going to end up in this place anyway. 774 00:40:00,703 --> 00:40:04,953 Like it's very hard to build a big business purely off of a hosted thing. 775 00:40:04,963 --> 00:40:08,273 Like some people do it when you really have like a large market, 776 00:40:08,493 --> 00:40:09,623 but oftentimes you're forced to. 777 00:40:09,841 --> 00:40:11,671 Bring yourself inside someone else's environment. 778 00:40:11,671 --> 00:40:14,351 So I think one way or another, you're likely to hit that. 779 00:40:14,361 --> 00:40:17,281 So it's good to plan for that upfront and assume that you're going to run into that. 780 00:40:17,461 --> 00:40:20,461 And we, because we're like, We're more in the infrastructure space. 781 00:40:20,461 --> 00:40:23,441 We kind of expected that from the beginning, which is why we care a little 782 00:40:23,441 --> 00:40:25,921 bit more about making all that possible. 783 00:40:26,611 --> 00:40:32,021 So let's imagine I want to follow this paradigm for Overtone. 784 00:40:32,071 --> 00:40:35,781 And I do think that Cloudflare could be a very interesting fit for that in 785 00:40:35,781 --> 00:40:41,111 terms of the modern primitives that it provides, so what would I need to do as 786 00:40:41,121 --> 00:40:45,091 the application developer of Overtone who buys into that vision and says 787 00:40:45,101 --> 00:40:49,421 like, Hey, I don't want to operate like the cloud thing for that, but I want 788 00:40:49,421 --> 00:40:54,031 to empower every user to deploy their own for the benefits that it provides. 789 00:40:54,511 --> 00:40:58,421 What would I as the application developer need to do to make that happen? 790 00:40:58,781 --> 00:41:00,501 And then also follow up question. 791 00:41:00,561 --> 00:41:04,831 What does someone who wants to deploy that Which sort of additional stuff 792 00:41:04,831 --> 00:41:08,391 do they need to deal with as opposed to just using something like Spotify? 793 00:41:08,741 --> 00:41:09,101 Yeah. 794 00:41:09,141 --> 00:41:09,401 Yeah. 795 00:41:09,401 --> 00:41:09,701 Cool. 796 00:41:09,711 --> 00:41:13,348 So I think, I think the simplest way to think about it is how hard is it you 797 00:41:13,348 --> 00:41:17,048 for you to spin up a staging environment for your own application, right? 798 00:41:17,158 --> 00:41:20,648 You want to create an exact copy of your environment, but you 799 00:41:20,648 --> 00:41:22,108 know, just the staging version. 800 00:41:22,348 --> 00:41:24,468 So this requires bringing up all the same infrastructure. 801 00:41:24,478 --> 00:41:27,058 It requires like, you know, running your database migrations 802 00:41:27,058 --> 00:41:28,138 to get the schemas running. 803 00:41:28,158 --> 00:41:29,598 Um, requires a bunch of things. 804 00:41:29,758 --> 00:41:32,528 And, you know, the obvious thing is you should be using infrastructure 805 00:41:32,528 --> 00:41:33,748 as code to help you do this. 806 00:41:33,748 --> 00:41:36,988 You define all your infrastructure as code so you can point it at different 807 00:41:36,988 --> 00:41:38,968 environments and run entire copies of it. 808 00:41:39,448 --> 00:41:40,738 That's like the bare minimum. 809 00:41:41,008 --> 00:41:45,398 If you yourself can quickly create another environment for yourself, 810 00:41:45,438 --> 00:41:46,778 you've kind of solved the problem. 811 00:41:46,778 --> 00:41:49,268 Now someone else can follow those same steps. 812 00:41:49,678 --> 00:41:51,688 Where they're just cloning your project and running. 813 00:41:52,198 --> 00:41:55,038 You might be using Terraform, you might be using SST, whatever it is. 814 00:41:55,088 --> 00:41:58,208 Uh, you can do a thing, deploy with your credentials. 815 00:41:58,248 --> 00:42:00,508 And the same thing ends up in your account. 816 00:42:00,718 --> 00:42:03,018 Where this is a little bit challenging is updates. 817 00:42:03,198 --> 00:42:05,348 So obviously, you know, you have new versions. 818 00:42:05,348 --> 00:42:07,798 People can clone and redeploy, whatever. 819 00:42:07,908 --> 00:42:11,098 But there's sometimes operationally challenging updates. 820 00:42:11,098 --> 00:42:12,768 Like you might have like a schema change. 821 00:42:13,128 --> 00:42:15,968 You might have, uh, like data needs to be migrated. 822 00:42:16,418 --> 00:42:21,133 So, ultimately, the thing to always go back to is how do you make it 823 00:42:21,133 --> 00:42:22,773 easy for your own team to do that? 824 00:42:23,013 --> 00:42:24,983 Are there programmatic ways of doing all this? 825 00:42:25,023 --> 00:42:29,116 Or, like, if you need to do ad hoc random stuff and that's part of your 826 00:42:29,126 --> 00:42:32,136 workflow, it's going to be annoying for your end user to self host because 827 00:42:32,136 --> 00:42:34,556 then you need to, like, send them the instructions, they need to do it, 828 00:42:34,886 --> 00:42:36,246 they might, like, do it incorrectly. 829 00:42:36,456 --> 00:42:39,136 So, if everything is tracked in code and is automated and is 830 00:42:39,136 --> 00:42:40,999 programmatic, It's good for your team. 831 00:42:41,099 --> 00:42:42,896 That's good for the end user. 832 00:42:43,266 --> 00:42:46,116 and for an end user, in terms of what they should expect, if you are 833 00:42:46,116 --> 00:42:51,233 using some version of the cloud, you should hope that the thing you're self 834 00:42:51,243 --> 00:42:55,473 hosting is taking advantage of as many managed services as possible, right? 835 00:42:55,863 --> 00:42:57,403 So I had this issue with PostHog. 836 00:42:57,743 --> 00:42:59,693 So PostHog is an open source analytics tool. 837 00:43:00,358 --> 00:43:02,808 And when I was exploring it for my healthcare thing, I was like, 838 00:43:02,808 --> 00:43:04,408 okay, we'd have to self host it. 839 00:43:04,838 --> 00:43:06,628 Let me go look at the first self hosting steps. 840 00:43:07,058 --> 00:43:08,818 Step one, set up Kubernetes. 841 00:43:09,168 --> 00:43:14,548 Right, immediately there, I'm like, I like, found a way to finally free myself 842 00:43:14,548 --> 00:43:16,638 of Kubernetes for my main application. 843 00:43:16,648 --> 00:43:19,098 I don't want to like go, have to go manage a Kubernetes cluster 844 00:43:19,098 --> 00:43:20,948 again, just for this thing. 845 00:43:21,168 --> 00:43:24,628 So you should hope that, you should pick tools that use 846 00:43:25,168 --> 00:43:27,818 managed, versions of these things. 847 00:43:27,828 --> 00:43:30,998 That's why, like, we typically focus a little bit more on some of the 848 00:43:31,018 --> 00:43:33,278 serverless stuff, because it's very easy. 849 00:43:33,658 --> 00:43:37,338 If our app just runs as a Lambda function inside of someone's 850 00:43:37,338 --> 00:43:41,088 AWS account, or as a Cloudflare worker, there's almost no overhead. 851 00:43:41,098 --> 00:43:44,318 You're not like, you don't have to like set up like Datadog 852 00:43:44,398 --> 00:43:46,808 to like monitor the memory and like scale this up, up and down. 853 00:43:47,188 --> 00:43:52,058 It sucks to do that for like a small tool that you're adding to your project. 854 00:43:52,208 --> 00:43:56,358 So we try to make use of managed servers as much as possible so that the end user 855 00:43:56,358 --> 00:43:59,098 doesn't have as much operational overhead. 856 00:43:59,528 --> 00:44:01,338 and again, some people are willing to do that. 857 00:44:01,378 --> 00:44:04,558 It's just, uh, it's obviously a spectrum with all of these things. 858 00:44:04,948 --> 00:44:09,128 I do think it's a double edged sword while it like really takes away that operational 859 00:44:09,188 --> 00:44:11,678 burden and operational overhead. 860 00:44:11,948 --> 00:44:17,563 It's not just about, uh, deployment cycles and like the update cycles of the app 861 00:44:17,563 --> 00:44:22,333 that you're deploying, you potentially also need to update a, like from database 862 00:44:22,353 --> 00:44:26,703 version A to database version B of like just a database server that's running or 863 00:44:26,703 --> 00:44:28,483 like your analytics server or whatever. 864 00:44:28,813 --> 00:44:30,983 So that certainly takes a lot more effort. 865 00:44:31,393 --> 00:44:36,473 However, on a longer time horizon, if you do rely on managed services, 866 00:44:36,953 --> 00:44:40,763 they might just at some point send out a notice and say like, Hey, next 867 00:44:40,763 --> 00:44:44,158 quarter We're shutting down like that plan that you're relying on. 868 00:44:44,478 --> 00:44:47,808 So you're also in some regards might be building on quicksand. 869 00:44:48,138 --> 00:44:53,078 I think the, the larger a services such as Cloudflare, I think the 870 00:44:53,078 --> 00:44:57,298 chances that the rug is being pulled underneath you are probably lower. 871 00:44:57,928 --> 00:44:59,818 But it's always a double edged sword. 872 00:44:59,868 --> 00:45:04,808 And so my preference typically is in terms of the architecture that I'm using 873 00:45:05,058 --> 00:45:07,088 is like to go as simple as possible. 874 00:45:07,108 --> 00:45:11,298 This, for example, why I'm also very drawn to SQLite and I love the, all 875 00:45:11,298 --> 00:45:16,298 of the, the new tooling being built around SQLite since SQLite that's, no 876 00:45:16,298 --> 00:45:17,798 one's going to take that away from me. 877 00:45:17,798 --> 00:45:19,258 It's just like a little file. 878 00:45:19,688 --> 00:45:22,578 That I can put on a SD card or whatever. 879 00:45:22,908 --> 00:45:27,638 And, uh, that's still gonna like similar to that computer game from like the 1980s. 880 00:45:28,038 --> 00:45:30,388 that's still gonna work, in, in the future. 881 00:45:30,388 --> 00:45:33,508 And I think that's a great way to preserve data and you can 882 00:45:33,518 --> 00:45:35,328 still do so much with that. 883 00:45:35,488 --> 00:45:39,618 So I think that's sort of like a third option, uh, instead of 884 00:45:39,648 --> 00:45:44,278 going with like hosted or, Very scary self hosted infrastructure. 885 00:45:44,498 --> 00:45:48,738 If you make the self hosted infrastructure just that simple to 886 00:45:48,738 --> 00:45:52,728 rely on something like, like something that's almost serverless by default, 887 00:45:53,048 --> 00:45:57,468 like SQLite, I think that's a, that's a very attractive idea for me. 888 00:45:57,773 --> 00:45:58,763 Yeah, no, I agree. 889 00:45:58,763 --> 00:46:01,063 And with everything I'm saying, it's always like you have 890 00:46:01,063 --> 00:46:02,193 to exercise your judgment. 891 00:46:02,193 --> 00:46:05,183 I'm speaking from the things that I typically have worked on and 892 00:46:05,183 --> 00:46:06,813 I think this is where we landed. 893 00:46:06,863 --> 00:46:09,863 but yeah, if I was working on something that had different requirements, 894 00:46:09,863 --> 00:46:13,843 like, yeah, having like the simplest approach, uh, makes sense. 895 00:46:13,843 --> 00:46:17,423 The only reason that we have to do this is because we work on stuff 896 00:46:17,423 --> 00:46:20,203 that is like one of our tools is. 897 00:46:20,398 --> 00:46:23,138 Like, uh, like issues, like, kind of like how Sentry offers, 898 00:46:23,148 --> 00:46:24,308 like, issues that extracts. 899 00:46:24,738 --> 00:46:28,608 So we need to process, like, a large amount of logs, uh, because 900 00:46:28,608 --> 00:46:31,208 some people have, like, you know, like, billions of invocations a day. 901 00:46:31,658 --> 00:46:34,468 So it's not the type of thing that we can really simplify, like, we can't 902 00:46:34,468 --> 00:46:36,238 just give you, like, a single container. 903 00:46:36,553 --> 00:46:38,533 And this, because that's going to get overloaded very quickly. 904 00:46:38,933 --> 00:46:42,773 So the options for us are some crazy Kubernetes thing, or we 905 00:46:42,773 --> 00:46:45,913 just take advantage of AWS Kinesis and all these things that are 906 00:46:45,913 --> 00:46:47,253 built in that are lower overhead. 907 00:46:47,273 --> 00:46:49,833 Um, but, you know, if those weren't my requirements, I would 908 00:46:49,833 --> 00:46:51,636 probably opt for something similar. 909 00:46:51,636 --> 00:46:54,876 And yeah, at the day, it always just comes down to like, have good judgment. 910 00:46:55,496 --> 00:46:56,296 With whatever you're doing. 911 00:46:57,166 --> 00:46:57,556 Yeah. 912 00:46:57,926 --> 00:47:04,486 I think it's just as web developers, we're just so like in, in our like dependency 913 00:47:04,686 --> 00:47:09,606 fury in a way where like, we just like npm install this, npm install that, and 914 00:47:09,606 --> 00:47:14,556 we also not just package dependencies, but we also like add infrastructure 915 00:47:14,556 --> 00:47:19,073 dependencies left and right to something, I think is a big contributor, contributor. 916 00:47:19,358 --> 00:47:24,408 Why the long now aspect of local-first software is so hard to achieve. 917 00:47:24,818 --> 00:47:29,738 So I'm always, uh, trying as hard as possible to avoid dependencies, 918 00:47:29,748 --> 00:47:33,268 whether it's package dependencies or whether it's like infrastructure 919 00:47:33,268 --> 00:47:35,118 dependencies as much as possible. 920 00:47:35,348 --> 00:47:38,328 But it's always a trade off since they do sometimes can 921 00:47:38,328 --> 00:47:39,588 really save you a lot of time. 922 00:47:39,868 --> 00:47:40,258 Yeah. 923 00:47:40,308 --> 00:47:40,498 Yeah. 924 00:47:40,498 --> 00:47:42,728 I think for us, we kind of land in this middle ground where 925 00:47:42,728 --> 00:47:44,518 we'll commit to one thing. 926 00:47:44,933 --> 00:47:46,733 But then we'll reject a bunch of other things. 927 00:47:46,743 --> 00:47:51,863 So, there's this phenomena happening right now, where, uh, you have these large 928 00:47:51,863 --> 00:47:53,623 cloud providers that offer these services. 929 00:47:53,673 --> 00:47:57,908 The services aren't like, The best, most wonderful things to use. 930 00:47:58,258 --> 00:48:01,958 There's a bunch of companies that'll like, make a copy of just that one 931 00:48:01,958 --> 00:48:04,018 service, but do it like 10 times better. 932 00:48:04,178 --> 00:48:08,068 It's often really compelling, and like you, I can see why people are tempted 933 00:48:08,068 --> 00:48:11,258 to adopt every single one of these, and people end up with a stack where it's 934 00:48:11,258 --> 00:48:16,716 like, It's my application and sitting on top of like 10 different other vendors. 935 00:48:17,296 --> 00:48:21,136 And these 10 vendors are also startups, you know, like it's unclear if they're 936 00:48:21,386 --> 00:48:22,666 going to be around for a while. 937 00:48:22,936 --> 00:48:25,016 So for us, we like as tempting as it is. 938 00:48:25,016 --> 00:48:28,456 And some of it has nice as some of these offerings are like, we never use those. 939 00:48:28,456 --> 00:48:32,656 We just stick to the most lowest level primitives that we can be sure are 940 00:48:32,656 --> 00:48:34,076 going to be around for a long time. 941 00:48:34,666 --> 00:48:35,606 And we'll commit to those. 942 00:48:35,636 --> 00:48:37,736 Like, we're going to accept the fact that if something 943 00:48:37,736 --> 00:48:38,786 happens to them, we're screwed. 944 00:48:39,216 --> 00:48:40,866 More likely we're going to die before they do. 945 00:48:40,866 --> 00:48:44,176 So that makes sense, but like, you know, we won't, we won't apply that everywhere. 946 00:48:44,176 --> 00:48:46,739 So again, it just comes down to like having the right judgment 947 00:48:46,739 --> 00:48:50,279 and picking things and low dependency is very important. 948 00:48:50,739 --> 00:48:51,839 That makes a lot of sense. 949 00:48:52,069 --> 00:48:56,289 So you mentioned in terms of the deployment cycle, also the update cycle 950 00:48:56,309 --> 00:48:58,424 of your application, and now in the. 951 00:48:59,104 --> 00:49:03,754 local-first way, there is, uh, primarily you need to think about how do I 952 00:49:03,774 --> 00:49:06,414 update the local-first app itself? 953 00:49:06,774 --> 00:49:10,874 So some certain things are easy to deploy, like a, a new component 954 00:49:10,874 --> 00:49:13,294 version of your UI that's, that's easy. 955 00:49:13,604 --> 00:49:18,064 But now that also all of your data lives in the client, the schema of your 956 00:49:18,064 --> 00:49:22,304 data or like the shape of your data is possibly also going to evolve over time. 957 00:49:22,304 --> 00:49:23,984 And there's different ways to deal with that. 958 00:49:24,294 --> 00:49:26,204 So I'm curious how you've handled that. 959 00:49:26,644 --> 00:49:30,804 as well as possibly also the same problem applied to your cloud component. 960 00:49:31,284 --> 00:49:31,694 Yeah. 961 00:49:31,694 --> 00:49:35,374 So in terms of the data locally, we've never done anything sophisticated here. 962 00:49:35,374 --> 00:49:36,834 We've always just blown it all away. 963 00:49:36,874 --> 00:49:41,674 If we have to do some kind of severe breaking change, we will just update like 964 00:49:41,674 --> 00:49:46,524 the big version number and the app will erase everything locally and re sync. 965 00:49:46,524 --> 00:49:47,254 It's not a huge deal. 966 00:49:47,254 --> 00:49:49,444 It's never like massive amount of data. 967 00:49:49,844 --> 00:49:53,284 I think I can see a world where this is, and already it's actually not 968 00:49:53,294 --> 00:49:56,004 too different than changing your back end database schema because 969 00:49:56,004 --> 00:49:57,094 you have similar issues, right? 970 00:49:57,094 --> 00:50:01,014 Like you want to make backwards compatible changes as much as you can because 971 00:50:01,014 --> 00:50:03,584 you don't want to have to like force changes in your application code and 972 00:50:03,584 --> 00:50:05,124 force deployments of those together. 973 00:50:05,394 --> 00:50:08,914 So similarly, most of the time you can do something backwards compatible. 974 00:50:09,084 --> 00:50:11,694 If you totally mess something up, which obviously happens sometimes, 975 00:50:11,964 --> 00:50:13,044 yeah, we just blow it away. 976 00:50:13,044 --> 00:50:15,734 We haven't really found the need to do anything more sophisticated 977 00:50:15,744 --> 00:50:16,464 in what we have, like. 978 00:50:17,104 --> 00:50:19,034 Migration scripts that run locally or anything. 979 00:50:19,324 --> 00:50:23,614 I can see how that's a case for if you're like running, I guess, if it's like end 980 00:50:23,614 --> 00:50:27,434 to end encrypted or something where you can't really do that and the true state of 981 00:50:27,434 --> 00:50:30,064 the data is what's on the person's device. 982 00:50:30,354 --> 00:50:32,374 I can see how you have to like think about that a little bit more. 983 00:50:32,524 --> 00:50:34,484 I think it kind of reminds me of WhatsApp a little bit because like with 984 00:50:34,484 --> 00:50:37,704 WhatsApp, it feels like you're like shuffling your data across your devices. 985 00:50:37,804 --> 00:50:41,024 You get a new device, you like Move the data from one to another. 986 00:50:41,024 --> 00:50:44,074 So I imagine they deal with things like this, but yeah, personally don't 987 00:50:44,074 --> 00:50:46,294 have a ton of experience with that. 988 00:50:46,984 --> 00:50:51,544 Yeah, I mean WhatsApp is also one of the OG local-first apps that 989 00:50:51,549 --> 00:50:55,144 really like followed this pattern out of necessity that defined 990 00:50:55,144 --> 00:50:56,974 why WhatsApp is so attractive. 991 00:50:57,634 --> 00:51:01,664 But I think the, the trade off that you've landed on, I think makes a lot of sense. 992 00:51:01,664 --> 00:51:06,974 It's very pragmatic and given that you're in this hybrid mode of like some parts of 993 00:51:06,974 --> 00:51:11,354 your app are cloud oriented, some parts of your app are local-first, now you can 994 00:51:11,354 --> 00:51:15,654 also reap the benefits of the best of both worlds that allows you to move quickly. 995 00:51:16,084 --> 00:51:19,684 I think if at some point you want to move further on the local-first side. 996 00:51:19,764 --> 00:51:23,174 Spectrum, then I think maybe you can't quite afford just 997 00:51:23,174 --> 00:51:24,794 blowing all the local data away. 998 00:51:24,994 --> 00:51:29,524 I'm kind of exploring some patterns in that regard where I'm kind of keeping 999 00:51:29,554 --> 00:51:32,084 two versions of the data around locally. 1000 00:51:32,304 --> 00:51:35,234 One version that is more of like an event log. 1001 00:51:35,714 --> 00:51:39,274 And one that is more of like a typical app database. 1002 00:51:39,614 --> 00:51:44,454 And the app database is just a projection on aggregate from the event log. 1003 00:51:44,524 --> 00:51:49,484 So I also get the benefits and luxury of, in the case of a schema migration, 1004 00:51:49,484 --> 00:51:50,974 I can just blow away the app DB. 1005 00:51:51,304 --> 00:51:54,714 But instead of talking to the server, I can just replay it locally. 1006 00:51:55,064 --> 00:51:58,804 Sometimes takes a little bit of time, but, uh, you get a lot of different 1007 00:51:58,814 --> 00:52:03,484 options here that you can choose depending on your requirements and how much time 1008 00:52:03,484 --> 00:52:06,094 you can afford to put some effort into. 1009 00:52:06,294 --> 00:52:07,314 Yeah, yeah, that makes sense. 1010 00:52:07,314 --> 00:52:11,864 And what's interesting is this feels very different, but it just kind of 1011 00:52:11,904 --> 00:52:15,544 echoes the same things you do with like a database in the back end. 1012 00:52:15,554 --> 00:52:16,694 It's ultimately the same thing. 1013 00:52:16,694 --> 00:52:20,014 It just happens to be that the node of the database is running. 1014 00:52:20,331 --> 00:52:22,791 In someone's machine, so you end up with like almost all 1015 00:52:22,791 --> 00:52:24,831 the same scenarios and options. 1016 00:52:25,561 --> 00:52:30,311 Did you run into any situation where you feel like, okay, this was really 1017 00:52:30,361 --> 00:52:34,431 easier in the way how you've built software in the past that's now 1018 00:52:34,471 --> 00:52:39,941 like either currently harder with local-first or like just categorically 1019 00:52:39,951 --> 00:52:41,861 inherently harder with local-first? 1020 00:52:42,631 --> 00:52:45,051 Well, it's really that one scenario I talked about before where 1021 00:52:45,051 --> 00:52:46,731 you do want to block the user. 1022 00:52:46,741 --> 00:52:51,111 Since the default is inverted, whenever, like you never, you never think like 1023 00:52:51,111 --> 00:52:55,571 holding the user up until the backend verifies something has happened. 1024 00:52:56,101 --> 00:52:58,621 99 percent of developers would never think about that as complicated. 1025 00:52:58,651 --> 00:53:00,691 It's like, obviously, that's like how everything works. 1026 00:53:01,091 --> 00:53:04,041 But when you invert the default, that becomes a little bit more challenging 1027 00:53:04,411 --> 00:53:08,511 and Yeah, we just have to come up with, like, certain patterns around, like, if 1028 00:53:08,511 --> 00:53:13,676 you do an action, and a server rejects the action, the natural s thing that'll happen 1029 00:53:13,676 --> 00:53:18,236 is your state locally will revert to the state it was at before you did the action. 1030 00:53:18,736 --> 00:53:21,906 But that state has no record of you trying to do the action, so 1031 00:53:21,906 --> 00:53:25,376 the UI won't have like any error or like information about this. 1032 00:53:25,386 --> 00:53:28,856 So, doing an action where there was an error on the backend and preserving 1033 00:53:28,856 --> 00:53:34,016 that error, it just ends up being more steps than it would be otherwise. 1034 00:53:34,146 --> 00:53:37,096 But again, like we talked about, like this is a minority of cases, so it doesn't come 1035 00:53:37,096 --> 00:53:38,786 up, but it's just a funny thing where. 1036 00:53:39,531 --> 00:53:43,231 Something so straightforward in the traditional situation is like 1037 00:53:43,231 --> 00:53:45,731 so weirdly complicated in this. 1038 00:53:46,151 --> 00:53:47,331 So that's one thing that comes up. 1039 00:53:47,331 --> 00:53:50,559 I think the second thing that comes up is Kind of going back to this thing about 1040 00:53:50,559 --> 00:53:55,799 like the doing migrations of data locally or the schema changes, there's always 1041 00:53:55,839 --> 00:53:59,289 a chance, and it's happened more when I was earlier on in doing this stuff. 1042 00:53:59,289 --> 00:54:02,719 So I think it was just me, like, not doing stuff well, or like not having 1043 00:54:03,409 --> 00:54:04,569 the right approach to certain things. 1044 00:54:04,579 --> 00:54:09,264 But, um, Sometimes you would just end up with, like, data that was bad and 1045 00:54:09,264 --> 00:54:12,654 messing up the user's state locally. 1046 00:54:12,894 --> 00:54:17,144 And with any other app, hitting refresh means, start over, you're, like, rebooting 1047 00:54:17,144 --> 00:54:20,944 your computer, you're, like, back to, back to ground, like, back to zero. 1048 00:54:21,594 --> 00:54:24,374 But with local-first, you might hit refresh and the local data is still there. 1049 00:54:24,724 --> 00:54:28,344 That's causing the bug, preventing, like, you know, the fix from being applied. 1050 00:54:28,944 --> 00:54:32,024 So, just like the, you lose the ease of, like, wiping everything 1051 00:54:32,074 --> 00:54:34,124 and there's no, like, built in user. 1052 00:54:34,434 --> 00:54:38,474 Habits around like, oh, like, let me try clearing my index 1053 00:54:38,474 --> 00:54:39,834 DB and my browser, right? 1054 00:54:39,834 --> 00:54:41,244 That's like not a thing that anyone thinks about. 1055 00:54:41,604 --> 00:54:43,904 So just like guarding those things so you never end up in a 1056 00:54:43,904 --> 00:54:46,314 state where it's unrecoverable. 1057 00:54:46,734 --> 00:54:47,654 I think that's, that's for good. 1058 00:54:47,654 --> 00:54:49,674 Again, it's usually handled on a lower level, so you're not 1059 00:54:49,674 --> 00:54:50,884 dealing with this constantly, but. 1060 00:54:51,499 --> 00:54:53,169 It is a technical possibility. 1061 00:54:53,619 --> 00:54:56,489 Yeah, I like that, uh, that observation a lot. 1062 00:54:56,539 --> 00:54:59,009 This is also something I'm currently thinking a lot about. 1063 00:54:59,469 --> 00:55:01,899 How can I make that easier through LiveStore? 1064 00:55:01,949 --> 00:55:07,579 Since I also, as working both on LiveStore and Overtone, I do discover 1065 00:55:07,609 --> 00:55:11,799 those behaviors, whether it's like still me as a developer driving the 1066 00:55:11,819 --> 00:55:16,499 user experience where it didn't pop open the console and like throw away, like 1067 00:55:16,509 --> 00:55:18,759 all the, the locally persisted data. 1068 00:55:19,099 --> 00:55:22,279 But I can't expect an app user to do the same thing. 1069 00:55:22,529 --> 00:55:26,979 So I need to build like some sort of, um, guards or some sort of detection 1070 00:55:26,979 --> 00:55:31,629 of like, Hey, it seems like the app is in sort of like a really tough spot. 1071 00:55:31,849 --> 00:55:33,029 What should we do about this? 1072 00:55:33,219 --> 00:55:36,489 Should we try to just like delete a little bit of stuff 1073 00:55:36,509 --> 00:55:38,699 that might cause the blockage? 1074 00:55:39,064 --> 00:55:40,744 Or what should we do about that? 1075 00:55:40,744 --> 00:55:45,264 And so where, where I'm currently at is I think a mixture of user experience 1076 00:55:45,304 --> 00:55:48,994 affordances, as well as technical detections, whether something is 1077 00:55:48,994 --> 00:55:53,514 wrong, I think transactions can help with that in regards to the technical 1078 00:55:53,514 --> 00:55:58,064 abilities, but then in terms of the user experience, similar to like a 1079 00:55:58,114 --> 00:56:02,124 React error boundary that you have to detect whether something has gone wrong. 1080 00:56:02,844 --> 00:56:07,544 I want to have a similar pattern that allows you to, you know, Click a button 1081 00:56:07,554 --> 00:56:12,314 that wipe everything, but it before it does wipe everything, download 1082 00:56:12,384 --> 00:56:16,654 a snapshot of your full database that in case something catastrophic 1083 00:56:16,654 --> 00:56:18,624 happens, you can, you still have that. 1084 00:56:18,874 --> 00:56:22,874 You can hand that to an app developer and you can also later re import 1085 00:56:22,924 --> 00:56:26,274 your app state from there so that you can go back where you've 1086 00:56:26,274 --> 00:56:28,014 left off in case you wiped it. 1087 00:56:28,374 --> 00:56:32,414 So those are like some, some primitives and some, some patterns I'm exploring 1088 00:56:32,414 --> 00:56:35,674 right now, but I'm, I'm excited to see what other figures out. 1089 00:56:36,119 --> 00:56:37,419 Yeah, that makes sense. 1090 00:56:37,779 --> 00:56:42,969 It's also great that you're like, building an actual thing with the tool. 1091 00:56:43,249 --> 00:56:46,489 There's just like, no better way to like, really understand 1092 00:56:46,489 --> 00:56:47,649 what problems you need to solve. 1093 00:56:48,149 --> 00:56:51,669 With SST, like, our console is built with SST. 1094 00:56:52,179 --> 00:56:56,069 So, any change we make comes from problems we discover. 1095 00:56:56,209 --> 00:56:57,479 The actual product that we're building. 1096 00:56:57,769 --> 00:57:01,899 That's why it's so fun to work on like, developer tools, because you are the user. 1097 00:57:02,579 --> 00:57:05,879 So you're never like, how do I get in the mind of a user? 1098 00:57:05,899 --> 00:57:07,269 Like, that's, that problem isn't there. 1099 00:57:07,299 --> 00:57:08,429 Like, you are the user. 1100 00:57:08,639 --> 00:57:11,809 It's very easy to figure out what problems there are, um, and discover that. 1101 00:57:11,809 --> 00:57:14,704 You kind of skip that whole, like, discovery process that 1102 00:57:14,704 --> 00:57:15,684 usually needs to happen. 1103 00:57:16,374 --> 00:57:20,494 So if you have someone who's currently like, by default, building 1104 00:57:20,524 --> 00:57:22,304 a new app with something like Next. 1105 00:57:22,304 --> 00:57:27,514 js or Ruby on Rails, and they, they hear about your story and now they're like 1106 00:57:27,554 --> 00:57:31,334 curious about local-first, but they're not quite sure where to get started. 1107 00:57:31,694 --> 00:57:34,644 Do you have some tactical suggestions for them? 1108 00:57:34,914 --> 00:57:38,694 And also in terms of mindset, what do they need to. 1109 00:57:39,009 --> 00:57:43,729 switch in their brain, uh, that they're successful and can hit the ground 1110 00:57:43,729 --> 00:57:45,869 running in a local-first mindset. 1111 00:57:46,259 --> 00:57:46,829 Yeah. 1112 00:57:47,179 --> 00:57:50,699 You know, it's, I don't think I've really thought about like, what's 1113 00:57:50,729 --> 00:57:54,509 the right onboarding path for people doing this type of thing. 1114 00:57:54,539 --> 00:57:57,449 I'm like, I know the tools that I use, like I said, we're, we're, we've 1115 00:57:57,479 --> 00:58:00,569 centered around Replicache at this point, but you know, local-first website 1116 00:58:00,569 --> 00:58:02,419 obviously has a ton of other options. 1117 00:58:03,129 --> 00:58:05,609 And there's a spectrum of like what you care about and like how 1118 00:58:05,609 --> 00:58:08,339 easy it is and how incremental you can add it and things like that. 1119 00:58:08,379 --> 00:58:12,979 But the mindset I think really is, it really has nothing to do with local-first. 1120 00:58:12,999 --> 00:58:14,879 And I think it's a good mindset for everyone. 1121 00:58:14,919 --> 00:58:19,219 I feel like there has been this shift away from like caring about UX and 1122 00:58:19,219 --> 00:58:22,849 almost, I feel like there's like a weird proudness to like not caring about UX, 1123 00:58:22,859 --> 00:58:24,309 which I think is fundamentally wrong. 1124 00:58:24,629 --> 00:58:26,169 And what I mean by that is. 1125 00:58:26,366 --> 00:58:29,736 There's a whole meme of like, Oh, if you did this, you shipped too late. 1126 00:58:29,876 --> 00:58:32,576 Or like people are proud of like shipping bad stuff. 1127 00:58:32,586 --> 00:58:35,646 Cause they're signaling that like, I'm just someone that 1128 00:58:35,646 --> 00:58:37,296 like tries to get stuff done. 1129 00:58:37,296 --> 00:58:43,066 I'm not like wasting time on stupid stuff, which the Linear people had a great write 1130 00:58:43,066 --> 00:58:48,806 up about this and it's this whole concept around the idea of an MVP is stupid and 1131 00:58:48,806 --> 00:58:52,096 it's been stupid for a while, but for some reason, people haven't realized this. 1132 00:58:52,591 --> 00:58:55,841 I definitely will acknowledge maybe back when I was starting out, like 1133 00:58:55,841 --> 00:58:59,231 in the startup world, like, I guess it's been like 10 or 11 years, things 1134 00:58:59,231 --> 00:59:02,051 were definitely different back then where there wasn't a lot of software. 1135 00:59:02,511 --> 00:59:05,131 So anything was better than nothing. 1136 00:59:05,361 --> 00:59:09,071 So you could really ship something pretty quick and like get validation and move on. 1137 00:59:09,231 --> 00:59:11,896 It's like that whole like mindset kind of made sense back then. 1138 00:59:12,246 --> 00:59:14,216 But it hasn't been that way in a long time. 1139 00:59:14,366 --> 00:59:17,276 So many people ship like something they built in a week and they're 1140 00:59:17,276 --> 00:59:18,356 like, Oh, it didn't work. 1141 00:59:18,356 --> 00:59:19,446 Let me move on to the next thing. 1142 00:59:19,739 --> 00:59:23,989 To be honest, nothing good can really be shipped that fast. 1143 00:59:23,989 --> 00:59:25,079 It's just not possible. 1144 00:59:25,469 --> 00:59:29,999 Uh, and you really need to have a strong sense of here's a problem I'm solving. 1145 00:59:30,509 --> 00:59:31,899 I have good taste around it. 1146 00:59:31,929 --> 00:59:35,849 I'm going to put in a lot of effort and make a really great experience. 1147 00:59:36,379 --> 00:59:36,929 And. 1148 00:59:37,509 --> 00:59:41,529 Whether or not my idea is going to work, you can't know that 1149 00:59:41,539 --> 00:59:43,129 until you've hit that bar. 1150 00:59:43,379 --> 00:59:47,409 And as a Linear people wrote up a whole thing about this on like, we're so 1151 00:59:47,409 --> 00:59:49,829 obsessed with these like little tiny MVPs. 1152 00:59:50,209 --> 00:59:52,189 And that's like the weird default that we're all like kind of 1153 00:59:52,189 --> 00:59:54,689 proud to say that we follow that. 1154 00:59:54,709 --> 00:59:59,549 Um, and the mindset shift is with local-first, it's getting easier all 1155 00:59:59,549 --> 01:00:03,959 the time, but it's going to be a lot harder than a lot of things that you've 1156 01:00:03,959 --> 01:00:08,229 done before because you have so much time to focus on these little details. 1157 01:00:08,329 --> 01:00:09,909 And you really have to focus on details. 1158 01:00:09,909 --> 01:00:14,019 You have to enjoy Letting them and caring about them and making that 1159 01:00:14,019 --> 01:00:17,829 feel good because that's what that's where the bar is now, whether people 1160 01:00:17,829 --> 01:00:23,079 realize it or not, the fact is Linear, Linear exists now that it exists. 1161 01:00:23,089 --> 01:00:26,459 How can you possibly ship anything not at that level? 1162 01:00:26,459 --> 01:00:26,629 Right? 1163 01:00:26,629 --> 01:00:29,929 How, like, sure, in the short term, I'm sure you can, but the long term, 1164 01:00:29,939 --> 01:00:32,099 obviously that becomes a new bar. 1165 01:00:32,429 --> 01:00:36,589 So, for me, the mindset shift is like, there is a new bar go use products that 1166 01:00:36,589 --> 01:00:40,459 are like this, like, Linear is one, like, superhuman is like a smaller example. 1167 01:00:40,986 --> 01:00:42,296 of stuff that's kind of gotten bigger. 1168 01:00:42,716 --> 01:00:45,476 That is the bar, and you have to accept that that is a bar. 1169 01:00:45,636 --> 01:00:48,516 And if you really accept that, then you'll be motivated to like 1170 01:00:48,516 --> 01:00:50,196 go and figure out all this stuff. 1171 01:00:50,356 --> 01:00:53,706 Yeah, it's quite different from where I think the mindset is currently. 1172 01:00:54,163 --> 01:00:58,798 I think you've very succinctly Summarized my last two and a 1173 01:00:58,798 --> 01:01:00,488 half years working on Overtone. 1174 01:01:00,708 --> 01:01:03,148 I'm exactly inspired by that high bar. 1175 01:01:03,198 --> 01:01:08,458 Sometimes I might even raise it a bit higher just for, for the challenge, but 1176 01:01:08,498 --> 01:01:13,058 it's so fun to see like all of those details just compounding and, and I 1177 01:01:13,078 --> 01:01:14,878 like much smoother product experience. 1178 01:01:15,568 --> 01:01:19,413 And, uh, yeah, I love the the blog posts that you've pointed 1179 01:01:19,413 --> 01:01:21,103 out from the, the Linear blog. 1180 01:01:21,463 --> 01:01:25,423 And I think the only exception really to where the bar needs to be higher is 1181 01:01:25,423 --> 01:01:27,853 like for just categorically new things. 1182 01:01:28,123 --> 01:01:32,283 Maybe an exception here is like AI products, uh, like AI products. 1183 01:01:32,313 --> 01:01:34,883 There is no, no prior version to that. 1184 01:01:34,893 --> 01:01:38,923 So maybe it is really speed that, that matters most, but I think 1185 01:01:38,933 --> 01:01:42,753 for every software that replaces something that was there before. 1186 01:01:43,213 --> 01:01:46,823 I think it's, you have to really, really care about craft. 1187 01:01:46,843 --> 01:01:52,023 Um, Arc is another example as like to really innovate on a browser. 1188 01:01:52,063 --> 01:01:55,733 Like the browser is still the same, what it is before, but now it's 1189 01:01:55,763 --> 01:01:59,563 like all the compound effect of all of like getting the details right. 1190 01:02:00,043 --> 01:02:02,303 And that really, that really excites me. 1191 01:02:02,543 --> 01:02:04,753 So thank you so much for that wonderful summary. 1192 01:02:05,473 --> 01:02:05,743 Yeah. 1193 01:02:05,743 --> 01:02:07,613 And there's so much opportunity to do this. 1194 01:02:07,613 --> 01:02:10,903 Like I'm unhappy with so much of the things that I use every day. 1195 01:02:10,993 --> 01:02:14,373 So yeah, I just want more people to get excited about doing this type of thing. 1196 01:02:14,656 --> 01:02:15,496 Thank you so much. 1197 01:02:15,536 --> 01:02:17,136 This has been really, really fun. 1198 01:02:17,246 --> 01:02:18,526 Thank you so much for coming on. 1199 01:02:19,276 --> 01:02:20,586 Yeah, appreciate having me. 1200 01:02:20,616 --> 01:02:21,716 I, I, it was good. 1201 01:02:21,716 --> 01:02:23,766 I actually don't get to get into some of these details. 1202 01:02:24,096 --> 01:02:26,266 I don't, I've actually never gotten a lot of these details before. 1203 01:02:26,266 --> 01:02:27,586 So yeah, it was great. 1204 01:02:27,737 --> 01:02:30,277 Thank you for listening to the localfirst.fm podcast. 1205 01:02:30,517 --> 01:02:34,247 If you've enjoyed this episode and haven't done so already, please subscribe and 1206 01:02:34,247 --> 01:02:36,007 leave a review wherever you're listening. 1207 01:02:36,377 --> 01:02:37,807 Please also tell your friends about it. 1208 01:02:37,817 --> 01:02:41,387 If you think they could be interested in local-first, if you have feedback, 1209 01:02:41,427 --> 01:02:45,167 questions or ideas for the podcast, please get in touch via hello at 1210 01:02:45,167 --> 01:02:50,947 localfirst.fm or use the feedback form on our website, special thanks to Expo and 1211 01:02:50,947 --> 01:02:52,997 Crab Nebula for supporting this podcast. 1212 01:02:53,397 --> 01:02:54,157 See you next time.