localfirst.fm
All episodes
May 21, 2024

#9 – Dax Raad: Local-First SaaS

#9 – Dax Raad: Local-First SaaS
Sponsored byExpoCrabNebula
Show notes

Transcript

0:00:00 Intro
0:00:00 What do you mean replicate the whole data to the end client?
0:00:03 Like, It's too big.
0:00:03 Like, that can't work.
0:00:04 So I understand the hesitation.
0:00:06 But any like half step in that direction, it just a gateway to
0:00:10 replicating more and more and more.
0:00:11 Cause you just want more and more and more to be instant.
0:00:13 So I had a very traditional mindset around it, which is, okay, we have an
0:00:17 API, the API serves data and we're going to like cache some of that locally.
0:00:22 And I think a lot of people are already doing this stuff, like react-query
0:00:24 put you in that direction where just caching stuff and then refetching.
0:00:28 It kind of gives you some of this like real time local-first feel, but then
0:00:32 you start to hit the limits with that, if you're looking for stuff that's not
0:00:34 literally in the exact view, you're then round tripping with the server again.
0:00:39 The key thing to understand is if you're building an app that people
0:00:42 are actually using every day, the initial load time is really not
0:00:46 something you need to care about.
0:00:48 Welcome to the Local First FM podcast.
0:00:50 I'm your host, Johannes Schickling, and I'm a web developer, a
0:00:53 startup founder, and love the craft of software engineering.
0:00:57 For the past few years, I've been on a journey to build a modern, high quality
0:01:01 music app using web technologies.
0:01:03 And in doing so, I've been falling down the rabbit hole of local first software.
0:01:07 This podcast is your invitation to join me on that journey.
0:01:11 In this episode, I'm speaking to Dax Rad, who is using local first
0:01:15 in multiple projects, including the serverless deployment tool, sst.
0:01:19 dev, a healthcare app, and an upcoming personal finance app.
0:01:23 In this conversation, we explore how local first simplifies app development, the UX
0:01:29 and data patterns he's using, and how self hosting could empower local first apps.
0:01:34 Before getting started, also a big thank you to Expo and Crab
0:01:38 Nebula for supporting this podcast.
0:01:40 And now my interview with Dax.
0:01:42 Hey Dax, welcome to the show.
0:01:44 How are you doing?
0:01:45 Good.
0:01:45 How are you doing?
0:01:47 I'm doing great.
0:01:48 Super excited to have you on the show.
0:01:50 You're certainly also one of the more, well known voices on Twitter
0:01:54 sharing the local-first gospel.
0:01:56 So, seems like you're not just working on one project with local-first,
0:02:00 but almost quite a portfolio of local-first inspired projects.
0:02:04 So super curious to hear more about those, but maybe you want to
0:02:08 share a bit of your story of like, what has led you to local-first?
0:02:12 Local-first motivation and projects overview
0:02:12 yeah, so my name is Dax.
0:02:13 My primary project that I work on is a project called SST.
0:02:18 Uh, we're a, we're a dev tool.
0:02:19 Like, we help people ship applications.
0:02:21 We help people deploy all kinds of infrastructure to all kinds of places.
0:02:25 And we have an adjacent project to it.
0:02:29 Uh, so SST users get access to this thing called the SST console.
0:02:33 And that is a local-first application.
0:02:36 I mean, I'm gonna say local-first.
0:02:38 There's obviously, like, a spectrum.
0:02:39 I would say it's a local-first.
0:02:41 The least local-first thing with that you could possibly have while still,
0:02:45 I would say, embodying some of the characteristics, but my history with it,
0:02:49 like most people or like a lot of people, I guess, uh, it started with, with Linear.
0:02:54 I came across.
0:02:56 The product probably like 2018 or 2019 somewhere, somewhere around there,
0:03:00 probably 2019, something like that.
0:03:02 And I found them fascinating in a few dimensions.
0:03:07 One, their attention to detail was just kind of outrageous.
0:03:10 Like there's all these little details.
0:03:12 Outside of local-first stuff, just these details that are in there that, you know,
0:03:16 they're, they're like real craftsmen.
0:03:17 They care about, uh, every little aspect of their product.
0:03:20 I found them really interesting from a business perspective because they
0:03:24 entered the most crowded and most cliche space you can possibly think of.
0:03:28 Everyone has had the idea of, I hate my project management tool.
0:03:32 Like I should build my own, uh, the most boring, cliche,
0:03:36 non innovative idea possible.
0:03:38 They enter that space and they absolutely crush it.
0:03:40 Like no one really could have predicted that.
0:03:42 I think you would have, if you just heard that idea, you're just
0:03:45 been like, whatever, and they did that purely from this aspect of.
0:03:49 Really excellent quality and performance.
0:03:52 And these are things that people will love to say, like, oh, the user doesn't care.
0:03:56 People, performance doesn't matter.
0:03:57 Like, you know, they'll try to say that it's something that you can do later.
0:04:00 And this is a great example of a company that's kind of violating that narrative.
0:04:05 So I find them really fascinating.
0:04:07 And I got obsessed with just digging into how They built their stuff
0:04:11 initially from like a UI perspective.
0:04:13 But then I was like kind of looking into how all this, how everything
0:04:16 is super responsive and instant.
0:04:18 And I started them so hard to the point where I think I was really
0:04:21 convinced at some point that I knew more about their system than
0:04:23 anybody that didn't work there.
0:04:25 Like I understood like their exact protocol, like how
0:04:27 they sort stuff locally.
0:04:29 Uh, I kind of just kept going back to it to refer to it.
0:04:32 And around the same time, my wife and I were starting a new
0:04:34 project in the healthcare space, and this was a productivity tool.
0:04:39 So it's the type of tool that people log into the beginning of the day, use it
0:04:43 all day until they finish their work.
0:04:45 So these are the places where I feel like the performance
0:04:49 aspect is really understated.
0:04:52 When you're using an app every single second of the day to do your work,
0:04:57 There's all those little paper cuts where something takes a little bit longer
0:05:01 to load, or there's like a spinner.
0:05:03 These do weigh on you.
0:05:04 If you talk to the user, they probably won't articulate it.
0:05:07 But if you ask them the question, does it feel like a joy to do your work?
0:05:11 Or does it feel draining to do your work?
0:05:13 And they're going to say draining unless you push things to this degree.
0:05:17 and this never shows up in like typical user research or like user
0:05:20 feedback or any of that stuff.
0:05:22 So because we were working on something in this category, I
0:05:24 was like, okay, we have to do it.
0:05:26 We have to like set the, meet the same bar that Linear met.
0:05:29 And that's kind of when I started digging into what are all the
0:05:31 different ways that we can enable this.
0:05:34 And we started from like a JSON API using Orbit to like replicate
0:05:39 the data locally, to GraphQL and Urql to do something similar.
0:05:44 Um, and then we eventually ended up on Replicache after,
0:05:47 like, trying a few of those.
0:05:48 Uh, we also tried, I think, RxDB at some point.
0:05:52 Because we knew that, yeah, we want to have almost every operation
0:05:55 happen locally, if possible, so that the feedback is instant.
0:05:59 You know, searching, and this is in the healthcare space, so searching
0:06:02 through patients should be instant.
0:06:03 Loading up their information should be instant.
0:06:06 Even if we had a really large data set on the server, In terms of like,
0:06:10 a single business might have, you know, tens of thousands of patients.
0:06:14 An individual doctor is only seeing a small subset.
0:06:16 So having the ability to like, partially sync the data that
0:06:19 we know the user cares about.
0:06:21 So we spent like, through the course of building this product,
0:06:24 we tried so many different setups.
0:06:25 And we've probably spent two years of learning and trying how to do these
0:06:31 patterns before we landed on something where, one, like the tools, like
0:06:35 I said, we ended up on Replicache.
0:06:36 Replicache is a tool that we liked, and two, like, As people building products,
0:06:40 like we understood how to like, really take advantage of it, how to structure
0:06:43 things and where to pay attention.
0:06:45 So that product is called Bumi.
0:06:48 Uh, we actually ended up deciding to pivot away from it.
0:06:50 Uh, like we have, we have some customers, but it just ended up not being a
0:06:54 market that was particularly large.
0:06:56 And so we wanted to switch to something that was a lot more,
0:06:59 like, wide, like anyone can use.
0:07:02 And something that we personally would use, I found that any product
0:07:05 I build where I personally use it, it just comes out like 10 times better.
0:07:09 It's just way easier to understand the problems and be motivated to fix them.
0:07:13 So we're working on a new product called Radiant now.
0:07:15 And that is a personal finance application, which again,
0:07:18 there's thousands of, very similar to the Linear story.
0:07:21 But we really believe building, like, a very power user
0:07:25 productivity focused version of it.
0:07:27 There's like interesting room in the market for that.
0:07:30 So the one other thing just to kind of cap off the story is, uh, so between
0:07:33 those two things, uh, working on SST, we also kicked off a new project there, the
0:07:38 SST console, which I mentioned earlier.
0:07:40 Kind of a similar story where this is a tool that you use alongside
0:07:43 your day to day development.
0:07:44 You're using all the time.
0:07:46 Having every single thing be fast really makes a difference in the end
0:07:51 feeling that users have of the product, so we decided to go with the same kind
0:07:56 of local-first ish model for that.
0:07:58 And that one is completely open source.
0:08:00 We were really public about building it.
0:08:02 I think a lot of people were exposed to the idea of This pattern, and we've seen
0:08:07 people like, kind of take that project and like, use a basis, use it as a
0:08:12 basis for things that they're building.
0:08:13 So yeah, I think for me it's always been about delivering
0:08:17 a much higher user experience.
0:08:19 I really feel like at some point the web was really focused on how
0:08:25 can we make the web feel native, and that was like the obsession.
0:08:28 And for some reason that like, kind of went out of popularity, but I personally
0:08:33 still care about that as an end user when I use products and they're slow and laggy.
0:08:37 I want everything to be my browser.
0:08:39 I like that and I want people building those things to care
0:08:41 about those things because I'm just going to be happier as a user.
0:08:44 And it's kind of been my.
0:08:45 My reasoning to really like, you know, spread the word about this stuff.
0:08:49 Yeah.
0:08:49 Everything you've just said deeply, deeply resonates with me.
0:08:52 I'm similarly also very inspired by, by the folks at Linear, how
0:08:56 much value they put into the craft.
0:08:59 I was actually just, uh, as a little anecdote, I was just having
0:09:03 drinks last night, uh, with Julian from the, the, the Linear team.
0:09:08 And we were also chatting about this and similar to what you've
0:09:11 described as that it's so tricky.
0:09:13 It never shows up in your user interviews, et cetera, that people say like, Oh,
0:09:18 like I'm really annoyed that this button takes like 300 milliseconds.
0:09:22 But if it was instant, then I think people will really, uh, share that.
0:09:26 And it's basically like a, more of like a death by a thousand paper cuts, and
0:09:30 it's too hard to enumerate the thousand paper cuts, but it's still kind of clear
0:09:35 that the product is not very smooth.
0:09:37 But once you really, once you're using Linear, then there is no going back.
0:09:42 And this seems to be also still like a challenge in terms
0:09:44 of communication for them.
0:09:46 How do they articulate to someone who has not tried it out yet?
0:09:49 What the difference is?
0:09:51 It's that overall quality and, but I think they're doing a great job of
0:09:55 just being sort of like the lighthouse example now of like what that next
0:09:59 generation category defining product feels like and should be like.
0:10:04 So I think they're, they've like bootstrapped their way out of that, that
0:10:07 problem and it's very inspiring for me where I'm like my JIRA is kind of music
0:10:13 apps where I am annoyed by the thousand paper cuts that you have in when you're
0:10:18 using Spotify or SoundCloud, et cetera.
0:10:22 So many of those supposed apps feel more like websites that really like
0:10:27 Winamp was a, or iTunes back in the golden days, that was a much superior
0:10:32 user experience to what we have today.
0:10:34 We have maybe a richer ecosystem in terms of available music, but the actual user
0:10:39 experience that has really suffered and I similarly also care a lot about how
0:10:46 native can you make a web app feel like.
0:10:48 And not just, end up with your ambitions on like a website level.
0:10:54 So, uh, that deeply resonates.
0:10:56 I think there is, it's both, uh, equally exciting to explore that from a user
0:11:00 experience, what really drove you.
0:11:02 But I think there's also a lot of potential from a developer
0:11:06 experience point of view, where I think there's also so much stuff
0:11:11 we just put up with as a developer.
0:11:12 So I'm also curious to hear more on that, but yeah, you, you mentioned that you
0:11:18 had a one to two years of explorations early on that, where you figured out
0:11:24 how not to do it, I'd love to hear a bit more about those failed attempts.
0:11:28 A slower initial page load is worth it
0:11:28 Yeah, so I think, the spectrum really was just us dipping a toe to
0:11:33 then going further and further and further with how much is done locally.
0:11:36 So, I think initially, it's, that sounds weird to everyone, right?
0:11:40 Like, what do you mean replicate the whole data to the end client?
0:11:45 Like, it's too big.
0:11:46 Like, that can't work.
0:11:46 Or like, what about this?
0:11:47 What about that?
0:11:48 What about that?
0:11:49 Uh, so I understand the hesitation.
0:11:51 But any like half step in that direction, it just kind of a gateway to like, just
0:11:55 replicating more and more and more.
0:11:57 Cause you just want more and more and more to be instant.
0:11:59 So I had a very traditional mindset around it, which is, okay, we have an
0:12:03 API, the API serves data and like, we're going to like cache some of that locally.
0:12:07 And I think a lot of people are already doing this.
0:12:09 Like a lot of stuff, like react-query like gives you this starts to like put
0:12:13 you in that direction where just caching stuff and then like refetching, you know,
0:12:17 when the window becomes active again, it kind of gives you some of this like
0:12:20 real time local-first feel, but then you start to hit the limits with that, where.
0:12:25 If you're like, if you're looking for stuff that's not literally in
0:12:28 the exact view, you're then kind of round tripping with the server again.
0:12:32 And I think the key thing to understand is, is if you're building an app that
0:12:37 people are actually using every day, the initial load time is really not
0:12:42 something you need to care about.
0:12:44 The first time they load the app, like let's say they like
0:12:47 log out or it's a new computer or whatever, they're setting it up.
0:12:49 Okay, like maybe they're downloading a couple megabytes of stuff.
0:12:53 That's going to be slower than You visiting some public website that's
0:12:57 like optimized around like the initial load time, of course, but once that
0:13:02 initial cost is paid, every single interaction that they have going
0:13:06 forward from there is insanely fast.
0:13:09 And that trade off is so worth it for apps that people actually use as a joke.
0:13:13 I like to make out is that the web has become so obsessed with
0:13:17 optimizing for websites where people visit and leave as fast as possible.
0:13:22 I'm like, If you're working on something like that, totally get it.
0:13:25 Like totally get all the, the SSR stuff.
0:13:27 Everyone's obsessed with all the, like the infinite levels of like CDN caching
0:13:31 and the little optimizations there.
0:13:32 I totally understand that, like minimizing bundle size, all that stuff.
0:13:36 But a lot of people work on SaaS products.
0:13:38 Most of the products that I use every day are not, don't fit in that category.
0:13:42 I'm using them every day, like just preload stuff for me.
0:13:45 And I feel this way about some of the biggest products, right?
0:13:48 Like think about GitHub.
0:13:49 I'm an open source developer, like, my day to day job is
0:13:52 maintaining open source projects.
0:13:53 I'm in GitHub all day, clicking through issues, looking through
0:13:57 commits, looking at PRs.
0:13:59 It is so frustratingly slow how almost every single interaction
0:14:04 results in like a page load.
0:14:05 GitHub knows, okay, you're not going to send me all of GitHub to me locally.
0:14:10 But you know there's these three repos I work on every single day.
0:14:13 Sync that locally, sync that optimistically.
0:14:15 Like that would save me so much time and frustration and energy.
0:14:19 And actually scratch that.
0:14:20 It's not really about the time.
0:14:21 It's really about the energy for me.
0:14:22 You can spend four hours doing work that saps your energy and four
0:14:27 hours where you feel empowered.
0:14:28 And to me, like good apps like this.
0:14:31 I like feel super empowered and it's not sapping my energy.
0:14:33 I'm not drained after the four hours.
0:14:35 I'm like ready to go on to my next thing.
0:14:37 Right.
0:14:37 And yeah, some of these biggest apps that are productivity apps are so
0:14:40 built like traditional websites.
0:14:43 Definitely.
0:14:44 Yeah.
0:14:44 I mean, the, the use case that you've mentioned in regards to
0:14:47 GitHub is, is an excellent example.
0:14:49 Like for, like you have those.
0:14:52 units that are really self contained, most repos don't have hundred of thousand
0:14:58 of issues it's really easy, like takes roughly the same amount of data that
0:15:03 like your initial JavaScript bundles took to just download the entire, thing as a
0:15:08 SQLite database or like in another format, and then just have it there available.
0:15:13 Since you're navigating so much within the scope of a GitHub repo, whether
0:15:17 it's Between GitHub issues or going to like a pull request or something
0:15:22 and whatever paper cuts you experience there, it really lowers your effort
0:15:27 of like wanting to go the extra mile.
0:15:29 Whether you want to respond to someone's like, in a GitHub comment.
0:15:33 I think, uh, Jamie Kyle, actually, I think he ran a couple of experiments
0:15:37 there that's literally faster on GitHub to open a new tab for a link and have,
0:15:43 get the server side rendered stuff than dealing with like the, The, the rail
0:15:46 style in navigation on the existing site.
0:15:50 And that speaks exactly to, to the symptoms that you've,
0:15:53 that you've described.
0:15:54 I will also call out a project.
0:15:57 I don't fully remember the name anymore, but someone on Twitter, I
0:16:00 think was working on, on exactly that, like a little GitHub client that is
0:16:05 local-first inspired, that pulls down your data that you're dealing with to
0:16:10 make exactly these interactions fast.
0:16:12 Maybe you know the name.
0:16:13 Yeah, so I actually tweeted asking about this.
0:16:15 I remember seeing it and I couldn't remember it.
0:16:17 And I think it was, uh, by Devin, the Parcel JS.
0:16:20 Yeah, so I saw him messing around with that.
0:16:22 I don't know if he ever, like, finished it or released it or anything, but
0:16:26 yeah, this is so desperately needed.
0:16:29 GitHub isn't going to do it, I don't think, because it's so outside the
0:16:32 scope of how their system works.
0:16:33 But just someone, please, just build a thing that syncs the
0:16:36 issues and PRs optimistically.
0:16:39 And you're going to save me so much.
0:16:40 I'll pay for this product easily.
0:16:42 I don't know how big the market is for people that care this much, but it
0:16:45 doesn't seem like that much work because it's just a single repository view
0:16:48 and some of the stuff that's in there.
0:16:51 And you could totally do this.
0:16:52 Yeah.
0:16:53 This is kind of what I was saying before.
0:16:54 I'm mostly speaking as a developer, like building these things.
0:16:57 But the end thing I care about is as a user.
0:17:01 I just want more of this stuff out there in the world.
0:17:03 So I'm not as frustrated.
0:17:04 I definitely agree.
0:17:06 And like, I applaud you for like going that adventurous path and that extra
0:17:10 mile with SST console, since I think you had the right intuition there and it is
0:17:16 paying off in terms of just how fast that feels to use and how much, like you say,
0:17:21 like it no longer drains your energy.
0:17:23 Yeah.
0:17:24 It gives you energy using that.
0:17:26 And once you had that experience, you'd really like every loading spinner
0:17:30 that you see is so much more painful afterwards when you're like using,
0:17:35 for example, the, Cloudflare console, it's like the same thing there.
0:17:38 Like you're within a project , you have that many deployed workers and
0:17:41 you just want to navigate between that.
0:17:43 It's fine that my logs stream in.
0:17:46 But all the metadata around that should just be instant.
0:17:49 It's a tiny amount of data.
0:17:52 And like the majority of apps, if you really look at what data people are
0:17:55 constantly going between, it is so small.
0:17:58 So yeah, you figured out like the, the patterns early on or rather that you've
0:18:02 realized, okay, you started with a bit of caching, a bit of more caching, a
0:18:06 bit of more caching, and you didn't quite find the right line to draw.
0:18:10 So you just, okay.
0:18:11 We're going to just bring over all the data.
0:18:14 Did you have other sort of learnings where you had to rewire your brain?
0:18:19 Local-first makes app development simpler
0:18:19 Yeah.
0:18:19 So I think, uh, one other middle step we had was we tried it through GraphQL.
0:18:24 We weren't particularly interested in the GraphQL part.
0:18:28 It was, it just happened to be that, uh, Urql, the GraphQL client.
0:18:32 It implemented a lot of, uh, the local-first stuff like you could
0:18:37 replicate the whole database locally and because GraphQL has a
0:18:40 nice, idea of like relationships between objects, the data format
0:18:44 locally could be pretty intelligent.
0:18:45 like, downloaded 1 thing, it knows how it's related to another thing.
0:18:48 So if you query it from a different path, it can, like, resolve it locally.
0:18:52 So there's just some clever things that it did.
0:18:54 And we thought that was really cool.
0:18:55 But what ended up sucking was we didn't really like GraphQL.
0:19:01 And everything you did, even local operations, required GraphQL as input.
0:19:06 which again is fine.
0:19:07 It's just, it just wasn't really clicking for us.
0:19:10 And again, it still had this, uh, There was a limitation of like, it
0:19:15 wasn't really meant or initially designed to have all data locally,
0:19:19 so it's all like, there's always like some stealing or some performance
0:19:22 issue or something you run into.
0:19:24 So when we went all in on having, okay, like we, the system is primarily
0:19:28 designed around syncing the data locally.
0:19:30 What we found actually, and I think the Linear people talk about this too, is.
0:19:34 The developer experience around this became a lot more simple.
0:19:38 So my wife, who I work on this stuff with, she is not an engineer.
0:19:43 She does everything else outside of it.
0:19:44 But in the past couple of months, we're like, why are we drawing that boundary?
0:19:48 Just learn how to be more hands on.
0:19:50 And so she's been learning like how to actually like write the code
0:19:53 and build these things and she's making like fantastic progress.
0:19:56 One of the things that's been crazy helpful is.
0:20:00 All the data's just there locally.
0:20:02 So for her, even though she's a beginner, it's such a simple model.
0:20:05 She's not like figuring out the round trip with the server, like syncing all that.
0:20:10 Like, I handle all that, and I make sure, like I figure out how the data looks like
0:20:14 on the back end, and I make sure it's all synced correctly to the front end.
0:20:17 From there, there's not all this weird like, loading states, or like fetching it,
0:20:21 or like just a whole bunch of complexity around getting data back and forth.
0:20:25 It's solved in one part of your app, and then you never have to
0:20:28 think about it anywhere else.
0:20:29 So just from like a team productivity point of view, like she can build
0:20:33 any feature she wants, even if I didn't like explicitly think about
0:20:37 it from the backend point of view, because she has all the data locally.
0:20:41 She's like, I want to create a view that searches through this set of data.
0:20:43 She can just go do that.
0:20:44 All the data is there.
0:20:45 Very, very straightforward.
0:20:47 And it's actually wild how much of a productivity boost that has on
0:20:51 your team, because you're not like constantly building these like back
0:20:54 and forth with every new feature you're not rebuilding another way to
0:20:57 like sync that data back and forth.
0:20:59 and it's been amazing.
0:21:01 That's so liberating.
0:21:02 Uh, we talked about this also in the recent episode with Kyle, who drew the
0:21:06 comparison of like going from jQuery to React where React freed you up of like
0:21:11 that manual view maintenance and now going from like the, the manual state
0:21:15 transfer across different environments that frees you up of like that data
0:21:20 management and you can now actually.
0:21:22 Focus on what matters most, like building a great user experience
0:21:25 and putting the effort into the pieces that do really matter.
0:21:29 And that simplification that is just so, so hard to overstate how nice that is.
0:21:35 And I think that also unlocks a whole bunch of like new.
0:21:38 tooling.
0:21:39 So for Overtone that I co developed with the project Rffle, or now called
0:21:45 LiveStore, it's always been a first class citizen to have great dev tools.
0:21:49 And one of the parts of the dev tools is to have a data browser in there.
0:21:52 So it basically feels like a Google spreadsheet and really it
0:21:56 also acts as a Google spreadsheet.
0:21:57 You have, you have like visual view.
0:22:00 on all of your data, if you change something such as like a playlist
0:22:04 title in that data browser, it like automatically updates in your app.
0:22:09 And there's no question of like, Oh, do I not need to like
0:22:12 send this to this REST request?
0:22:14 But do I need to also like, Invalidate this in Redis.
0:22:18 No, you just like set the data and there it is.
0:22:21 Yeah, that's great.
0:22:21 I mean, a local data route is actually something that we're definitely
0:22:24 missing, but that's a, yeah, it's like it enables so many things like that.
0:22:29 Just the debug ability and observability of what's going on and just being
0:22:32 able to change something in one place and have it update everywhere, like
0:22:35 in your view and in the backend, it's just so, it's so much simpler.
0:22:38 And it's weird because I feel like apps used to kind of work this way.
0:22:42 Like when I got started, I was building desktop applications.
0:22:46 And I guess there wasn't really a cloud component in some of
0:22:49 the initial things that I built.
0:22:51 And they were this simple because the data was just local and like
0:22:53 you'd hit a button and you like mutate the data and it's it's there.
0:22:56 So yeah, to me it feels like returning to a simplicity with like
0:23:00 much more power and capabilities that we didn't have back then.
0:23:03 Exactly.
0:23:04 Plus we now also get the power of the cloud for collaboration and
0:23:07 like a lot of the, the nice pieces.
0:23:10 But I think there's just been an over investment over the last 10 years
0:23:14 into having everything be so cloud centric that like you built like
0:23:19 even a local calculator probably as like a remote rendered server app.
0:23:24 And, I think now also bringing more investment into kind of back to the roots,
0:23:30 uh, in, in this way of building, building apps, I think this will also help more
0:23:35 people who are not quite as adventurous as you are to, to really explore this before
0:23:45 Local-first data patterns
0:23:45 Yeah, and like there are, like a lot of stuff becomes simpler.
0:23:48 There's some new stuff you have to learn, of course, like with
0:23:50 any new paradigm, there's, things that are a little bit different.
0:23:52 I think some of those involve things like, so in our case, in the Bumi example,
0:23:57 we unfortunately had customers that had too much data, where it wasn't as
0:24:01 simple as just syncing it all locally.
0:24:03 So we have to think of like some new kind of like UX related patterns where
0:24:08 we kind of optimistically sync stuff that we think the user will care about.
0:24:12 So like the first time you visit a patient, it might take a little
0:24:15 bit to load because we didn't sync all the patients locally.
0:24:18 We do sync like a shallow version of the patient locally for everyone, so they can
0:24:23 search through all of them really quickly.
0:24:25 But to get into the full details, like you might not.
0:24:27 That's too much data to send to everyone.
0:24:29 So the first time you go there, it'll be a slow load.
0:24:31 But from that point, we kind of flag them as, Oh, this
0:24:33 user cares about this patient.
0:24:35 And from then on, we'll constantly send them updates.
0:24:37 If they haven't visited the patient's profile for like two weeks or
0:24:40 whatever, then we'll kind of unflag it as something that they care about.
0:24:43 These are like new patterns that, you know, they don't really
0:24:46 exist in a traditional app.
0:24:47 But this mixture of local and cloud, you can get pretty far with tricks like that.
0:24:52 And we kind of have to learn some of those tricks and some of those ideas.
0:24:55 Because we have a whole like We have, I forgot what we called it, but
0:24:58 it's like, uh, We have like a system where you can easily flag stuff as
0:25:02 a user is interested in this thing.
0:25:03 And if you flag it, it starts getting synced and then it'll get unsynced
0:25:06 after some window that you specify.
0:25:08 So we kind of have to like, you know, think about that and, and
0:25:10 create a framework around it.
0:25:11 But that's one.
0:25:12 The second thing is like, obviously handling, And this
0:25:15 isn't unique to local-first.
0:25:17 Anywhere you're doing optimistic things, obviously there can be
0:25:21 errors that happen on a delay.
0:25:23 Again, it depends on the type of application.
0:25:24 Like a music player, probably, the syncing is probably like pretty
0:25:27 straightforward, but for something that's Looks more like a traditional SaaS app.
0:25:32 There might be sources of truth that can't be validated entirely locally.
0:25:37 So you'll end up with situations where the user does something, then goes
0:25:40 away, then the error shows up later.
0:25:42 And like, you need like a whole different UX pattern when you can't block the user.
0:25:47 It's worth doing because 99 percent of the time they don't hit that error.
0:25:51 So it's good to let them move on.
0:25:52 But you have to handle a case where, where they do.
0:25:54 So there's different problems that show up, but again, it's all in the name
0:25:57 of a better experience to the user.
0:26:00 So totally worth it.
0:26:01 So, let's say you have some kind of.
0:26:03 You can create a new field that needs to be globally unique in your system.
0:26:06 So let's say, uh, I mean, we can just use Linear as an example.
0:26:10 Like, you can create a new project in Linear, but the name of the
0:26:12 project needs to be unique.
0:26:14 there's an impossibly small chance that you create it and you move on, but someone
0:26:19 had created it at the same time, because they thought it was their job to do it.
0:26:23 And there's like an issue, because your write maybe got rejected.
0:26:26 in a typical UI, when you create the project, you would see a spinner.
0:26:31 Spinning.
0:26:32 Okay, created.
0:26:33 Because you have a spinner there, you can, like, make sure stuff gets written
0:26:36 correctly and then you don't let the spinner come back till you know for sure.
0:26:40 It's good.
0:26:41 Um, so anywhere with this like unique feel type of situation,
0:26:43 we run into this problem.
0:26:45 Our fix is actually pretty simple.
0:26:47 We just have like some kind of like context thing of like pending
0:26:50 stuff that hasn't been confirmed.
0:26:52 And if it comes back with an error, we just pop up a toast that
0:26:55 brings them back to the original.
0:26:57 We, like, reload that original content.
0:26:58 If they want, they can click back and go back to where they were.
0:27:01 And, like, you know, change the issue that they had.
0:27:05 So I think we found that pattern to work pretty well.
0:27:08 Obviously, it's like, the example I gave is really stupid.
0:27:11 Like, no one is ever going to run into that.
0:27:14 There's some examples that are a little less stupid, where it is reasonably
0:27:17 possible that it could happen.
0:27:18 But we found this idea of, like, preserving the context of the
0:27:22 UI and bringing them back to it.
0:27:24 If the error happens, they can opt to go back.
0:27:27 We found that to work pretty well.
0:27:28 Yeah, I think that's a very elegant solution for this.
0:27:31 I mean, another possibly even more aggressive solution to this
0:27:35 would be to say to gate this feature behind being online.
0:27:39 And to actually like establish some notion of like a global transaction for
0:27:44 that and, only let the user pass through this intentional bottleneck if that
0:27:49 has happened, but the way how you've designed this in a asynchronous way.
0:27:54 I think it's also very elegant.
0:27:56 but I think this is the nice thing that like local-first affords you or forces
0:28:01 you to do is like, it frees you up from a whole bunch of stuff you no longer
0:28:05 need to do, but it really forces you to think about carefully, what are the
0:28:09 domain requirements of your specific app?
0:28:13 And if your domain expert from the app says like, Hey, this is
0:28:16 what's really important here.
0:28:18 There cannot be two project names with the same exact name.
0:28:23 Then like you can actually put in the extra efforts to enforcing that.
0:28:27 And this is what makes the app worth it later.
0:28:29 Yeah.
0:28:30 Yeah.
0:28:30 And it's, yeah, it's not all or nothing.
0:28:31 You can opt in.
0:28:32 So the thing that you said, we are in the SC console.
0:28:34 We do that when you're creating a new workspace, we actually do have a
0:28:37 spinner there because it's like weird to like, Create a new workspace and get
0:28:41 kicked back 'cause the name was taken.
0:28:43 So yeah, we, we hold you there And that's like, you know, a more
0:28:45 traditional experience and that's fine 'cause that's like a very small
0:28:49 percentage of the app where you're like creating a new workspace.
0:28:53 You do that once when you sign up and you never do that again.
0:28:55 So yeah, you can kind of granularly pick where you want a more traditional
0:28:59 blocking approach and where you want an optimistic approach.
0:29:02 And I think a lot of the people that are maybe skeptical of the local-first
0:29:05 thing, I think they tend to imagine it in these extremes of like.
0:29:09 You have to sync all of your data and obviously that won't work.
0:29:12 Or like you have to have everything be optimistic and obviously
0:29:14 everything can't be optimistic, but you can really pick and choose.
0:29:18 It's more about what you default to.
0:29:20 And then you opt out of It's good to default to optimistic first.
0:29:23 Cause that's, what's great for the user.
0:29:24 Right.
0:29:25 I think in the, in your context of building SaaS apps, I think there's
0:29:29 kind of layers to this entire thing.
0:29:31 There's like the global system.
0:29:33 That you're still in control of.
0:29:34 That global system is probably not local-first by all the ideals, but once
0:29:40 you create an account or once you've created a project, and now you enter like
0:29:44 a smaller scope of that overall system, and that now is very much local-first
0:29:50 because this is where it actually matters.
0:29:51 It's okay if your users sign up.
0:29:54 takes half a second to load.
0:29:56 But once you're in your productivity environment, this is where you
0:29:59 want to really have unlock the benefits that local-first gives you.
0:30:03 Yeah, exactly.
0:30:04 The data, what is the day to day workflow like?
0:30:06 And that should be, that should be, you know, an excellent experience.
0:30:09 I think the other area, and we talked about this a little, is there's also the
0:30:15 desire for apps that don't die because a company went out of business or like,
0:30:20 you know, They were forced to find a business model that didn't make sense
0:30:23 for the idea that they were working on.
0:30:25 And I think this does make a lot of sense, I think.
0:30:27 If you think about something like a, like a video game.
0:30:30 I mean, video games are different now, but like, you know, there was a time
0:30:33 where you would buy the video game.
0:30:35 It was a finished product, and it was on, like, a physical thing, and
0:30:39 you could just run it and play it.
0:30:41 And.
0:30:42 You had that forever.
0:30:43 So, but I mean, now you have like some games that require you to be online
0:30:47 or it's a, it's a hybrid of both.
0:30:48 And like, you can imagine how at some point this game won't be playable anymore.
0:30:53 And that's happened to a few things.
0:30:55 I think people feel that way about applications as well.
0:30:57 And I totally get that.
0:30:58 I personally don't work on anything where that's like the critical
0:31:02 burning desire where like, you want it to like really run locally.
0:31:06 You want, you care about the privacy, you care about whatever.
0:31:08 I like totally get all of that.
0:31:10 It just hasn't intersected with like the areas that I focus on.
0:31:13 So for me, it's been more about, uh, just the experience side of it.
0:31:18 And I think the reason is a little bit tricky to go to that extreme in SaaS.
0:31:22 is a lot of like a portion of your value is in the end experience.
0:31:27 And like we talked about, I think people are under delivering there,
0:31:30 but usually it's also tapping into some kind of bigger data set or bigger
0:31:35 capability that can't really run locally.
0:31:38 So it's usually a mix of the two things.
0:31:40 So I typically will have to mutate the data outside of
0:31:43 the user interacting with it.
0:31:44 So if you look at something like, uh, like Radiance, so this is
0:31:47 going to be a personal finance app.
0:31:49 You can totally build a fully local-first version of this
0:31:51 that runs entirely locally.
0:31:53 That whoever's building the app, it can be totally encrypted where they don't even
0:31:55 have access to seeing any of this stuff.
0:31:57 And there's like value in building something like that.
0:31:59 But, you know, with all these advancements in AI and LLMs, those can actually impact
0:32:05 Personal finance apps a lot in terms of like making sure that data is cleaned
0:32:08 up correctly, auto categorizing, like all the things that sucked historically
0:32:11 about these applications, LMS have a lot of potential to fix that, but
0:32:17 there's not really a good way to do that in a local-first way, at least today.
0:32:20 So that's why for us, you know, for building this thing,
0:32:23 it's not going to be this.
0:32:25 thing that runs entirely locally because we still want the ability to
0:32:27 like process your data using tools and technologies that, you know,
0:32:32 unfortunately can't run locally today.
0:32:34 Yeah, I think you've touched on a couple of really interesting points there.
0:32:38 So the, I think right now, the canonical definition of like, what is local-first
0:32:43 software is as according to the Ink and Switch essay that lays out the seven
0:32:48 ideals of local-first and I think you're, You're, nicely sticking to the first four,
0:32:53 which is like about the loading spinners and that it works offline and so on.
0:32:57 And I think what you've just hinted at, what you don't do yet is what
0:33:01 local-first calls like the long now that your app like lives on, even if the
0:33:07 creators are no longer working on it.
0:33:09 And that's very understandable.
0:33:11 That takes a lot of time to, and effort to put into.
0:33:14 And given that you just have so much time to work on the app,
0:33:18 that is not your highest priority.
0:33:19 However, what I think is still nice and a glimmer of hope there for the entire
0:33:25 category of local-first inspired software is that if at some point you say like,
0:33:30 okay, I'm winding down development on this app, then you could still much more
0:33:36 easily to put in a bit of extra effort.
0:33:38 to now round up the project in a local-first way.
0:33:42 I think we've seen a really nice example of that with another personal finance
0:33:46 app called Actual Budget by James Long.
0:33:49 And so as he no longer had time to work on that project, it was so much easier now
0:33:56 to transition the app from something that he hosted as a cloud service to something
0:34:00 that people can just run by themselves.
0:34:02 If you build like those monstrosities of like giant Kubernetes cloud things,
0:34:08 it's really, really hard to like, tell someone how to easily just download a DMG
0:34:13 and run this on your MacBook, whereas if your app is local-first to begin with.
0:34:18 Then, I think it's much easier to repackage the app that you've built.
0:34:23 And you can trim away a lot of like the multi tenant stuff that
0:34:26 you need about SaaS and just package the, the productivity
0:34:30 aspect of the core of your app.
0:34:39 Self hosting
0:34:39 Yeah, I agree.
0:34:40 I think so.
0:34:41 And with Radiant, we're actually, so because we can't.
0:34:44 Do this thing where it's like end to end encrypted and because of
0:34:46 what, what our goals are, instead, we're making it dead simple to
0:34:51 fully run the whole system yourself.
0:34:54 If you care about hosting yourself and you want all the data and a big part, and to
0:34:58 be honest, that's a lot of what SST does.
0:35:00 SST helps you ship very complex software multiple times in multiple environments.
0:35:05 and so, because Radiant is an SST app, it is very easy to point it
0:35:09 at your own private infrastructure and say, I'm just going to have
0:35:12 a self hosted version of this.
0:35:14 And it's, and we're making sure it's like, As simple as it can be to do
0:35:18 that, and get as close to, like, using the hosted version because there's
0:35:23 like some weird benefits of that.
0:35:24 Like, so this version that we're building is going to be mostly built on Cloudflare.
0:35:28 If a lot of people end up self hosting it, that's great because
0:35:31 Cloudflare is paying for the usage.
0:35:33 Like, The free tier is coming out of each individual's deployment.
0:35:37 They're like self deploying it into CloudFlare.
0:35:39 And that's like an interesting model for, I don't think for radiant, it's
0:35:42 like particularly interesting, but if you look at, um, there's another
0:35:45 project by, uh, Ben Vinegar, he works at Sentry, called CounterScale.
0:35:50 So this is a classic, like Google analytics type product, right?
0:35:54 It does like this web analytics, the basics, and it's very early on.
0:35:57 But it's not a hosted project.
0:35:59 It's just something that deploys into your own CloudFlare account.
0:36:01 So he can have a million users using it for free without ever
0:36:05 really, you know, paying for that because, you know, CloudFlare is
0:36:08 much more set up to offer that.
0:36:11 I'm very interested in that model.
0:36:12 Uh, cause I think for a lot of infrastructure pieces
0:36:14 like that, it is a nice.
0:36:16 To have it alongside the rest of your infrastructure.
0:36:18 I worked a lot in healthcare environment, which has a lot
0:36:21 of compliance requirements.
0:36:23 And oftentimes I couldn't use the tool I wanted to use because it
0:36:26 wasn't hostable in my own environment.
0:36:29 So, um, we're pretty excited about like letting people do more of that.
0:36:33 I love that.
0:36:34 And I think this is like intuitively.
0:36:37 It should be easy to self host your own software, like whether it's like
0:36:42 some company running it or whether I just like take the software, put
0:36:46 it on my Raspberry Pi, put it on, on Cloudflare or AWS, but in reality,
0:36:52 that's very much the exception.
0:36:54 I'd be curious whether you can share a bit more of like the reasons that
0:36:57 you see why that's so hard and how you're trying to make that easier.
0:37:01 Yeah, I think, uh, it's funny because there's a weird alignment
0:37:05 if you think about this.
0:37:07 We are a small team.
0:37:08 If our system is really complicated to run, that sucks for us.
0:37:12 If we can make our system really easy to run and really low overhead and we care
0:37:15 about that more than everything, it kind of starts to look like something that's
0:37:18 easy to self host by anyone, right?
0:37:21 So I think for us, like, a lot of times we'll choose architectures that look
0:37:24 weird because they're like, Oh, that looks like the fourth option on the list
0:37:28 of the ways they could have built it.
0:37:30 But it's because we really, really care about, low operation overhead long term.
0:37:38 So even if it's like, you know, 20 percent harder to build up front, if
0:37:41 it results in like less babysitting on our end, we'll like choose that option.
0:37:46 And it's because we're very committed to continuing to be a really small team.
0:37:49 And so we'll, we'll end up picking those options and those options happen
0:37:52 to align with like, what's, what's simplest for, for the end end user,
0:37:57 if they're self hosting, I will say like there is a version of doing
0:38:00 this, which we don't do, which is.
0:38:03 Building your stuff in the most, like, neutral way possible, so it
0:38:06 can run in literally any environment.
0:38:09 I definitely get that, but you do end up having to run a lot of
0:38:14 infrastructure on your own to, like, get any complicated application working.
0:38:18 If you do it in a totally neutral way.
0:38:20 We kind of picked a middle ground where it's like, we do rely a lot on, like,
0:38:24 in this example, like, we're going to be using CloudFlare, we're going to be using
0:38:28 workers, we're going to be using their queues, we're going to be using their
0:38:29 PubSub, all the CloudFlare native things.
0:38:32 So, yeah, if you want to go take that and run it inside, like, just
0:38:37 a standard server you have, it's going to be a little bit challenging.
0:38:40 And like, there are adapters and stuff, and you can figure that out.
0:38:43 But we're starting with just making it runnable in your own cloud environment.
0:38:49 So you can sign up for a Cloudflare account and run it.
0:38:51 I know that doesn't like hit the exact extreme of like being able
0:38:54 to fully run it yourself, but we think it's like a nice middle ground
0:38:57 for a lot of companies, right?
0:38:58 Companies typically are already using some form of this.
0:39:01 Getting this stuff deployed into their own account.
0:39:03 I think it works well.
0:39:05 What's weird is you ask, like, why isn't this more common?
0:39:08 I think it's actually common in this weird way that people don't expect.
0:39:13 A lot of companies build SaaS software, right?
0:39:16 They'll build like, I don't know, let's say, let's take some random common
0:39:20 thing, like Auth as a service, right?
0:39:21 Like, I'm going to build Auth as a service that people can use.
0:39:25 And they initially launched that as like a hosted product.
0:39:28 And nobody uses it except for people that have no money.
0:39:32 So they have like a lot of users, but you know, these users don't pay a lot.
0:39:35 They start to try to move up, up market.
0:39:38 They end up with bigger companies, you know, medium sized
0:39:40 companies, enterprise companies.
0:39:42 They'll all love the product, but refuse to use a hosted service.
0:39:46 So then they're forced to figure out how to make their stuff run
0:39:49 inside the customer's AWS accounts.
0:39:52 So if you do look at a lot of these companies, they kind of
0:39:54 do have this hidden, like thing that they eventually figured out.
0:39:57 I think companies should realize they're going to end up in this place anyway.
0:40:00 Like it's very hard to build a big business purely off of a hosted thing.
0:40:04 Like some people do it when you really have like a large market,
0:40:08 but oftentimes you're forced to.
0:40:09 Bring yourself inside someone else's environment.
0:40:11 So I think one way or another, you're likely to hit that.
0:40:14 So it's good to plan for that upfront and assume that you're going to run into that.
0:40:17 And we, because we're like, We're more in the infrastructure space.
0:40:20 We kind of expected that from the beginning, which is why we care a little
0:40:23 bit more about making all that possible.
0:40:26 So let's imagine I want to follow this paradigm for Overtone.
0:40:32 And I do think that Cloudflare could be a very interesting fit for that in
0:40:35 terms of the modern primitives that it provides, so what would I need to do as
0:40:41 the application developer of Overtone who buys into that vision and says
0:40:45 like, Hey, I don't want to operate like the cloud thing for that, but I want
0:40:49 to empower every user to deploy their own for the benefits that it provides.
0:40:54 What would I as the application developer need to do to make that happen?
0:40:58 And then also follow up question.
0:41:00 What does someone who wants to deploy that Which sort of additional stuff
0:41:04 do they need to deal with as opposed to just using something like Spotify?
0:41:08 Yeah.
0:41:09 Yeah.
0:41:09 Cool.
0:41:09 So I think, I think the simplest way to think about it is how hard is it you
0:41:13 for you to spin up a staging environment for your own application, right?
0:41:17 You want to create an exact copy of your environment, but you
0:41:20 know, just the staging version.
0:41:22 So this requires bringing up all the same infrastructure.
0:41:24 It requires like, you know, running your database migrations
0:41:27 to get the schemas running.
0:41:28 Um, requires a bunch of things.
0:41:29 And, you know, the obvious thing is you should be using infrastructure
0:41:32 as code to help you do this.
0:41:33 You define all your infrastructure as code so you can point it at different
0:41:36 environments and run entire copies of it.
0:41:39 That's like the bare minimum.
0:41:41 If you yourself can quickly create another environment for yourself,
0:41:45 you've kind of solved the problem.
0:41:46 Now someone else can follow those same steps.
0:41:49 Where they're just cloning your project and running.
0:41:52 You might be using Terraform, you might be using SST, whatever it is.
0:41:55 Uh, you can do a thing, deploy with your credentials.
0:41:58 And the same thing ends up in your account.
0:42:00 Where this is a little bit challenging is updates.
0:42:03 So obviously, you know, you have new versions.
0:42:05 People can clone and redeploy, whatever.
0:42:07 But there's sometimes operationally challenging updates.
0:42:11 Like you might have like a schema change.
0:42:13 You might have, uh, like data needs to be migrated.
0:42:16 So, ultimately, the thing to always go back to is how do you make it
0:42:21 easy for your own team to do that?
0:42:23 Are there programmatic ways of doing all this?
0:42:25 Or, like, if you need to do ad hoc random stuff and that's part of your
0:42:29 workflow, it's going to be annoying for your end user to self host because
0:42:32 then you need to, like, send them the instructions, they need to do it,
0:42:34 they might, like, do it incorrectly.
0:42:36 So, if everything is tracked in code and is automated and is
0:42:39 programmatic, It's good for your team.
0:42:41 That's good for the end user.
0:42:43 and for an end user, in terms of what they should expect, if you are
0:42:46 using some version of the cloud, you should hope that the thing you're self
0:42:51 hosting is taking advantage of as many managed services as possible, right?
0:42:55 So I had this issue with PostHog.
0:42:57 So PostHog is an open source analytics tool.
0:43:00 And when I was exploring it for my healthcare thing, I was like,
0:43:02 okay, we'd have to self host it.
0:43:04 Let me go look at the first self hosting steps.
0:43:07 Step one, set up Kubernetes.
0:43:09 Right, immediately there, I'm like, I like, found a way to finally free myself
0:43:14 of Kubernetes for my main application.
0:43:16 I don't want to like go, have to go manage a Kubernetes cluster
0:43:19 again, just for this thing.
0:43:21 So you should hope that, you should pick tools that use
0:43:25 managed, versions of these things.
0:43:27 That's why, like, we typically focus a little bit more on some of the
0:43:31 serverless stuff, because it's very easy.
0:43:33 If our app just runs as a Lambda function inside of someone's
0:43:37 AWS account, or as a Cloudflare worker, there's almost no overhead.
0:43:41 You're not like, you don't have to like set up like Datadog
0:43:44 to like monitor the memory and like scale this up, up and down.
0:43:47 It sucks to do that for like a small tool that you're adding to your project.
0:43:52 So we try to make use of managed servers as much as possible so that the end user
0:43:56 doesn't have as much operational overhead.
0:43:59 and again, some people are willing to do that.
0:44:01 It's just, uh, it's obviously a spectrum with all of these things.
0:44:04 I do think it's a double edged sword while it like really takes away that operational
0:44:09 burden and operational overhead.
0:44:11 It's not just about, uh, deployment cycles and like the update cycles of the app
0:44:17 that you're deploying, you potentially also need to update a, like from database
0:44:22 version A to database version B of like just a database server that's running or
0:44:26 like your analytics server or whatever.
0:44:28 So that certainly takes a lot more effort.
0:44:31 However, on a longer time horizon, if you do rely on managed services,
0:44:36 they might just at some point send out a notice and say like, Hey, next
0:44:40 quarter We're shutting down like that plan that you're relying on.
0:44:44 So you're also in some regards might be building on quicksand.
0:44:48 I think the, the larger a services such as Cloudflare, I think the
0:44:53 chances that the rug is being pulled underneath you are probably lower.
0:44:57 But it's always a double edged sword.
0:44:59 And so my preference typically is in terms of the architecture that I'm using
0:45:05 is like to go as simple as possible.
0:45:07 This, for example, why I'm also very drawn to SQLite and I love the, all
0:45:11 of the, the new tooling being built around SQLite since SQLite that's, no
0:45:16 one's going to take that away from me.
0:45:17 It's just like a little file.
0:45:19 That I can put on a SD card or whatever.
0:45:22 And, uh, that's still gonna like similar to that computer game from like the 1980s.
0:45:28 that's still gonna work, in, in the future.
0:45:30 And I think that's a great way to preserve data and you can
0:45:33 still do so much with that.
0:45:35 So I think that's sort of like a third option, uh, instead of
0:45:39 going with like hosted or, Very scary self hosted infrastructure.
0:45:44 If you make the self hosted infrastructure just that simple to
0:45:48 rely on something like, like something that's almost serverless by default,
0:45:53 like SQLite, I think that's a, that's a very attractive idea for me.
0:45:57 Yeah, no, I agree.
0:45:58 And with everything I'm saying, it's always like you have
0:46:01 to exercise your judgment.
0:46:02 I'm speaking from the things that I typically have worked on and
0:46:05 I think this is where we landed.
0:46:06 but yeah, if I was working on something that had different requirements,
0:46:09 like, yeah, having like the simplest approach, uh, makes sense.
0:46:13 The only reason that we have to do this is because we work on stuff
0:46:17 that is like one of our tools is.
0:46:20 Like, uh, like issues, like, kind of like how Sentry offers,
0:46:23 like, issues that extracts.
0:46:24 So we need to process, like, a large amount of logs, uh, because
0:46:28 some people have, like, you know, like, billions of invocations a day.
0:46:31 So it's not the type of thing that we can really simplify, like, we can't
0:46:34 just give you, like, a single container.
0:46:36 And this, because that's going to get overloaded very quickly.
0:46:38 So the options for us are some crazy Kubernetes thing, or we
0:46:42 just take advantage of AWS Kinesis and all these things that are
0:46:45 built in that are lower overhead.
0:46:47 Um, but, you know, if those weren't my requirements, I would
0:46:49 probably opt for something similar.
0:46:51 And yeah, at the day, it always just comes down to like, have good judgment.
0:46:55 With whatever you're doing.
0:46:57 Yeah.
0:46:57 I think it's just as web developers, we're just so like in, in our like dependency
0:47:04 fury in a way where like, we just like npm install this, npm install that, and
0:47:09 we also not just package dependencies, but we also like add infrastructure
0:47:14 dependencies left and right to something, I think is a big contributor, contributor.
0:47:19 Why the long now aspect of local-first software is so hard to achieve.
0:47:24 So I'm always, uh, trying as hard as possible to avoid dependencies,
0:47:29 whether it's package dependencies or whether it's like infrastructure
0:47:33 dependencies as much as possible.
0:47:35 But it's always a trade off since they do sometimes can
0:47:38 really save you a lot of time.
0:47:39 Yeah.
0:47:40 Yeah.
0:47:40 I think for us, we kind of land in this middle ground where
0:47:42 we'll commit to one thing.
0:47:44 But then we'll reject a bunch of other things.
0:47:46 So, there's this phenomena happening right now, where, uh, you have these large
0:47:51 cloud providers that offer these services.
0:47:53 The services aren't like, The best, most wonderful things to use.
0:47:58 There's a bunch of companies that'll like, make a copy of just that one
0:48:01 service, but do it like 10 times better.
0:48:04 It's often really compelling, and like you, I can see why people are tempted
0:48:08 to adopt every single one of these, and people end up with a stack where it's
0:48:11 like, It's my application and sitting on top of like 10 different other vendors.
0:48:17 And these 10 vendors are also startups, you know, like it's unclear if they're
0:48:21 going to be around for a while.
0:48:22 So for us, we like as tempting as it is.
0:48:25 And some of it has nice as some of these offerings are like, we never use those.
0:48:28 We just stick to the most lowest level primitives that we can be sure are
0:48:32 going to be around for a long time.
0:48:34 And we'll commit to those.
0:48:35 Like, we're going to accept the fact that if something
0:48:37 happens to them, we're screwed.
0:48:39 More likely we're going to die before they do.
0:48:40 So that makes sense, but like, you know, we won't, we won't apply that everywhere.
0:48:44 So again, it just comes down to like having the right judgment
0:48:50 Updating a local-first app
0:48:50 That makes a lot of sense.
0:48:52 So you mentioned in terms of the deployment cycle, also the update cycle
0:48:56 of your application, and now in the.
0:48:59 local-first way, there is, uh, primarily you need to think about how do I
0:49:03 update the local-first app itself?
0:49:06 So some certain things are easy to deploy, like a, a new component
0:49:10 version of your UI that's, that's easy.
0:49:13 But now that also all of your data lives in the client, the schema of your
0:49:18 data or like the shape of your data is possibly also going to evolve over time.
0:49:22 And there's different ways to deal with that.
0:49:24 So I'm curious how you've handled that.
0:49:26 as well as possibly also the same problem applied to your cloud component.
0:49:31 Yeah.
0:49:31 So in terms of the data locally, we've never done anything sophisticated here.
0:49:35 We've always just blown it all away.
0:49:36 If we have to do some kind of severe breaking change, we will just update like
0:49:41 the big version number and the app will erase everything locally and re sync.
0:49:46 It's not a huge deal.
0:49:47 It's never like massive amount of data.
0:49:49 I think I can see a world where this is, and already it's actually not
0:49:53 too different than changing your back end database schema because
0:49:56 you have similar issues, right?
0:49:57 Like you want to make backwards compatible changes as much as you can because
0:50:01 you don't want to have to like force changes in your application code and
0:50:03 force deployments of those together.
0:50:05 So similarly, most of the time you can do something backwards compatible.
0:50:09 If you totally mess something up, which obviously happens sometimes,
0:50:11 yeah, we just blow it away.
0:50:13 We haven't really found the need to do anything more sophisticated
0:50:15 in what we have, like.
0:50:17 Migration scripts that run locally or anything.
0:50:19 I can see how that's a case for if you're like running, I guess, if it's like end
0:50:23 to end encrypted or something where you can't really do that and the true state of
0:50:27 the data is what's on the person's device.
0:50:30 I can see how you have to like think about that a little bit more.
0:50:32 I think it kind of reminds me of WhatsApp a little bit because like with
0:50:34 WhatsApp, it feels like you're like shuffling your data across your devices.
0:50:37 You get a new device, you like Move the data from one to another.
0:50:41 So I imagine they deal with things like this, but yeah, personally don't
0:50:44 have a ton of experience with that.
0:50:46 Yeah, I mean WhatsApp is also one of the OG local-first apps that
0:50:51 really like followed this pattern out of necessity that defined
0:50:55 why WhatsApp is so attractive.
0:50:57 But I think the, the trade off that you've landed on, I think makes a lot of sense.
0:51:01 It's very pragmatic and given that you're in this hybrid mode of like some parts of
0:51:06 your app are cloud oriented, some parts of your app are local-first, now you can
0:51:11 also reap the benefits of the best of both worlds that allows you to move quickly.
0:51:16 I think if at some point you want to move further on the local-first side.
0:51:19 Spectrum, then I think maybe you can't quite afford just
0:51:23 blowing all the local data away.
0:51:24 I'm kind of exploring some patterns in that regard where I'm kind of keeping
0:51:29 two versions of the data around locally.
0:51:32 One version that is more of like an event log.
0:51:35 And one that is more of like a typical app database.
0:51:39 And the app database is just a projection on aggregate from the event log.
0:51:44 So I also get the benefits and luxury of, in the case of a schema migration,
0:51:49 I can just blow away the app DB.
0:51:51 But instead of talking to the server, I can just replay it locally.
0:51:55 Sometimes takes a little bit of time, but, uh, you get a lot of different
0:51:58 options here that you can choose depending on your requirements and how much time
0:52:03 you can afford to put some effort into.
0:52:06 Yeah, yeah, that makes sense.
0:52:07 And what's interesting is this feels very different, but it just kind of
0:52:11 echoes the same things you do with like a database in the back end.
0:52:15 It's ultimately the same thing.
0:52:16 It just happens to be that the node of the database is running.
0:52:20 In someone's machine, so you end up with like almost all
0:52:22 the same scenarios and options.
0:52:25 New challenges with local-first
0:52:25 Did you run into any situation where you feel like, okay, this was really
0:52:30 easier in the way how you've built software in the past that's now
0:52:34 like either currently harder with local-first or like just categorically
0:52:39 inherently harder with local-first?
0:52:42 Well, it's really that one scenario I talked about before where
0:52:45 you do want to block the user.
0:52:46 Since the default is inverted, whenever, like you never, you never think like
0:52:51 holding the user up until the backend verifies something has happened.
0:52:56 99 percent of developers would never think about that as complicated.
0:52:58 It's like, obviously, that's like how everything works.
0:53:01 But when you invert the default, that becomes a little bit more challenging
0:53:04 and Yeah, we just have to come up with, like, certain patterns around, like, if
0:53:08 you do an action, and a server rejects the action, the natural s thing that'll happen
0:53:13 is your state locally will revert to the state it was at before you did the action.
0:53:18 But that state has no record of you trying to do the action, so
0:53:21 the UI won't have like any error or like information about this.
0:53:25 So, doing an action where there was an error on the backend and preserving
0:53:28 that error, it just ends up being more steps than it would be otherwise.
0:53:34 But again, like we talked about, like this is a minority of cases, so it doesn't come
0:53:37 up, but it's just a funny thing where.
0:53:39 Something so straightforward in the traditional situation is like
0:53:43 so weirdly complicated in this.
0:53:46 So that's one thing that comes up.
0:53:47 I think the second thing that comes up is Kind of going back to this thing about
0:53:50 like the doing migrations of data locally or the schema changes, there's always
0:53:55 a chance, and it's happened more when I was earlier on in doing this stuff.
0:53:59 So I think it was just me, like, not doing stuff well, or like not having
0:54:03 the right approach to certain things.
0:54:04 But, um, Sometimes you would just end up with, like, data that was bad and
0:54:09 messing up the user's state locally.
0:54:12 And with any other app, hitting refresh means, start over, you're, like, rebooting
0:54:17 your computer, you're, like, back to, back to ground, like, back to zero.
0:54:21 But with local-first, you might hit refresh and the local data is still there.
0:54:24 That's causing the bug, preventing, like, you know, the fix from being applied.
0:54:28 So, just like the, you lose the ease of, like, wiping everything
0:54:32 and there's no, like, built in user.
0:54:34 Habits around like, oh, like, let me try clearing my index
0:54:38 DB and my browser, right?
0:54:39 That's like not a thing that anyone thinks about.
0:54:41 So just like guarding those things so you never end up in a
0:54:43 state where it's unrecoverable.
0:54:46 I think that's, that's for good.
0:54:47 Again, it's usually handled on a lower level, so you're not
0:54:49 dealing with this constantly, but.
0:54:51 It is a technical possibility.
0:54:53 Yeah, I like that, uh, that observation a lot.
0:54:56 This is also something I'm currently thinking a lot about.
0:54:59 How can I make that easier through LiveStore?
0:55:01 Since I also, as working both on LiveStore and Overtone, I do discover
0:55:07 those behaviors, whether it's like still me as a developer driving the
0:55:11 user experience where it didn't pop open the console and like throw away, like
0:55:16 all the, the locally persisted data.
0:55:19 But I can't expect an app user to do the same thing.
0:55:22 So I need to build like some sort of, um, guards or some sort of detection
0:55:26 of like, Hey, it seems like the app is in sort of like a really tough spot.
0:55:31 What should we do about this?
0:55:33 Should we try to just like delete a little bit of stuff
0:55:36 that might cause the blockage?
0:55:39 Or what should we do about that?
0:55:40 And so where, where I'm currently at is I think a mixture of user experience
0:55:45 affordances, as well as technical detections, whether something is
0:55:48 wrong, I think transactions can help with that in regards to the technical
0:55:53 abilities, but then in terms of the user experience, similar to like a
0:55:58 React error boundary that you have to detect whether something has gone wrong.
0:56:02 I want to have a similar pattern that allows you to, you know, Click a button
0:56:07 that wipe everything, but it before it does wipe everything, download
0:56:12 a snapshot of your full database that in case something catastrophic
0:56:16 happens, you can, you still have that.
0:56:18 You can hand that to an app developer and you can also later re import
0:56:22 your app state from there so that you can go back where you've
0:56:26 left off in case you wiped it.
0:56:28 So those are like some, some primitives and some, some patterns I'm exploring
0:56:32 right now, but I'm, I'm excited to see what other figures out.
0:56:36 Yeah, that makes sense.
0:56:37 It's also great that you're like, building an actual thing with the tool.
0:56:43 There's just like, no better way to like, really understand
0:56:46 what problems you need to solve.
0:56:48 With SST, like, our console is built with SST.
0:56:52 So, any change we make comes from problems we discover.
0:56:56 The actual product that we're building.
0:56:57 That's why it's so fun to work on like, developer tools, because you are the user.
0:57:02 So you're never like, how do I get in the mind of a user?
0:57:05 Like, that's, that problem isn't there.
0:57:07 Like, you are the user.
0:57:08 It's very easy to figure out what problems there are, um, and discover that.
0:57:11 You kind of skip that whole, like, discovery process that
0:57:14 usually needs to happen.
0:57:16 So if you have someone who's currently like, by default, building
0:57:20 a new app with something like Next.
0:57:22 js or Ruby on Rails, and they, they hear about your story and now they're like
0:57:27 curious about local-first, but they're not quite sure where to get started.
0:57:31 Do you have some tactical suggestions for them?
0:57:34 And also in terms of mindset, what do they need to.
0:57:39 switch in their brain, uh, that they're successful and can hit the ground
0:57:43 running in a local-first mindset.
0:57:46 Advice for builders
0:57:46 Yeah.
0:57:47 You know, it's, I don't think I've really thought about like, what's
0:57:50 the right onboarding path for people doing this type of thing.
0:57:54 I'm like, I know the tools that I use, like I said, we're, we're, we've
0:57:57 centered around Replicache at this point, but you know, local-first website
0:58:00 obviously has a ton of other options.
0:58:03 And there's a spectrum of like what you care about and like how
0:58:05 easy it is and how incremental you can add it and things like that.
0:58:08 But the mindset I think really is, it really has nothing to do with local-first.
0:58:12 And I think it's a good mindset for everyone.
0:58:14 I feel like there has been this shift away from like caring about UX and
0:58:19 almost, I feel like there's like a weird proudness to like not caring about UX,
0:58:22 which I think is fundamentally wrong.
0:58:24 And what I mean by that is.
0:58:26 There's a whole meme of like, Oh, if you did this, you shipped too late.
0:58:29 Or like people are proud of like shipping bad stuff.
0:58:32 Cause they're signaling that like, I'm just someone that
0:58:35 like tries to get stuff done.
0:58:37 I'm not like wasting time on stupid stuff, which the Linear people had a great write
0:58:43 up about this and it's this whole concept around the idea of an MVP is stupid and
0:58:48 it's been stupid for a while, but for some reason, people haven't realized this.
0:58:52 I definitely will acknowledge maybe back when I was starting out, like
0:58:55 in the startup world, like, I guess it's been like 10 or 11 years, things
0:58:59 were definitely different back then where there wasn't a lot of software.
0:59:02 So anything was better than nothing.
0:59:05 So you could really ship something pretty quick and like get validation and move on.
0:59:09 It's like that whole like mindset kind of made sense back then.
0:59:12 But it hasn't been that way in a long time.
0:59:14 So many people ship like something they built in a week and they're
0:59:17 like, Oh, it didn't work.
0:59:18 Let me move on to the next thing.
0:59:19 To be honest, nothing good can really be shipped that fast.
0:59:23 It's just not possible.
0:59:25 Uh, and you really need to have a strong sense of here's a problem I'm solving.
0:59:30 I have good taste around it.
0:59:31 I'm going to put in a lot of effort and make a really great experience.
0:59:36 And.
0:59:37 Whether or not my idea is going to work, you can't know that
0:59:41 until you've hit that bar.
0:59:43 And as a Linear people wrote up a whole thing about this on like, we're so
0:59:47 obsessed with these like little tiny MVPs.
0:59:50 And that's like the weird default that we're all like kind of
0:59:52 proud to say that we follow that.
0:59:54 Um, and the mindset shift is with local-first, it's getting easier all
0:59:59 the time, but it's going to be a lot harder than a lot of things that you've
1:00:03 done before because you have so much time to focus on these little details.
1:00:08 And you really have to focus on details.
1:00:09 You have to enjoy Letting them and caring about them and making that
1:00:14 feel good because that's what that's where the bar is now, whether people
1:00:17 realize it or not, the fact is Linear, Linear exists now that it exists.
1:00:23 How can you possibly ship anything not at that level?
1:00:26 Right?
1:00:26 How, like, sure, in the short term, I'm sure you can, but the long term,
1:00:29 obviously that becomes a new bar.
1:00:32 So, for me, the mindset shift is like, there is a new bar go use products that
1:00:36 are like this, like, Linear is one, like, superhuman is like a smaller example.
1:00:40 of stuff that's kind of gotten bigger.
1:00:42 That is the bar, and you have to accept that that is a bar.
1:00:45 And if you really accept that, then you'll be motivated to like
1:00:48 go and figure out all this stuff.
1:00:50 Yeah, it's quite different from where I think the mindset is currently.
1:00:54 I think you've very succinctly Summarized my last two and a
1:00:58 half years working on Overtone.
1:01:00 I'm exactly inspired by that high bar.
1:01:03 Sometimes I might even raise it a bit higher just for, for the challenge, but
1:01:08 it's so fun to see like all of those details just compounding and, and I
1:01:13 like much smoother product experience.
1:01:15 And, uh, yeah, I love the the blog posts that you've pointed
1:01:19 out from the, the Linear blog.
1:01:21 And I think the only exception really to where the bar needs to be higher is
1:01:25 like for just categorically new things.
1:01:28 Maybe an exception here is like AI products, uh, like AI products.
1:01:32 There is no, no prior version to that.
1:01:34 So maybe it is really speed that, that matters most, but I think
1:01:38 for every software that replaces something that was there before.
1:01:43 I think it's, you have to really, really care about craft.
1:01:46 Um, Arc is another example as like to really innovate on a browser.
1:01:52 Like the browser is still the same, what it is before, but now it's
1:01:55 like all the compound effect of all of like getting the details right.
1:02:00 And that really, that really excites me.
1:02:02 So thank you so much for that wonderful summary.
1:02:05 Yeah.
1:02:05 And there's so much opportunity to do this.
1:02:07 Like I'm unhappy with so much of the things that I use every day.
1:02:14 Outro
1:02:14 Thank you so much.
1:02:15 This has been really, really fun.
1:02:17 Thank you so much for coming on.
1:02:19 Yeah, appreciate having me.
1:02:20 I, I, it was good.
1:02:21 I actually don't get to get into some of these details.
1:02:24 I don't, I've actually never gotten a lot of these details before.
1:02:26 So yeah, it was great.
1:02:27 Thank you for listening to the localfirst.fm podcast.
1:02:30 If you've enjoyed this episode and haven't done so already, please subscribe and
1:02:34 leave a review wherever you're listening.
1:02:36 Please also tell your friends about it.
1:02:37 If you think they could be interested in local-first, if you have feedback,
1:02:41 questions or ideas for the podcast, please get in touch via hello at
1:02:45 localfirst.fm or use the feedback form on our website, special thanks to Expo and
1:02:50 Crab Nebula for supporting this podcast.