1 00:00:00,000 --> 00:00:02,180 isn't it really complicated to build web apps? 2 00:00:02,325 --> 00:00:06,564 What if it was just way simpler to build an awesome app that was fast, that was 3 00:00:06,564 --> 00:00:10,493 really responsive, that stored all the data people care about, was easier for 4 00:00:10,493 --> 00:00:14,790 you to develop faster, simpler, less ops maintenance stuff The data ownership 5 00:00:14,790 --> 00:00:16,389 stuff just falls out as a consequence. 6 00:00:16,486 --> 00:00:21,316 Could we leverage the power of databases and the power of local-first 7 00:00:21,336 --> 00:00:24,536 architecture to cut through a lot of the complexity of building 8 00:00:24,536 --> 00:00:26,151 modern web apps and make it simpler. 9 00:00:26,611 --> 00:00:28,951 Welcome to the localfirst.fm podcast. 10 00:00:29,091 --> 00:00:32,051 I'm your host, Johannes Schickling, and I'm a web developer, a 11 00:00:32,051 --> 00:00:35,176 startup founder, And love the craft of software engineering. 12 00:00:35,556 --> 00:00:39,396 For the past few years, I've been on a journey to build a modern, high quality 13 00:00:39,396 --> 00:00:41,331 music app using web technologies. 14 00:00:41,551 --> 00:00:45,971 And in doing so, I've been falling down the rabbit hole of local-first software. 15 00:00:46,511 --> 00:00:49,571 This podcast is your invitation to join me on that journey. 16 00:00:50,176 --> 00:00:53,376 In this episode, I'm speaking to Geoffrey Litt, who's currently 17 00:00:53,376 --> 00:00:55,076 a researcher at Ink and Switch. 18 00:00:55,406 --> 00:00:58,821 Geoffrey has worked on many interesting research projects such 19 00:00:58,821 --> 00:01:00,841 as Riffle, Cambria, and Embark. 20 00:01:01,221 --> 00:01:04,921 In our conversation today, we're talking about the ideas and goals 21 00:01:04,981 --> 00:01:09,886 that motivated Riffle, Which include expressing an app as a query, fast 22 00:01:09,886 --> 00:01:14,786 synchronous reactivity, and unifying UI state and app data in a single system. 23 00:01:15,341 --> 00:01:18,861 Before getting started, also a big thank you to Expo and Crab 24 00:01:18,861 --> 00:01:20,561 Nebula for supporting this podcast. 25 00:01:21,213 --> 00:01:23,163 And now my interview with Geoffrey. 26 00:01:23,767 --> 00:01:25,227 Welcome, Geoffrey, to the show. 27 00:01:25,227 --> 00:01:26,450 So excited to have you. 28 00:01:26,450 --> 00:01:26,890 Thanks. 29 00:01:26,890 --> 00:01:27,950 It's great to be here. 30 00:01:28,328 --> 00:01:32,813 I mean, you and I have been working together now for a few years, But let's 31 00:01:32,813 --> 00:01:37,763 rewind time a little bit and maybe start where you and I have first crossed paths. 32 00:01:38,228 --> 00:01:42,728 This was, I think the end of 2020 and you've been just wrapping 33 00:01:42,728 --> 00:01:46,028 up your first project at Ink and Switch, which was about Cambria. 34 00:01:46,673 --> 00:01:50,053 So would you mind, motivating what the project was about? 35 00:01:51,043 --> 00:01:51,363 Yeah. 36 00:01:51,363 --> 00:01:51,843 Absolutely. 37 00:01:51,843 --> 00:01:57,638 So, I'm a researcher that works on a topic called malleable software, where the idea 38 00:01:57,638 --> 00:02:02,358 is, can we let everybody customize their software tools to meet their own personal 39 00:02:02,358 --> 00:02:07,093 needs rather than everybody changing the way they work to match standardized 40 00:02:07,093 --> 00:02:09,193 software tools that other people develop. 41 00:02:09,253 --> 00:02:09,689 Right? 42 00:02:09,726 --> 00:02:14,546 turns out one of the core problems in this space is wrangling data schemas. 43 00:02:15,061 --> 00:02:18,421 So imagine, you know, you're using your favorite to do app, I'm using 44 00:02:18,421 --> 00:02:22,201 my favorite to do app, and we decide we wanna work on a project together. 45 00:02:22,346 --> 00:02:23,146 What are the options? 46 00:02:23,146 --> 00:02:27,226 We either have to pick the same to do app, or if we wanna each keep using 47 00:02:27,226 --> 00:02:30,726 our own favorite to do app, those apps need to have some way of talking to one 48 00:02:30,746 --> 00:02:33,391 another and sharing a data representation. 49 00:02:33,691 --> 00:02:34,191 Right? 50 00:02:34,604 --> 00:02:38,439 it turns out that this is a pretty gnarly problem because those data 51 00:02:38,439 --> 00:02:42,679 representations our 2 apps wanna use might be different in subtle ways. 52 00:02:42,679 --> 00:02:43,339 You know? 53 00:02:43,559 --> 00:02:47,364 Perhaps your app has subtasks and mine doesn't or something like that. 54 00:02:47,424 --> 00:02:51,104 And so the goal of Cambria was to explore this problem and try to figure 55 00:02:51,104 --> 00:02:54,929 out, could we find a way to enable collaboration across diverse tools, 56 00:02:55,132 --> 00:02:59,292 while also not requiring all of our tools to share exactly the same data 57 00:02:59,292 --> 00:03:00,892 schema and all agree on everything. 58 00:03:00,892 --> 00:03:05,267 And It turns out that this is actually sort of a pervasive problem 59 00:03:05,267 --> 00:03:08,627 across local-first software in a bunch of different contexts. 60 00:03:08,627 --> 00:03:10,992 This problem pops up in many shapes and forms. 61 00:03:11,115 --> 00:03:14,955 Even the simple case of, like, having a centralized application written by 62 00:03:14,955 --> 00:03:19,824 one developer in a local-first context schema migrations And upgrades often 63 00:03:19,824 --> 00:03:23,024 become a lot harder than they are in sort of a server based environment. 64 00:03:23,024 --> 00:03:28,289 So, the Cambria project again was about sort of First, just recognizing that 65 00:03:28,289 --> 00:03:32,659 this problem exists everywhere and that it's really holds back progress 66 00:03:32,749 --> 00:03:37,514 in terms of interoperability and schema management and local-first steps. 67 00:03:37,734 --> 00:03:41,464 And then we sort of prototyped a solution to it, which was you can think of it 68 00:03:41,464 --> 00:03:45,779 sort of as a live data translation system where as different tools are 69 00:03:45,779 --> 00:03:49,312 working on shared data, there's a layer underneath the individual tools that 70 00:03:49,312 --> 00:03:53,287 helps translate data formats between all the various tools in such a way that 71 00:03:53,287 --> 00:03:57,417 each app can feel like it's just working with the data representation it wants. 72 00:03:57,587 --> 00:04:01,347 But, actually, under the hood where we have some sort of translation layer 73 00:04:01,347 --> 00:04:05,282 that's, you know, sort of serving as the glue that lets different 74 00:04:05,382 --> 00:04:08,742 versions of the same app collaborate or lets even different apps entirely 75 00:04:08,742 --> 00:04:09,962 collaborate with one another. 76 00:04:10,932 --> 00:04:11,359 Yeah. 77 00:04:11,359 --> 00:04:12,979 I think that's a brilliant motivation. 78 00:04:13,105 --> 00:04:18,920 I remember, like, having read the essay the first time was super well 79 00:04:18,920 --> 00:04:20,780 illustrated and super well motivated. 80 00:04:21,330 --> 00:04:26,035 It sort of almost provoked me into reimplementing a version 81 00:04:26,035 --> 00:04:28,135 of Cambria myself back then. 82 00:04:28,275 --> 00:04:31,715 This is how much it's it kinda spoke to me since I remember that the 83 00:04:31,715 --> 00:04:36,030 first version of Cambria was an sort of like a DSL expressed in YAML. 84 00:04:36,410 --> 00:04:40,948 I am more someone who's working mostly in TypeScript, so I remember reimplementing 85 00:04:41,328 --> 00:04:43,418 a small version in TypeScript. 86 00:04:43,835 --> 00:04:46,768 So, yeah, I love that problem statement. 87 00:04:46,886 --> 00:04:50,886 And so I think it's also interesting how it fits into this broader 88 00:04:50,886 --> 00:04:52,666 umbrella of malleable software. 89 00:04:52,733 --> 00:04:56,151 and turns out, Looking back over the last few years, this is not 90 00:04:56,151 --> 00:05:00,091 the only project you've done in the realm of malleable software. 91 00:05:00,311 --> 00:05:04,776 So which other problem spaces have you run into while pursuing 92 00:05:04,776 --> 00:05:06,716 this goal of malleable software. 93 00:05:07,316 --> 00:05:07,636 Yeah. 94 00:05:07,636 --> 00:05:09,556 I think it's a fascinating space. 95 00:05:09,556 --> 00:05:10,196 You know? 96 00:05:10,196 --> 00:05:13,476 The way I got into it was originally it was actually I was working at a 97 00:05:13,476 --> 00:05:15,911 start up building normal SaaS software. 98 00:05:16,531 --> 00:05:19,351 And you know, we were doing what SaaS companies do, which is that you 99 00:05:19,351 --> 00:05:24,276 have 30 people in a room somewhere, designing interfaces that thousands 100 00:05:24,276 --> 00:05:27,716 and thousands of people, thousands of miles away are supposed to use. 101 00:05:27,746 --> 00:05:28,026 Right? 102 00:05:28,626 --> 00:05:31,251 We were, in our case, designing education software for schools. 103 00:05:31,731 --> 00:05:34,371 I just remember talking to all these teachers and principals and all these 104 00:05:34,371 --> 00:05:39,511 different schools, and they had very specific requests often as customers do. 105 00:05:39,686 --> 00:05:42,566 And, of course in SaaS, typically, the answer is no. 106 00:05:42,566 --> 00:05:46,966 You have to be disciplined and say, I can't change the wording 107 00:05:46,966 --> 00:05:48,561 of that button just for you. 108 00:05:48,721 --> 00:05:50,341 I'm not gonna add a setting for that. 109 00:05:50,601 --> 00:05:53,801 But I started to find this very frustrating and wanted to 110 00:05:53,801 --> 00:05:56,941 explore what would it feel like if software worked differently. 111 00:05:57,436 --> 00:06:00,016 And, you know, I think there's an interesting connection to local-first 112 00:06:00,156 --> 00:06:04,316 because I remember coming across the original Ink & Switch essay 113 00:06:04,316 --> 00:06:07,131 about local-first when I was starting to think about this stuff. 114 00:06:07,131 --> 00:06:12,206 And I think they said briefly in the essay something about how It 115 00:06:12,206 --> 00:06:15,566 seems like an intriguing foundation if you have data locally and 116 00:06:15,566 --> 00:06:17,346 maybe even code locally available. 117 00:06:17,676 --> 00:06:21,116 That gives you a little bit more access and control over your software than 118 00:06:21,116 --> 00:06:23,711 if You have a cloud SaaS architecture. 119 00:06:23,981 --> 00:06:28,061 And that sentence really sort of sparked a bunch of thoughts in my brain that 120 00:06:28,061 --> 00:06:31,550 have led you know, I think a lot of my work, the way I see it is sort of at 121 00:06:31,550 --> 00:06:36,290 the intersection of how do we use the local-first architecture to enable more 122 00:06:36,290 --> 00:06:39,955 malleable software for end users is a theme that I care a lot So Cambria was 123 00:06:39,955 --> 00:06:41,951 definitely one project in that line. 124 00:06:41,951 --> 00:06:46,706 I've worked on a couple other projects in this space. 125 00:06:46,706 --> 00:06:51,606 one project I worked on early in my grad school research career was a little 126 00:06:51,606 --> 00:06:53,146 browser extension called Wildcard. 127 00:06:53,446 --> 00:06:58,071 And the idea was what if you could access the data underneath any web 128 00:06:58,071 --> 00:07:01,275 page in a spreadsheet uh, but it's not only a read only spreadsheet. 129 00:07:01,275 --> 00:07:04,240 You could even write to the spreadsheet and mod it yourself. 130 00:07:04,620 --> 00:07:08,570 So a very accessible way for normal people to make their own browser 131 00:07:08,570 --> 00:07:09,790 extensions without programming. 132 00:07:10,700 --> 00:07:11,320 I love that. 133 00:07:11,620 --> 00:07:16,210 And I think as a fun fact, this might have actually been the very first 134 00:07:16,230 --> 00:07:18,511 point where we've been put in touch. 135 00:07:18,511 --> 00:07:22,671 Because at that time, I was also working on my little own Chrome 136 00:07:22,671 --> 00:07:26,876 extension, which was also kinda in a direction of malleable software. 137 00:07:26,876 --> 00:07:31,661 This was before I was even aware of the term and, like, that broader field. 138 00:07:31,743 --> 00:07:37,675 I was just motivated by my own frustration that I could that the websites didn't 139 00:07:37,675 --> 00:07:39,455 quite work the way how I intended. 140 00:07:39,515 --> 00:07:43,750 So it just feels like we've been on similar paths there, And what 141 00:07:43,750 --> 00:07:48,040 you've been building with Wildcard was quite a step ahead of what I've 142 00:07:48,040 --> 00:07:50,275 been coming up with at that point. 143 00:07:50,595 --> 00:07:51,665 But yeah, 144 00:07:51,880 --> 00:07:54,920 Well, yeah, I, you know, I remember one thing about that that I think 145 00:07:54,920 --> 00:07:57,640 maybe is a preview of the way we've collaborated since then is that mine 146 00:07:57,640 --> 00:08:02,235 was a more speculative prototype of a interface design, but it wasn't 147 00:08:02,455 --> 00:08:04,425 particularly solidly implemented. 148 00:08:04,485 --> 00:08:08,910 And I remember you had this really, fancy developer experience around 149 00:08:08,920 --> 00:08:11,550 customizing your extensions and stuff that I got inspired by. 150 00:08:11,550 --> 00:08:15,329 And so I think There's a fun interplay there we can get into 151 00:08:15,329 --> 00:08:18,619 later about kind of more speculative research versus engineering 152 00:08:18,619 --> 00:08:20,319 more solid versions of the idea. 153 00:08:21,094 --> 00:08:21,594 Yeah. 154 00:08:21,889 --> 00:08:24,139 So you've been working on on Wildcard. 155 00:08:24,320 --> 00:08:29,660 Which are the results that come out of your your overall research in that field? 156 00:08:30,340 --> 00:08:30,660 Yeah. 157 00:08:30,660 --> 00:08:34,195 So, you know, throughout the years, I've had the chance to work on 158 00:08:34,675 --> 00:08:37,335 A bunch of projects with mostly with really awesome collaborators. 159 00:08:38,225 --> 00:08:42,200 one of the more recent projects which I we actually worked on together, was 160 00:08:42,200 --> 00:08:45,580 the the last project I worked on in grad school, which is called Riffle. 161 00:08:46,120 --> 00:08:50,905 And that was a project that you and I worked on together with, Nicholas Schiefer 162 00:08:51,325 --> 00:08:54,135 and Daniel Jackson, my PhD advisor at MIT. 163 00:08:54,755 --> 00:08:59,180 And sort of the, I guess, the origin story of Riffle, is that Nicholas and 164 00:08:59,180 --> 00:09:02,273 I were having a bunch of conversations that revolved around sort of this 165 00:09:02,273 --> 00:09:05,013 idea of having a personal data store. 166 00:09:05,233 --> 00:09:10,248 So, one way I think about cloud versus local-first is that in 167 00:09:10,248 --> 00:09:12,669 local-first software, one of the ideals is that you own your data. 168 00:09:13,066 --> 00:09:16,976 these valuable thoughts that I'm having and artifacts that I'm producing in the 169 00:09:16,976 --> 00:09:21,231 digital world, they should feel like mine, just like a notebook I can carry around 170 00:09:21,231 --> 00:09:23,151 and, you know, have with me forever. 171 00:09:23,151 --> 00:09:23,651 Right? 172 00:09:23,991 --> 00:09:26,391 And There's this question of great. 173 00:09:26,391 --> 00:09:30,551 If you own your data sure, you get longevity and control, but 174 00:09:30,551 --> 00:09:35,276 what about this ability to take arbitrary tools that I wanna use and 175 00:09:35,276 --> 00:09:37,136 connect them to that personal data. 176 00:09:37,196 --> 00:09:40,926 This is something that's often really hard in SaaS because the data's locked away. 177 00:09:40,926 --> 00:09:43,601 And maybe there's the APIs you want and maybe there's not. 178 00:09:43,601 --> 00:09:46,001 And maybe there's the partnership you want between the 2 tools 179 00:09:46,001 --> 00:09:47,221 you use, but maybe not. 180 00:09:47,361 --> 00:09:50,301 And we were talking about, you know, how would it feel if you had a local-first 181 00:09:50,321 --> 00:09:54,146 data store with all your stuff in it And you could connect whatever app 182 00:09:54,146 --> 00:09:57,346 or tool you wanted to that existing data store that has all your stuff. 183 00:09:57,346 --> 00:09:57,846 Right? 184 00:09:58,456 --> 00:10:00,546 Um, what shape would that data store take? 185 00:10:00,766 --> 00:10:01,391 How would it work? 186 00:10:01,391 --> 00:10:03,171 How would you develop against it? 187 00:10:03,391 --> 00:10:07,441 And one hypothesis we wanted to explore, particularly because of Nicholas's 188 00:10:07,581 --> 00:10:11,881 background, which is in databases, we wanted to sort of ask this question of 189 00:10:11,881 --> 00:10:15,341 what if you had a really powerful database that was designed for this purpose? 190 00:10:15,921 --> 00:10:18,556 Maybe it could be based on relational databases. 191 00:10:19,456 --> 00:10:24,336 And maybe the experience of building an app in that foundation could end up 192 00:10:24,336 --> 00:10:27,921 feeling really different from traditional software development in a bunch of ways. 193 00:10:27,921 --> 00:10:30,661 So that's kind of how we got into the Riffle work. 194 00:10:31,271 --> 00:10:32,391 That that's incredible. 195 00:10:32,391 --> 00:10:37,226 And if I remember correctly, This was not the first time that Nicholas 196 00:10:37,226 --> 00:10:39,146 was also working on on this field. 197 00:10:39,146 --> 00:10:43,491 He didn't just work on on databases, but I think he was at at Apple 198 00:10:43,551 --> 00:10:48,111 previously and was implementing similar systems, I think, related to 199 00:10:48,111 --> 00:10:50,771 to iCloud and how syncing works there. 200 00:10:51,256 --> 00:10:52,136 So yeah. 201 00:10:52,136 --> 00:10:54,636 I mean, those are some pretty big ideals, 202 00:10:54,689 --> 00:10:58,129 That is not a very common thing in the apps that that I'm using. 203 00:10:58,129 --> 00:11:01,639 It's, if, God forbid, something like Notion would shut down. 204 00:11:01,639 --> 00:11:05,159 Like, what what would even happen to to to my data? 205 00:11:05,159 --> 00:11:10,344 So I would love to see that flip of, like, Everything that I'm creatively 206 00:11:10,564 --> 00:11:15,094 producing is by default mine and turn around the relationship. 207 00:11:15,714 --> 00:11:20,452 But Uh, it's not even that you wanted to, from a idealistic perspective, 208 00:11:20,592 --> 00:11:24,352 push for that, but I think you took a step back and say, okay. 209 00:11:24,352 --> 00:11:27,037 What is even the technical foundation for that? 210 00:11:27,097 --> 00:11:29,214 What would a prototype of that look like? 211 00:11:29,214 --> 00:11:31,377 How did the project get off the ground? 212 00:11:31,827 --> 00:11:32,067 Yeah. 213 00:11:32,067 --> 00:11:34,787 So one way that I think about this is exactly the way you put 214 00:11:34,787 --> 00:11:37,687 it about the difference between ideology and technical foundations. 215 00:11:37,904 --> 00:11:41,000 I think that data ownership, one of the reasons we don't have it is because 216 00:11:41,000 --> 00:11:43,020 it's hard to build apps that way. 217 00:11:43,620 --> 00:11:47,750 It's not I think there are often companies that don't really have a 218 00:11:47,750 --> 00:11:50,255 strong desire to build a SaaS data moat. 219 00:11:50,415 --> 00:11:53,505 It just is kind of the default that is promoted by the way 220 00:11:53,505 --> 00:11:54,885 we naturally build stuff. 221 00:11:55,025 --> 00:11:57,745 And because it's so hard to build apps with data ownership, 222 00:11:57,745 --> 00:11:59,390 we don't get that many of them. 223 00:11:59,710 --> 00:12:04,670 And one of the I think most interesting potentials of local-first as an area that 224 00:12:04,670 --> 00:12:08,425 I don't think has been fully realized yet is what if we could make it easier to 225 00:12:08,425 --> 00:12:10,186 build apps this way rather than harder? 226 00:12:10,186 --> 00:12:10,665 Right? 227 00:12:10,665 --> 00:12:14,290 I think a lot of people in this space see that potential for this Radical 228 00:12:14,290 --> 00:12:16,931 simplification of how we build stuff. 229 00:12:16,931 --> 00:12:21,490 I think Peter, who was on the show see, you know, has sort of, Inspired 230 00:12:21,490 --> 00:12:22,610 a lot of my thinking on that. 231 00:12:22,610 --> 00:12:25,730 I think Martin Kleppmann, who was one of the coauthors of the local-first piece, 232 00:12:25,730 --> 00:12:30,581 has given talks about how you sort of have this, uh, many layered cloud architecture. 233 00:12:30,581 --> 00:12:33,581 And in theory, it could be so much simpler if you didn't have 234 00:12:33,581 --> 00:12:34,920 to deal with all that stuff. 235 00:12:35,520 --> 00:12:38,740 But, again, in practice, I think we're still getting there as a community, 236 00:12:39,041 --> 00:12:42,661 and the reality is we're still maybe in the zone where it's harder today. 237 00:12:42,960 --> 00:12:46,861 And so, You know, one of the ways that I thought about the Riffle project and, 238 00:12:46,861 --> 00:12:49,791 you know, Nicholas and I and Daniel thought about it was what if the pitch 239 00:12:49,791 --> 00:12:53,922 to an app developer for something like Riffle didn't start from ideology. 240 00:12:53,982 --> 00:12:58,322 It didn't start from you care about giving your users their data and providing 241 00:12:58,322 --> 00:12:59,969 interoperability, blah blah blah. 242 00:12:59,969 --> 00:13:03,349 The reality is for many people, these are not the most pressing concerns. 243 00:13:03,569 --> 00:13:05,669 What if we started instead from, hey. 244 00:13:05,969 --> 00:13:08,149 Isn't it really complicated to build web apps? 245 00:13:08,294 --> 00:13:12,534 What if it was just way simpler to build an awesome app that was fast, that was 246 00:13:12,534 --> 00:13:16,649 really responsive, that stored all the data people care about, was easier for 247 00:13:16,649 --> 00:13:20,946 you to develop faster, simpler, less ops maintenance stuff The data ownership 248 00:13:20,946 --> 00:13:22,546 stuff just falls out as a consequence. 249 00:13:22,546 --> 00:13:22,946 Right? 250 00:13:22,946 --> 00:13:28,211 So a lot of our Riffle work was focused on, could we leverage the 251 00:13:28,211 --> 00:13:34,051 power of databases and the power of the local-first architecture to cut through 252 00:13:34,051 --> 00:13:37,105 a lot of the complexity of building modern web apps and make it simpler. 253 00:13:37,566 --> 00:13:41,546 And in service of that mission, a few of our starting principles were 254 00:13:41,715 --> 00:13:45,900 can you think of an application as one giant database Query. 255 00:13:45,900 --> 00:13:49,740 What I mean by that is instead of writing a ton of normal code that produces 256 00:13:49,740 --> 00:13:54,686 your UI, could you somehow push a lot of the work into a optimized database 257 00:13:54,686 --> 00:13:59,736 that does a lot of heavy lifting and let it produce UI states for you. 258 00:14:00,336 --> 00:14:04,356 Another thing that couples really well with that is fast synchronous reactivity. 259 00:14:04,495 --> 00:14:07,875 So we have this idea that the data's already there on your device. 260 00:14:08,081 --> 00:14:12,421 Throw away all the async crap that comes with web apps typically. 261 00:14:12,721 --> 00:14:16,241 You know, React suspend network requests and work with the data 262 00:14:16,241 --> 00:14:20,986 that's already there and simplify just talking to it and querying it. 263 00:14:20,986 --> 00:14:25,196 And the last thing, our third principle was Can we take all these different 264 00:14:25,196 --> 00:14:29,036 kinds of state that typically end up in different systems and throw them in one? 265 00:14:29,196 --> 00:14:33,646 So your React UI state and your persistent local device local state 266 00:14:33,646 --> 00:14:35,566 and your synchronized multi user state. 267 00:14:35,566 --> 00:14:37,506 Can you just store them in one system? 268 00:14:37,806 --> 00:14:40,726 And then You know, we like to think of it as maybe there's some setting 269 00:14:40,726 --> 00:14:43,606 checkboxes on each bit of state that tell you should you share it or 270 00:14:43,606 --> 00:14:47,786 whatever, but just have one system that's capable of subsuming all those roles. 271 00:14:48,051 --> 00:14:51,491 And our hypothesis was that if you pulled all this off, it could feel really 272 00:14:51,491 --> 00:14:57,076 awesome to build apps, and you would get Both better apps for end users because 273 00:14:57,076 --> 00:14:59,896 they're fast and they work offline and they have all the local-first goodness. 274 00:15:00,036 --> 00:15:04,221 But also you could get a better developer experience because you've removed a lot 275 00:15:04,221 --> 00:15:06,161 of the layers of of traditional web apps. 276 00:15:06,761 --> 00:15:08,281 So this was a lot. 277 00:15:08,281 --> 00:15:12,886 And spoiler alert, that hypothesis that you've motivated, at least 278 00:15:12,886 --> 00:15:15,716 in my very case paid off big time. 279 00:15:15,716 --> 00:15:19,415 So the developer experience for me as a developer is better. 280 00:15:19,880 --> 00:15:23,911 I hope that the end user experience will be better partially also 281 00:15:23,911 --> 00:15:26,891 because I care a lot about performance and making things nice. 282 00:15:27,190 --> 00:15:33,355 But to crack the chicken egg problem of, like, how do you even build better 283 00:15:33,355 --> 00:15:35,215 apps with this in the first place? 284 00:15:35,580 --> 00:15:40,060 What really was the the motivation and the the catalyst for me was 285 00:15:40,060 --> 00:15:42,120 not all the ideals of local-first. 286 00:15:42,140 --> 00:15:42,460 Sure. 287 00:15:42,460 --> 00:15:46,045 I would love them, but that would not really make the difference for 288 00:15:46,045 --> 00:15:50,385 me, like, start to work on an app and build in one architecture or another. 289 00:15:50,525 --> 00:15:54,950 But the more Things I didn't have to do in the first place, the better. 290 00:15:54,950 --> 00:15:58,490 The more I could really focus on working on the app. 291 00:15:58,791 --> 00:16:04,135 And Just to simplify the entire stack your motivation to say, like, hey. 292 00:16:04,135 --> 00:16:06,135 Actually, why do you even need a server? 293 00:16:06,135 --> 00:16:08,075 Why do you need a back end for the thing? 294 00:16:08,410 --> 00:16:11,070 Ultimately, the app is is working on your client. 295 00:16:11,130 --> 00:16:12,990 How about that being the starting point? 296 00:16:13,050 --> 00:16:18,475 That really spoke to me, and this drew me in as an app developer and 297 00:16:18,475 --> 00:16:20,495 where I believe in in that mission. 298 00:16:21,435 --> 00:16:27,990 So, yeah, I I couldn't agree more, and I would love to dig more into the various 299 00:16:28,151 --> 00:16:31,690 principles that you've mentioned since I think there's quite a bit of, like, 300 00:16:31,990 --> 00:16:34,171 interesting thinking behind each of those. 301 00:16:34,420 --> 00:16:39,387 If I recap it correctly, I think it was simplifying the inner workings of 302 00:16:39,387 --> 00:16:44,932 an app into Uh, basically, database queries, aka, like, complex SQL queries 303 00:16:44,932 --> 00:16:49,800 or however else you wanna express it than the the synchronous uh, uh, graph 304 00:16:49,860 --> 00:16:55,096 of typically how React works, etcetera, coupling that directly together. 305 00:16:55,681 --> 00:16:59,461 And the third part oh, you gotta remind me about the third part again. 306 00:16:59,521 --> 00:17:03,621 But let's let's go through them, like, one by one again and with a bit more detail. 307 00:17:04,221 --> 00:17:04,701 Absolutely. 308 00:17:04,701 --> 00:17:08,461 So, you know, the first principle I talked about is thinking of an 309 00:17:08,461 --> 00:17:10,301 application as a database query. 310 00:17:10,301 --> 00:17:10,796 Right? 311 00:17:10,796 --> 00:17:13,456 And, actually, to throw a little more detail in there, 312 00:17:13,516 --> 00:17:15,036 it's not one database query. 313 00:17:15,036 --> 00:17:17,376 It's actually a graph of database queries with dependencies. 314 00:17:17,866 --> 00:17:21,388 Now that starts to sound kind of fancy, but I think we all understand 315 00:17:21,388 --> 00:17:23,088 this model from using spreadsheets. 316 00:17:23,688 --> 00:17:27,813 The the metaphor, I think, to think about is can You make coding 317 00:17:27,813 --> 00:17:32,313 a rich, complex application as simple as using a spreadsheet. 318 00:17:32,693 --> 00:17:35,623 Spreadsheets dependency tracking of formulas and automatic 319 00:17:36,008 --> 00:17:38,408 Dependency propagation is the bread and butter of spreadsheets. 320 00:17:38,408 --> 00:17:41,068 It's one of the key features that makes them useful. 321 00:17:41,208 --> 00:17:41,528 Right? 322 00:17:41,528 --> 00:17:44,813 When you're using a spreadsheet and you update a cell, The contract 323 00:17:44,813 --> 00:17:48,653 that Excel gives you is typically instantly or at least very quickly, 324 00:17:48,653 --> 00:17:51,453 unless you're in a huge spreadsheet, everything will be up to date. 325 00:17:51,453 --> 00:17:52,913 You're never worried about staleness. 326 00:17:53,198 --> 00:17:54,818 You're never thinking about caching. 327 00:17:55,278 --> 00:17:59,198 That complexity of dependency propagation is pushed down into the system. 328 00:17:59,198 --> 00:17:59,698 Right? 329 00:18:00,293 --> 00:18:03,813 And I would note, I think this is a lesson that we've definitely 330 00:18:03,813 --> 00:18:05,113 learned in UI development. 331 00:18:05,213 --> 00:18:10,138 You could definitely say that reactive UI frameworks like, React JS give 332 00:18:10,138 --> 00:18:11,838 you something like this guarantee. 333 00:18:12,138 --> 00:18:12,378 Right? 334 00:18:12,378 --> 00:18:18,273 They you declare the UI you want and state and DOM are synced automatically. 335 00:18:18,733 --> 00:18:22,753 The problem that I see is that often in our web stacks, this reactivity 336 00:18:22,893 --> 00:18:25,313 is partial to one part of the stack. 337 00:18:25,533 --> 00:18:29,918 So in in a common web application, your React UI, what it's 338 00:18:29,918 --> 00:18:33,438 faithfully representing is not all the state in your system. 339 00:18:33,438 --> 00:18:38,963 It's some view you currently have in this tab of some larger state that is, 340 00:18:38,963 --> 00:18:40,903 you know, maybe primarily on a server. 341 00:18:41,258 --> 00:18:44,538 And that introduces a lot of complexity because all of a sudden, you have 342 00:18:44,538 --> 00:18:48,028 your nice declarative spreadsheety React thing, but then you have At 343 00:18:48,028 --> 00:18:51,148 some point in your stack, you're gonna start hitting data fetching. 344 00:18:51,148 --> 00:18:54,558 You're gonna start hitting sending rights back up to the server. 345 00:18:55,098 --> 00:19:00,363 And, that's just an enormous source of mental model overhead, I think. 346 00:19:00,743 --> 00:19:03,943 On the flip side there have been some interesting research projects which come 347 00:19:03,943 --> 00:19:06,868 out from the other side, And people, for example, have literally tried to 348 00:19:06,868 --> 00:19:09,128 make UIs in things like Google Sheets. 349 00:19:09,298 --> 00:19:12,998 There's a really neat project by Ted Benson and collaborators called Quiltstep. 350 00:19:13,263 --> 00:19:18,063 Literally, they use Google Sheets to power your entire back end and all your your, 351 00:19:18,063 --> 00:19:20,083 you know, UI templating and essentially. 352 00:19:20,683 --> 00:19:23,803 And the problem there is normal spreadsheets aren't really powerful 353 00:19:23,803 --> 00:19:27,488 enough to do that, and they're not really architected the right way. 354 00:19:27,698 --> 00:19:30,468 one way to think about what we're trying to do in Riffle is can you take 355 00:19:30,688 --> 00:19:35,773 the beautifully simple model of just declarative dependency propagation, and 356 00:19:35,773 --> 00:19:38,433 apply that to your entire data stack. 357 00:19:38,653 --> 00:19:42,513 So your mental model as developer should be, I just have all the data locally. 358 00:19:42,928 --> 00:19:47,248 I'm just writing a spreadsheet that turns it into a UI, and the 359 00:19:47,248 --> 00:19:48,848 system will take care of the rest. 360 00:19:48,898 --> 00:19:50,198 Full stack reactivity. 361 00:19:50,418 --> 00:19:51,828 That's sort of principle number one. 362 00:19:52,563 --> 00:19:54,243 That makes that makes total sense. 363 00:19:54,243 --> 00:19:58,078 And I think you've Touched on also, like, the the third principle, which I remember 364 00:19:58,078 --> 00:20:03,843 now is, like, the the unifying the UI states and sort of the the other app data. 365 00:20:03,843 --> 00:20:07,763 And if you really think about it, where do you even draw the line between something 366 00:20:07,763 --> 00:20:10,263 being UI state, something being app data? 367 00:20:10,438 --> 00:20:12,838 There is sort of like a arbitrary line. 368 00:20:12,838 --> 00:20:17,878 Maybe I think de facto in most today's web apps is the app data is, like, 369 00:20:17,878 --> 00:20:22,583 what you fetch over something like React Query as your as your website 370 00:20:22,583 --> 00:20:25,003 boots up or you have it pre hydrated. 371 00:20:25,383 --> 00:20:29,558 And the app state It's more of like the in memory stuff that if you 372 00:20:29,558 --> 00:20:31,818 reload the pages, poof, it's gone. 373 00:20:32,278 --> 00:20:36,733 But, ideally, most of the things should really be treated in a very similar 374 00:20:36,733 --> 00:20:41,233 way when I'm thinking of a native Mac app, for example, like Finder. 375 00:20:41,533 --> 00:20:46,248 If I close a window and I come back, The same items are still selected. 376 00:20:46,388 --> 00:20:51,108 I'm still, like, roughly in the the same position with the the folders that 377 00:20:51,108 --> 00:20:52,968 I've selected and and the hierarchy. 378 00:20:53,623 --> 00:20:58,583 And most web apps, I would actually suffer from that they they have, like 379 00:20:58,663 --> 00:21:02,938 basically, they're suffering from dementia when you and insert something 380 00:21:02,998 --> 00:21:08,438 in a form, and maybe you really need to look up every value and maybe the form 381 00:21:08,438 --> 00:21:10,858 expires, you reload, everything is gone. 382 00:21:10,943 --> 00:21:14,283 That's I think everyone has, like, those terrible user experiences. 383 00:21:14,983 --> 00:21:19,748 And so treating everything as the same data, I think is is a kind 384 00:21:19,748 --> 00:21:23,678 of a bold, but in my experience, like, the the right step. 385 00:21:23,978 --> 00:21:28,673 And then if you can, Therefore, as a conclusion, kind of, like, have all 386 00:21:28,673 --> 00:21:30,273 the data that you need to work with. 387 00:21:30,273 --> 00:21:31,253 Have that locally. 388 00:21:31,313 --> 00:21:35,558 It simplifies everything to such a degree that's really liberating. 389 00:21:36,258 --> 00:21:40,688 So that that's sort of the the third the principle, and I think that's that's a 390 00:21:40,688 --> 00:21:45,723 really bold one that is, I think the most provocative compared to the traditional 391 00:21:45,723 --> 00:21:47,423 way of building web apps today. 392 00:21:48,098 --> 00:21:48,498 Yeah. 393 00:21:48,498 --> 00:21:48,978 Exactly. 394 00:21:48,978 --> 00:21:52,948 You know, just like you said I think it can be a disrespectful user experience 395 00:21:52,948 --> 00:21:55,368 to lose people's valuable input. 396 00:21:55,698 --> 00:21:59,373 Even something like Scroll position or, like you said, intermediate 397 00:21:59,433 --> 00:22:03,033 form state can be thing something that I put a lot of work into and 398 00:22:03,033 --> 00:22:04,553 I don't wanna necessarily lose. 399 00:22:04,553 --> 00:22:05,053 Right? 400 00:22:05,653 --> 00:22:10,293 Now I think the deeper reason we end up with software like this 401 00:22:10,293 --> 00:22:11,833 isn't that people don't care. 402 00:22:11,833 --> 00:22:14,633 It's really that we've made it hard to do. 403 00:22:14,633 --> 00:22:18,473 So, again, it's this technical defaults ruling, the user experience 404 00:22:18,473 --> 00:22:22,208 situation that we talked about where, You know, imagine you're a product 405 00:22:22,208 --> 00:22:26,228 manager and you get a request to please persist to this user input or 406 00:22:26,228 --> 00:22:28,168 share this user input across users. 407 00:22:28,853 --> 00:22:30,533 And the engineer says, oh, man. 408 00:22:30,533 --> 00:22:34,633 That was previously React components data, and now I need to, like, rearchitect 409 00:22:34,853 --> 00:22:38,548 where that data is stored and plummet through a bunch of places and Add a 410 00:22:38,548 --> 00:22:40,388 database column for it, blah blah blah. 411 00:22:40,388 --> 00:22:41,448 It's all this work. 412 00:22:42,068 --> 00:22:44,713 And the goal of having a unified system for your state. 413 00:22:44,713 --> 00:22:46,893 It's not that all states should be treated the same. 414 00:22:47,273 --> 00:22:51,833 Definitely, some state, you know, should be user local, device local, and so on. 415 00:22:51,833 --> 00:22:52,828 There, Yeah. 416 00:22:52,828 --> 00:22:56,398 Some state you want to reset on new sessions by default. 417 00:22:56,888 --> 00:22:58,508 So you can think of that as ephemeral. 418 00:22:58,568 --> 00:23:02,273 But If you store it all in one system and manage it all in one system, 419 00:23:02,573 --> 00:23:06,828 the goal is that it's becomes much easier to move between, these states. 420 00:23:06,828 --> 00:23:07,148 Right? 421 00:23:07,148 --> 00:23:10,508 one example I love is that someone who's working on a collaborative app 422 00:23:10,508 --> 00:23:17,203 told me the state of whether a context menu is open in a spatial canvas app. 423 00:23:17,503 --> 00:23:21,103 They actually realized they needed it to be shared because when I open a 424 00:23:21,103 --> 00:23:22,863 context menu, my cursor is moving around. 425 00:23:22,863 --> 00:23:25,868 If you can't see the context you I'm using, you don't 426 00:23:25,868 --> 00:23:27,068 really know what I'm doing. 427 00:23:27,068 --> 00:23:30,378 And so, I think that's a perfect example of blurring these boundaries 428 00:23:30,378 --> 00:23:35,263 where something that Seems like clearly quote, unquote, local component state 429 00:23:35,483 --> 00:23:40,358 in a traditional framing might actually need to be collaboratively synced 430 00:23:40,358 --> 00:23:42,298 or, you know, maybe even persisted. 431 00:23:42,758 --> 00:23:47,053 So that's what I see as the goal of having this unified state management system. 432 00:23:47,053 --> 00:23:50,143 And in the Riffle work that's basically the the maximalist 433 00:23:50,283 --> 00:23:52,563 view we took is no react state. 434 00:23:52,623 --> 00:23:53,123 Right? 435 00:23:53,758 --> 00:23:58,638 Every single bit of state in the system flows through this one database, and your 436 00:23:58,638 --> 00:24:00,898 UI is just derived from that one place. 437 00:24:01,518 --> 00:24:05,178 And You can always reason about essentially, the pixels on the screen 438 00:24:05,178 --> 00:24:06,478 are a function of the database. 439 00:24:07,018 --> 00:24:07,658 That's it. 440 00:24:07,658 --> 00:24:08,298 Nothing else. 441 00:24:08,298 --> 00:24:13,163 And we found a lot of neat qualities that that design led to along with 442 00:24:13,163 --> 00:24:14,543 a bunch of interesting challenges. 443 00:24:15,273 --> 00:24:20,283 And and I have to say, I was I was not on board with that when we got started. 444 00:24:20,663 --> 00:24:26,598 I was so attached to like, everything is in React, and you have, like, things 445 00:24:26,598 --> 00:24:28,698 inside of React components, etcetera. 446 00:24:28,758 --> 00:24:33,213 And I remember Nicholas, he was, like, on the on the opposite side there. 447 00:24:33,213 --> 00:24:34,093 And so, like, no. 448 00:24:34,093 --> 00:24:34,253 No. 449 00:24:34,253 --> 00:24:34,413 No. 450 00:24:34,413 --> 00:24:37,533 Like, React should do as little as possible and, like, have your 451 00:24:37,533 --> 00:24:42,178 state outside, and that didn't click quite back then for me. 452 00:24:42,478 --> 00:24:46,398 But step by step, I came around to it, and I'm now also, like, on 453 00:24:46,398 --> 00:24:50,833 a maximalist side of, like, most state should live outside of React. 454 00:24:50,833 --> 00:24:54,113 And for example, for Overtone, there's a very simple case where 455 00:24:54,113 --> 00:24:58,178 you for example, for the app for the playback of your player. 456 00:24:58,348 --> 00:25:00,982 Like, you want your playback to happen to happen. 457 00:25:01,142 --> 00:25:02,441 You wanna hear something. 458 00:25:02,591 --> 00:25:07,171 Maybe you captured the the time code of the the current playback progress. 459 00:25:07,711 --> 00:25:11,966 And even if the app is not open, You wanna still hear things. 460 00:25:12,346 --> 00:25:16,136 If you reload the app you might just still want to recover at the 461 00:25:16,136 --> 00:25:17,756 the correct playback position. 462 00:25:18,091 --> 00:25:20,671 So all of that state is kinda headless. 463 00:25:20,891 --> 00:25:25,401 So the state still lives on and, therefore wouldn't quite make sense to 464 00:25:25,401 --> 00:25:27,756 have that be part of React, you say. 465 00:25:27,756 --> 00:25:27,996 Sure. 466 00:25:27,996 --> 00:25:32,156 You could say you have, like, a headless React component, but that's already 467 00:25:32,156 --> 00:25:34,096 feels a bit backwards at that point. 468 00:25:34,396 --> 00:25:40,821 So Once I've started embracing that, it was hugely liberating, and now I can 469 00:25:40,821 --> 00:25:46,966 start to reason about my state outside of the context of React components in 470 00:25:46,966 --> 00:25:49,466 that outside of reactive view state. 471 00:25:49,766 --> 00:25:53,561 So That took me a bit to get around to it, but I'm fully on board 472 00:25:53,561 --> 00:25:55,261 with that principle now as well. 473 00:25:55,580 --> 00:25:57,820 you know, I'll I'll mention, I don't think we're the we're not 474 00:25:57,820 --> 00:25:58,975 the only ones who've of this right. 475 00:25:58,975 --> 00:26:02,465 I think um, the idea of having a reactive state graph separate from 476 00:26:02,465 --> 00:26:06,325 your UI tree is something that other web dev libraries have explored. 477 00:26:07,260 --> 00:26:11,610 MobX, Recoil, arguably, even something like Redux, I think shows some of the 478 00:26:11,610 --> 00:26:16,705 power of having this sort of centralized, outside of your UI tree state management. 479 00:26:16,875 --> 00:26:21,600 So, there's definitely, I think some broad recognition that this 480 00:26:21,600 --> 00:26:25,120 can be a powerful pattern for for some of the reasons you mentioned. 481 00:26:25,170 --> 00:26:27,730 You know, but I'll also mention, like, there are some challenges. 482 00:26:27,730 --> 00:26:27,890 Right? 483 00:26:27,890 --> 00:26:29,775 And, I mean, You've encountered some of these. 484 00:26:29,775 --> 00:26:30,975 I'd be curious to hear your take. 485 00:26:30,975 --> 00:26:34,475 Some of them that I think immediately come to mind for people are, one, 486 00:26:35,195 --> 00:26:37,265 Performance is always an easy one. 487 00:26:37,425 --> 00:26:42,195 Like, typically, we expect button hovers and, you know, selection 488 00:26:42,255 --> 00:26:45,580 changes to happen at 60 120 Hertz. 489 00:26:45,640 --> 00:26:50,250 And we don't expect things like loading thousands of rows of 490 00:26:50,525 --> 00:26:54,865 data from our core data store to necessarily happen at the same speed. 491 00:26:54,915 --> 00:26:59,960 And so that mismatch can be an an an interesting thing to Manage. 492 00:27:00,060 --> 00:27:03,820 Our motto Nicholas's motto to some extent is just make everything fast. 493 00:27:03,820 --> 00:27:06,965 If everything goes at 120 FPS, then don't have a problem. 494 00:27:06,965 --> 00:27:07,465 Right? 495 00:27:07,605 --> 00:27:10,665 Easier said than done, but I think a fun goal to shoot for. 496 00:27:11,163 --> 00:27:13,963 So far, most mostly what we've been talking about is 497 00:27:13,963 --> 00:27:16,233 conceptually a simplification. 498 00:27:16,353 --> 00:27:19,873 Getting on board with that different way of thinking about 499 00:27:19,873 --> 00:27:21,873 your your app on a conceptual basis. 500 00:27:21,873 --> 00:27:26,338 And I think for me, it took a little bit of time to ease into that, 501 00:27:26,338 --> 00:27:29,558 and then, be confronted with the new challenges that are raising. 502 00:27:29,558 --> 00:27:32,593 We we'll we'll go into the challenges in a second since 503 00:27:32,673 --> 00:27:34,373 We've encountered quite a few. 504 00:27:34,703 --> 00:27:38,783 But I think we didn't quite touch too much on the the second principle you've 505 00:27:38,783 --> 00:27:43,398 motivated before, which is, uh, the synchronous reactivity, and, like, 506 00:27:43,398 --> 00:27:45,238 that should be as fast as possible. 507 00:27:45,238 --> 00:27:48,538 We'll we'll go into the performance challenges there in a bit. 508 00:27:48,598 --> 00:27:53,993 But when you've said synchronous reactivity as opposed to 509 00:27:54,453 --> 00:27:58,118 asynchronous reactivity, what what are the why is this a principle. 510 00:27:58,118 --> 00:27:59,318 Like, what is so important? 511 00:27:59,318 --> 00:28:02,518 Can can you motivate the the problem and the status quo and 512 00:28:02,518 --> 00:28:04,538 how Riffle is challenging that? 513 00:28:04,838 --> 00:28:05,158 . Yeah. 514 00:28:05,158 --> 00:28:05,658 Absolutely. 515 00:28:05,878 --> 00:28:07,898 This is a really important principle to me. 516 00:28:08,038 --> 00:28:11,533 I think when we Build web apps that have a server. 517 00:28:11,533 --> 00:28:14,913 We assume a lot of asynchrony at many points. 518 00:28:15,053 --> 00:28:19,158 So, obviously, going on the network to a server is a point of asynchrony. 519 00:28:19,728 --> 00:28:23,318 Even often loading data from you know, like a local disk. 520 00:28:23,318 --> 00:28:23,558 Right? 521 00:28:23,558 --> 00:28:25,338 We think of as an asynchronous operation. 522 00:28:25,958 --> 00:28:30,813 And because of that, UI development typically has a lot of reasoning 523 00:28:30,813 --> 00:28:33,873 about asynchrony, which is a really hard thing to do as a programmer. 524 00:28:34,523 --> 00:28:38,068 For example, you might have a UI where There are loading states. 525 00:28:38,068 --> 00:28:42,368 And everywhere throughout your app, you need to think about, am I still 526 00:28:42,368 --> 00:28:43,903 loading, or do I have the data? 527 00:28:43,983 --> 00:28:47,183 And maybe you have a UI that's composed of different sections, and some of them 528 00:28:47,183 --> 00:28:49,123 might be loaded already and others aren't. 529 00:28:49,373 --> 00:28:51,613 You might have intermediate states to reason about. 530 00:28:51,613 --> 00:28:55,638 Like, After I select something in a sidebar, there's some time 531 00:28:55,638 --> 00:28:59,318 where the main other pane of the app hasn't reacted to that yet. 532 00:28:59,318 --> 00:29:02,713 So It might still be showing the old thing that was there before I selected 533 00:29:02,713 --> 00:29:05,933 the new thing, or it might be showing a loading state while I'm loading the data. 534 00:29:06,233 --> 00:29:10,378 And my experience at least personally has been that We kind of accept 535 00:29:10,378 --> 00:29:13,978 this as just the way it is in UI development, but it's terrible. 536 00:29:13,978 --> 00:29:16,713 It's it's a lot of overhead to reason about. 537 00:29:16,873 --> 00:29:21,053 There are many, many more states your system can be in when you have asynchrony. 538 00:29:21,193 --> 00:29:21,273 Right? 539 00:29:21,273 --> 00:29:25,458 And the the vision for synchronous reactivity is let's make it again 540 00:29:25,458 --> 00:29:26,678 feel more like a spreadsheet. 541 00:29:26,818 --> 00:29:31,458 So the way I want my UI to feel is that when I select something, on the 542 00:29:31,458 --> 00:29:35,973 next tick, on the next frame, every pixel in the UI has fully updated 543 00:29:35,973 --> 00:29:38,233 to reflect that new user input. 544 00:29:38,728 --> 00:29:42,063 And that's obviously good for users because they didn't have to wait 545 00:29:42,663 --> 00:29:43,943 But it's also good for developers because you don't have to reason 546 00:29:43,943 --> 00:29:45,733 about the intermediate states. 547 00:29:46,223 --> 00:29:50,623 You can sort of think transactionally where The state of the world changes, 548 00:29:50,623 --> 00:29:56,383 and, transactionally, we update a bunch of derived views and queries of that state 549 00:29:56,433 --> 00:29:58,613 which end up in the pixels of the UI. 550 00:29:58,993 --> 00:30:01,733 And there was never any intermediate state exposed. 551 00:30:01,873 --> 00:30:06,548 And it's It's sort of a subtle point to get across, but my experience has been 552 00:30:06,548 --> 00:30:10,938 that when you work in a system like this it just Cuts a lot of complexity. 553 00:30:11,538 --> 00:30:11,858 Yeah. 554 00:30:11,931 --> 00:30:16,856 It's not just a simplification in terms of architecture that we collapse 555 00:30:16,916 --> 00:30:21,176 the stack from back end and API, etcetera, and all into the client. 556 00:30:21,551 --> 00:30:25,651 But that's, like, one giant dimension of complexity. 557 00:30:26,111 --> 00:30:30,746 But there is a second, much less talked about vector of complexity, 558 00:30:31,046 --> 00:30:34,756 which is like, how is how are things related to each other? 559 00:30:34,756 --> 00:30:38,941 Can they be synchronously related or can or do they have 560 00:30:38,941 --> 00:30:40,881 to be asynchronously related? 561 00:30:41,341 --> 00:30:45,361 And this is where I think we're getting into the area of distributed systems. 562 00:30:45,647 --> 00:30:50,286 I'm sure we'll talk a lot more in future episodes about broader distributed 563 00:30:50,286 --> 00:30:54,842 systems where they're really needed, where you have You're you have a device. 564 00:30:54,842 --> 00:30:55,641 You're in the US. 565 00:30:55,641 --> 00:30:57,582 I'm in Europe, and so we are distributed. 566 00:30:57,961 --> 00:31:01,481 However, if we are starting to treat a local React app that's 567 00:31:01,481 --> 00:31:06,236 running in single thread And we're coordinating the various React use 568 00:31:06,236 --> 00:31:08,496 states things with React useEffect. 569 00:31:08,876 --> 00:31:13,411 We've kinda accidentally created a distributed system that's It's really hard 570 00:31:13,411 --> 00:31:19,591 to tame and where it is, there can be many unintended bugs and just starts becoming 571 00:31:19,891 --> 00:31:22,471 a lot more complex to to think about. 572 00:31:22,616 --> 00:31:27,416 So this is the other part where I think it really it con where Riffle, 573 00:31:27,416 --> 00:31:33,251 again, liberates so much and simplifies and frees us of the the accidental 574 00:31:33,631 --> 00:31:37,171 distributed systems problem that we have in most modern web apps. 575 00:31:37,694 --> 00:31:43,059 I, you know, I, think to 2 principles that I think about one is don't 576 00:31:43,299 --> 00:31:46,519 make something a distributed system if it really doesn't have to be. 577 00:31:47,059 --> 00:31:51,219 And 2 is if it has to be, someone smarter than me should 578 00:31:51,219 --> 00:31:52,999 do the distributed systems part. 579 00:31:53,124 --> 00:31:53,624 Right. 580 00:31:53,954 --> 00:31:58,753 Really, we should be providing abstractions that allow us to not think 581 00:31:58,753 --> 00:32:00,614 about the hard parts most of the time. 582 00:32:01,214 --> 00:32:05,454 Even, you know, I'm not a CRDT expert, but I know quite a bit about CRDTs and 583 00:32:05,454 --> 00:32:07,234 have done some work on developing CRDTs. 584 00:32:07,934 --> 00:32:11,739 But and so I, you know, I Probably know more about CRTs than a lot of 585 00:32:11,739 --> 00:32:15,559 app devs, but I don't wanna think about distributed systems when 586 00:32:15,559 --> 00:32:17,239 I'm building some product feature. 587 00:32:17,239 --> 00:32:17,479 Right? 588 00:32:17,479 --> 00:32:21,454 And I think That is clearly one of the core challenges in the local-first space 589 00:32:21,454 --> 00:32:25,134 that I think a number of projects and companies are trying to address, which 590 00:32:25,134 --> 00:32:29,449 is what are the Good abstractions you can expose to app developers that allow 591 00:32:29,449 --> 00:32:35,994 them to reason about tricky distributed systems problems in a in a straightforward 592 00:32:36,054 --> 00:32:41,564 way without needing to turn on your sort of distributed systems brain as much. 593 00:32:42,044 --> 00:32:42,364 Yeah. 594 00:32:42,364 --> 00:32:42,844 Exactly. 595 00:32:42,844 --> 00:32:48,069 And I I think the Being confronted with distributed systems problems there is 596 00:32:48,069 --> 00:32:51,609 much more common than most app devs think. 597 00:32:52,104 --> 00:32:59,194 So most of the time when in React, you use useEffect that that hook to, yeah, somehow 598 00:32:59,494 --> 00:33:03,569 tame your local state, Then you already have a distributed systems problem. 599 00:33:04,029 --> 00:33:07,149 Things like React suspense and and so on. 600 00:33:07,149 --> 00:33:12,364 That that's kind of like a a solution to address partially the the distributed 601 00:33:12,424 --> 00:33:14,584 systems nature that you have in React. 602 00:33:14,584 --> 00:33:19,622 So, I remember having when React suspense, and all of those primitives came out. 603 00:33:19,622 --> 00:33:24,582 I was kinda wondering, how does that fit into our Riffle world here? 604 00:33:24,662 --> 00:33:28,822 would Riffle at some point support react suspense, and then at 605 00:33:28,822 --> 00:33:30,177 some point, it clicked for me. 606 00:33:30,417 --> 00:33:30,657 No. 607 00:33:30,707 --> 00:33:34,067 That's, like, addressing a problem that we've already ruled out 608 00:33:34,067 --> 00:33:39,127 before, and we don't even have to think about that complexity at all. 609 00:33:39,622 --> 00:33:44,692 And yeah, this is, like, entirely different approach to addressing 610 00:33:44,692 --> 00:33:49,207 the problems that React, Suspense, etcetera, is addressing in a, I would 611 00:33:49,207 --> 00:33:51,867 say, in a much simpler overall picture. 612 00:33:52,467 --> 00:33:52,787 Yeah. 613 00:33:52,787 --> 00:33:57,507 I think maybe to avoid overclaiming here, I'll say there are some trade offs. 614 00:33:57,507 --> 00:33:57,747 Right? 615 00:33:57,747 --> 00:34:02,102 I think Often, these approaches that involve concurrency are they're optimizing 616 00:34:02,162 --> 00:34:05,522 for either the reality of something like a slow network request or for 617 00:34:05,522 --> 00:34:09,427 sort of worst case performance making sure that you keep some things running 618 00:34:09,427 --> 00:34:11,287 fast even if other things are slow. 619 00:34:11,587 --> 00:34:15,567 And I think there's a different approach you can think about, which is, In a 620 00:34:15,567 --> 00:34:17,347 nutshell, just make everything fast. 621 00:34:17,487 --> 00:34:19,747 And as long as everything's fast, it'll be simple. 622 00:34:19,967 --> 00:34:22,927 If things get slow, you might end up with a worse experience than you 623 00:34:22,927 --> 00:34:26,812 might have in a system that, you know that is designed around concurrency. 624 00:34:26,872 --> 00:34:31,557 For example, maybe in a in a Riffle style approach, if you're trying to 625 00:34:31,557 --> 00:34:35,717 synchronously paint frames and something is slow, you might just end up with a ton 626 00:34:35,717 --> 00:34:38,377 of dropped frames and sort of a frozen UI. 627 00:34:38,652 --> 00:34:42,352 Whereas in a system designed to account for that with better concurrency support, 628 00:34:42,572 --> 00:34:46,112 you might have, you know, a loading spinner and some things remain responsive. 629 00:34:46,172 --> 00:34:49,527 And so I think Part of the challenge is figuring out how to 630 00:34:49,527 --> 00:34:51,867 how to balance those 2 approaches. 631 00:34:52,007 --> 00:34:56,462 And as we've seen in our work, I think sometimes you do need to account for 632 00:34:56,462 --> 00:34:59,182 the reality of sometimes you have to make a network request because, you 633 00:34:59,182 --> 00:35:02,142 know, you're talking to an external service or something, and you do 634 00:35:02,142 --> 00:35:03,522 need ways to model concurrency. 635 00:35:03,902 --> 00:35:07,702 It's just that I think We don't need to, I guess, throw the 636 00:35:07,702 --> 00:35:08,822 baby out with the bathwater. 637 00:35:08,822 --> 00:35:12,742 Like, not everything needs to be concurrent, and some things can be fast. 638 00:35:12,742 --> 00:35:15,447 I think I don't have much game dev experience, but I my understanding is 639 00:35:15,447 --> 00:35:19,047 that a lot of video games, essentially, you know, they paint frames, and 640 00:35:19,047 --> 00:35:20,382 they make sure every frame is fast. 641 00:35:20,542 --> 00:35:23,262 And they don't drop frames because they make sure the frames are fast. 642 00:35:23,262 --> 00:35:23,502 Right? 643 00:35:23,502 --> 00:35:28,322 And I wonder how much of that ethos we can apply to general UI development as well. 644 00:35:28,607 --> 00:35:33,507 So we've been referring to this thing, Riffle, now throughout this conversation. 645 00:35:33,727 --> 00:35:38,212 And clearly, you and I are well aware of what Riffle is, And you've motivated 646 00:35:38,432 --> 00:35:43,152 what Riffle is supposed to be through the principles and sort of what you were 647 00:35:43,152 --> 00:35:45,459 hoping to achieve with it in theory. 648 00:35:45,804 --> 00:35:48,784 But in reality, what is Riffle? 649 00:35:49,134 --> 00:35:51,554 Riffle was a research project. 650 00:35:52,014 --> 00:35:55,214 And so our primary goal was to try to get some of these ideas into people's 651 00:35:55,214 --> 00:35:58,754 heads, but we did need a way to test them out and see, is this even possible? 652 00:35:58,909 --> 00:36:00,029 Is this really a good idea? 653 00:36:00,029 --> 00:36:04,539 And to do that, we built a simple prototype reusing existing 654 00:36:04,539 --> 00:36:05,919 parts as much as possible. 655 00:36:06,544 --> 00:36:10,994 Namely, we we built on React JS as a view templating layer, and we built on 656 00:36:10,994 --> 00:36:15,424 SQLite, which is a popular relational database that can be embedded on 657 00:36:15,424 --> 00:36:17,764 devices and in the browser through Wasm. 658 00:36:18,439 --> 00:36:24,219 And what Riffle is, technically, is a layer that sits between React and SQLite. 659 00:36:24,439 --> 00:36:29,657 And what it does is it lets you specify a bunch of, SQL queries that turn a 660 00:36:29,657 --> 00:36:33,657 SQLite database into a React UI, and it gives you some hooks in your React 661 00:36:33,657 --> 00:36:38,332 UI to do things like query data in a component or make writes to your database. 662 00:36:38,792 --> 00:36:42,327 And you can think of it sort of as a state management framework built on 663 00:36:42,327 --> 00:36:46,257 top of SQLite for React that tries to realize some of these ideals we 664 00:36:46,257 --> 00:36:48,257 just talked about in a concrete way. 665 00:36:48,257 --> 00:36:48,757 Right? 666 00:36:49,167 --> 00:36:53,317 Now, again, this uh, was just sort of a prototype to explore the ideas. 667 00:36:53,377 --> 00:36:58,942 And one challenge we faced early on was how do we really test out if this works 668 00:36:59,162 --> 00:37:04,067 in the kinds of context we care about, which are complex data intensive apps with 669 00:37:04,367 --> 00:37:08,127 pretty large amounts of data relatively speaking and interesting schemas 670 00:37:08,127 --> 00:37:09,747 and strict performance requirements. 671 00:37:10,223 --> 00:37:13,342 To do apps are kinda boring and don't really address any of those 672 00:37:13,392 --> 00:37:16,033 and that's actually how we ended up collaborating with you on this. 673 00:37:16,033 --> 00:37:20,638 So, Maybe do you wanna tell the audience a bit about how you got involved? 674 00:37:21,447 --> 00:37:21,847 Yeah. 675 00:37:21,847 --> 00:37:22,347 Totally. 676 00:37:22,437 --> 00:37:26,837 We've been in touch since You worked on Cambria, and I think we've 677 00:37:26,837 --> 00:37:28,597 been catching up once in a while. 678 00:37:28,597 --> 00:37:32,952 And then at some point I learned about you thinking about this this broader 679 00:37:32,952 --> 00:37:35,932 space and rethinking state management. 680 00:37:36,073 --> 00:37:40,467 With my background of Prisma, I'm obviously no stranger to 681 00:37:40,467 --> 00:37:41,928 thinking about state management. 682 00:37:41,987 --> 00:37:45,047 I've been thinking about how to make it simpler, typically 683 00:37:45,107 --> 00:37:46,727 more in a back end context. 684 00:37:47,402 --> 00:37:51,422 And for me, this was really the the interesting foundation 685 00:37:51,472 --> 00:37:52,673 that you said, like, hey. 686 00:37:52,673 --> 00:37:54,517 Why why do you even want the back end? 687 00:37:54,867 --> 00:37:55,827 You wanna build an app. 688 00:37:55,827 --> 00:37:59,507 You didn't quite say it like this, but this is the way how I how I had sort of 689 00:37:59,507 --> 00:38:01,767 picked it up and framed it in in my head. 690 00:38:02,152 --> 00:38:06,712 And that was a really stimulating idea for me to say, like, actually, yeah, 691 00:38:06,712 --> 00:38:09,132 let's bring the database into the client. 692 00:38:09,427 --> 00:38:13,347 I was using a lot of MobX and Redux and those sort of things in 693 00:38:13,347 --> 00:38:15,747 the past, and they they worked. 694 00:38:15,747 --> 00:38:19,492 They made me productive, but they didn't have the properties that you mentioned 695 00:38:19,552 --> 00:38:21,892 before that state wasn't persistent. 696 00:38:22,612 --> 00:38:26,524 It fundamentally treated state and data differently. 697 00:38:26,664 --> 00:38:32,439 I would fetch my data from from a back end . It was a very Interesting idea for 698 00:38:32,439 --> 00:38:34,779 me to have the data all there locally. 699 00:38:35,239 --> 00:38:41,699 So and I was thinking about building my own music app for for quite a while, and 700 00:38:41,699 --> 00:38:46,039 Riffle seemed like the perfect catalyst for me to really take a stab at it. 701 00:38:46,179 --> 00:38:51,184 And the only way how I could could really make progress on such a 702 00:38:51,184 --> 00:38:57,444 big effort, mostly by myself, was to cut scope as much as possible. 703 00:38:58,139 --> 00:39:02,729 And that's that was a very simple math to say, like, hey. 704 00:39:02,729 --> 00:39:07,004 We can cut the scope from the back end categorically, and I can 705 00:39:07,004 --> 00:39:10,544 focus all of my energy and time on building the best client possible. 706 00:39:10,924 --> 00:39:15,879 And a music client is no nobody talks about, oh, that's the best music back end. 707 00:39:16,039 --> 00:39:18,439 People want the best music app. 708 00:39:18,439 --> 00:39:24,214 And that has led me to become the first design customer, does it first design 709 00:39:24,214 --> 00:39:27,914 partner for Riffle, and that made a a brilliant combination, I think. 710 00:39:28,474 --> 00:39:28,794 Yeah. 711 00:39:28,794 --> 00:39:33,069 I think one alignment and values that has really helped here is that, you're trying 712 00:39:33,069 --> 00:39:35,089 to build a music app for power users. 713 00:39:35,149 --> 00:39:35,649 Right? 714 00:39:35,949 --> 00:39:40,544 And I think power users often care about things like data density, latency. 715 00:39:40,544 --> 00:39:42,604 Um, you know, it's funny. 716 00:39:42,604 --> 00:39:45,644 When you look at apps like Spotify, for example, and we've we've talked about 717 00:39:45,644 --> 00:39:50,204 this many times over the course of this collaboration, Spotify, their desktop 718 00:39:50,264 --> 00:39:56,154 app is quite slow often and also quite network reliant to a surprising degree. 719 00:39:56,482 --> 00:40:01,092 Many page transitions that we've encountered even for data that is already 720 00:40:01,092 --> 00:40:05,713 locally cached, for some reason has a lot of network access going on, and you 721 00:40:05,713 --> 00:40:07,493 often get multi second loading screens. 722 00:40:07,873 --> 00:40:12,807 And I think for serious Music people like DJs you know, some of 723 00:40:12,807 --> 00:40:14,427 your target audience for Overtone. 724 00:40:14,647 --> 00:40:18,802 I think of it a bit the same way that, serious email people like apps like 725 00:40:18,802 --> 00:40:21,703 Superhuman that respect their time and make them really fast at email. 726 00:40:21,842 --> 00:40:27,538 A serious music fan wants an app that feels good and not some, you know, loading 727 00:40:27,538 --> 00:40:29,698 screen filled consumer feeling app. 728 00:40:29,698 --> 00:40:30,178 Right? 729 00:40:30,178 --> 00:40:32,898 And I think that was really aligned with some of the goals that we wanted 730 00:40:32,898 --> 00:40:36,883 to hit with the Riffle approach is, Basically, can you just throw all the 731 00:40:36,883 --> 00:40:40,663 music metadata in a SQLite database use relational queries, which are really 732 00:40:40,663 --> 00:40:44,658 good fit for things like joining together albums and artists and tracks, things 733 00:40:44,658 --> 00:40:49,418 like that, and power, the kind of power user experience that you wanted to build. 734 00:40:50,183 --> 00:40:50,683 Exactly. 735 00:40:50,743 --> 00:40:54,503 And I think this was literally also, like, the starting point for our 736 00:40:54,503 --> 00:40:57,638 first prototypes to do a data model. 737 00:40:57,638 --> 00:41:01,798 I'm kinda employing similar ideas that you use in back end development where 738 00:41:01,798 --> 00:41:03,478 you first lay out your different tables. 739 00:41:03,478 --> 00:41:06,113 In this case, I didn't actually create a user table. 740 00:41:06,113 --> 00:41:10,433 I still don't have a user table since the app just runs locally, but 741 00:41:10,433 --> 00:41:14,308 I did create a tracks table and a albums table and a playlist table. 742 00:41:14,468 --> 00:41:16,488 And we threw that together. 743 00:41:16,948 --> 00:41:20,468 And within the shortest period of time, we had a fully 744 00:41:20,468 --> 00:41:23,583 functional, very crude music app. 745 00:41:23,883 --> 00:41:29,913 And step by step yeah, we we I think we've been looking for reasons why it doesn't 746 00:41:29,913 --> 00:41:31,968 work, and we never found that reason. 747 00:41:31,968 --> 00:41:36,688 And then the months passed, and the collaboration now lasted, I think, 748 00:41:36,688 --> 00:41:38,468 for for almost, like, 2 years. 749 00:41:38,659 --> 00:41:42,386 And you've confirmed the hypothesis that you had with your with your 750 00:41:42,386 --> 00:41:45,046 PhD thesis at MIT for for Riffle. 751 00:41:45,159 --> 00:41:46,859 this made for a brilliant partnership. 752 00:41:47,459 --> 00:41:47,859 Yeah. 753 00:41:47,859 --> 00:41:51,219 I think you know, one of our goals with working with you 754 00:41:51,219 --> 00:41:52,839 was that first of all, yes. 755 00:41:52,839 --> 00:41:55,989 Like you said If it went well, which I think it has gone better 756 00:41:55,989 --> 00:41:59,509 than we expected, then it's more valuable confirmation, right, that, 757 00:41:59,509 --> 00:42:04,549 like, a real serious app works with this than, like, a to do MVC demo. 758 00:42:04,549 --> 00:42:05,559 So I think that was one thing. 759 00:42:05,559 --> 00:42:07,909 But, also, the the primary goal was not that. 760 00:42:07,909 --> 00:42:11,144 The primary goal was uncover what the real challenges are of building 761 00:42:11,144 --> 00:42:12,984 real software in this model. 762 00:42:12,984 --> 00:42:16,424 And maybe you could talk a bit about you know, throughout the project, 763 00:42:16,424 --> 00:42:22,549 you've been a a very useful critic and sort of have pointed out a lot 764 00:42:22,549 --> 00:42:26,544 of the the problems and challenges that come from working in this way. 765 00:42:26,604 --> 00:42:30,434 And I'm curious what your take has been on what the biggest problems 766 00:42:30,434 --> 00:42:32,289 we've had to solve have been. 767 00:42:33,264 --> 00:42:33,764 Totally. 768 00:42:34,064 --> 00:42:39,149 So I as a person, I like pioneering things. 769 00:42:39,229 --> 00:42:44,429 So I have probably a higher risk appetite, and I can deal with, like, a 770 00:42:44,429 --> 00:42:50,334 couple of more paper cuts temporarily than someone else who is just looking 771 00:42:50,334 --> 00:42:52,834 for the the best well trodden path. 772 00:42:53,359 --> 00:43:00,379 So, this this made me a viable partner here as opposed to to someone who 773 00:43:00,724 --> 00:43:04,904 only touches the technology that is already well proven over the years. 774 00:43:05,364 --> 00:43:11,179 And so I was rather looking for an advances on a in a broader scale, 775 00:43:11,179 --> 00:43:16,539 like, on a architectural level and just something that in the long run can help 776 00:43:16,539 --> 00:43:22,684 me reduce, and avoid complexity as much as possible even though temporarily 777 00:43:23,224 --> 00:43:27,829 possibly dealing with enduring a few more paper cuts here and there. 778 00:43:28,209 --> 00:43:33,489 And given that I am both comfortable in the shoes of an app builder as well 779 00:43:33,489 --> 00:43:36,494 as in the shoes of a tools builder. 780 00:43:36,824 --> 00:43:41,464 I think I was uniquely positioned to switch between those those 2 modes 781 00:43:41,464 --> 00:43:46,949 to unblock me etcetera, and to have enough imagination to understand, 782 00:43:47,009 --> 00:43:51,469 oh, this is not a categorical flaw in the way how things are right now. 783 00:43:51,469 --> 00:43:55,489 We can fix that through better tooling or refactoring of the API. 784 00:43:56,089 --> 00:44:01,934 So this I think it was kinda in in waves where there was some waves of 785 00:44:02,174 --> 00:44:07,534 immense productivity, and things have been working much better than expected. 786 00:44:07,694 --> 00:44:12,994 And at times, we've hit some walls of doubting, is this ever gonna work? 787 00:44:12,994 --> 00:44:18,054 Are those principles, the the ones that we've picked Are those the right ones? 788 00:44:18,274 --> 00:44:23,174 Is it a good idea to keep our entire state graph synchronous, 789 00:44:23,505 --> 00:44:24,945 can we make it fast enough? 790 00:44:24,945 --> 00:44:29,430 So we've been hitting those challenges, And the ones that are most memorable 791 00:44:29,570 --> 00:44:35,064 to me was really around performance I can motivate it from my perspective. 792 00:44:35,399 --> 00:44:38,359 I've set it for myself as a challenge. 793 00:44:38,359 --> 00:44:42,393 I want to build a music app That's fundamentally built with 794 00:44:42,393 --> 00:44:47,054 web technology that should still feel as fast as a native app. 795 00:44:47,514 --> 00:44:52,849 So that means If you're now looking at a 60 hertz display or a 120 796 00:44:52,869 --> 00:44:57,528 hertz display, if you scroll, if you interact with the app in some way, 797 00:44:57,864 --> 00:45:00,204 It should work without frame drops. 798 00:45:00,744 --> 00:45:05,014 And given that all state management, everything everything that changes 799 00:45:05,014 --> 00:45:11,014 on your screen, is fundamentally a result an implication of state change. 800 00:45:11,554 --> 00:45:17,109 And that this happens smoothly, it needs to happen in a 120 hertz. 801 00:45:17,329 --> 00:45:21,729 So, that basically gives you per frame, yep, less than 4 802 00:45:21,729 --> 00:45:26,304 milliseconds to do everything, state change, render, react, etcetera. 803 00:45:26,444 --> 00:45:31,164 So performance was always top of mind, and I think that where we've been going 804 00:45:31,164 --> 00:45:33,339 back and forth is it ever gonna work? 805 00:45:33,339 --> 00:45:33,819 Oh, yes. 806 00:45:33,819 --> 00:45:34,959 We can make it work. 807 00:45:35,259 --> 00:45:39,439 And that has kept us busy for for quite a while, and I think we can go more 808 00:45:39,864 --> 00:45:42,584 into depth what that's what that meant. 809 00:45:42,584 --> 00:45:47,304 But that's that's the top challenge that comes to mind besides a few, like, paper 810 00:45:47,304 --> 00:45:52,799 cuts and also figuring out, like, how do we the the starting point, even though 811 00:45:52,799 --> 00:45:58,504 this is a local-first podcast, Riffle Up to this point, it was mostly local only. 812 00:45:58,964 --> 00:46:03,334 And just in a later point, we're making we're introducing the the collaboration 813 00:46:04,069 --> 00:46:06,049 aspect to make it truly local-first. 814 00:46:07,029 --> 00:46:11,049 But yeah, I think performance been the the major challenge that we've been facing. 815 00:46:11,349 --> 00:46:15,159 You know, the way I think about performance in this stack is that the role 816 00:46:15,159 --> 00:46:17,979 of the database is to make things fast. 817 00:46:18,309 --> 00:46:22,044 What a database does is you give it nice declarative queries, And it figures 818 00:46:22,044 --> 00:46:25,324 out how to make them fast because some smart people worked very hard, 819 00:46:25,324 --> 00:46:26,604 and you didn't have to do that work. 820 00:46:26,604 --> 00:46:27,104 Right? 821 00:46:27,244 --> 00:46:31,199 And I think a lot of the challenges we've hit basically boil down to, um, 822 00:46:31,199 --> 00:46:35,809 we don't quite have the right database for this use case or a shape yet. 823 00:46:36,029 --> 00:46:41,284 A lot of UI stuff, I think, boils down to the problem of incremental computation. 824 00:46:42,064 --> 00:46:45,984 Incremental computation is a is a pretty broad, you know, computer science term. 825 00:46:45,984 --> 00:46:50,149 That basically means I have a function and the input changes a little bit. 826 00:46:50,289 --> 00:46:54,894 Can we figure out how the output changed without starting over 827 00:46:54,894 --> 00:46:56,574 from scratch on the fresh input. 828 00:46:56,574 --> 00:46:57,074 Right? 829 00:46:57,294 --> 00:47:00,434 And this is a problem that people have approached from a number of sides. 830 00:47:00,574 --> 00:47:04,159 The sort of programming languages community has approached this problem. 831 00:47:04,209 --> 00:47:07,209 You know, incremental computation is the keyword that can highlight 832 00:47:07,209 --> 00:47:08,469 a lot of the work there. 833 00:47:08,639 --> 00:47:11,599 But the databases community has also thought a lot about this problem. 834 00:47:11,599 --> 00:47:14,024 They Often call it incremental view maintenance. 835 00:47:14,434 --> 00:47:18,194 You know, an example might be I have a big join on thousands of 836 00:47:18,194 --> 00:47:20,454 rows and I add one row to the table. 837 00:47:20,699 --> 00:47:22,699 How does the result change. 838 00:47:22,699 --> 00:47:23,019 Right? 839 00:47:23,019 --> 00:47:27,774 And I think a lot of the reasons we've had performance challenges is that our 840 00:47:27,934 --> 00:47:32,441 technical stack has mostly been based on SQLlite which is a database that is sort 841 00:47:32,441 --> 00:47:34,221 of built for UI, but is not incremental. 842 00:47:34,821 --> 00:47:40,517 We did some explorations with a database called SKDB which is actually a SQL 843 00:47:40,517 --> 00:47:44,146 database designed to be incremental, And that yielded some pretty 844 00:47:44,146 --> 00:47:45,506 interesting and promising results. 845 00:47:45,506 --> 00:47:49,026 We actually published a paper at the UIST conference, which talked 846 00:47:49,026 --> 00:47:52,391 about some of our positive results from working with that technology. 847 00:47:52,721 --> 00:47:56,081 I think, ultimately, you ended up deciding to stick with SQLite for the 848 00:47:56,081 --> 00:48:00,166 production Overtone app because you wanted a sort of a more, you know, mature 849 00:48:00,766 --> 00:48:02,546 database to work with as your foundation. 850 00:48:02,606 --> 00:48:07,271 But the way I see the problem is really that we sort of need the right database 851 00:48:07,271 --> 00:48:11,831 that has the right primitives to make UI development of this sort fast. 852 00:48:11,831 --> 00:48:15,236 And maybe the perfect database for that doesn't quite exist yet. 853 00:48:15,836 --> 00:48:19,916 But I think that's that that's the missing piece and the ultimate, you 854 00:48:19,916 --> 00:48:24,621 know, decade ahead if this really panned out, version of the stack, I 855 00:48:24,621 --> 00:48:26,161 think, would include that database. 856 00:48:26,761 --> 00:48:27,241 Yeah. 857 00:48:27,241 --> 00:48:27,741 Totally. 858 00:48:27,986 --> 00:48:31,826 And I I think it's a matter of, like, now it's early 20 24. 859 00:48:31,826 --> 00:48:32,386 Who knows? 860 00:48:32,386 --> 00:48:36,721 Maybe next year, the the world has already moved closer into the 861 00:48:36,721 --> 00:48:40,421 direction that is a good foundation for for something like Riffle. 862 00:48:40,831 --> 00:48:44,271 The the audience shouldn't have the takeaways like SQLite is slow. 863 00:48:44,271 --> 00:48:45,231 Quite the opposite. 864 00:48:45,231 --> 00:48:50,826 I think this was the insight that SQLite is incredibly fast and remarkably 865 00:48:51,046 --> 00:48:55,686 capable was the foundation to embark on this project in the first place. 866 00:48:55,686 --> 00:48:59,861 Nicholas has been through his prior work at Apple, Done a lot 867 00:48:59,861 --> 00:49:03,881 of work related to SQLite and I think related to to FoundationDB. 868 00:49:04,481 --> 00:49:08,415 And that was one of the key insights that we say, like, Actually, SQLite is 869 00:49:08,415 --> 00:49:13,615 so fast and now can be embedded into web applications through Wasm that it 870 00:49:13,615 --> 00:49:18,760 can be a replacement technology for some for, like, MobX and and Redux. 871 00:49:18,810 --> 00:49:23,730 So before WASM, etcetera, and all of the optimizations that have gone into that. 872 00:49:23,870 --> 00:49:25,410 This wouldn't have been possible. 873 00:49:25,470 --> 00:49:31,560 But now that's possible this allowed for a better foundation for to deal 874 00:49:31,560 --> 00:49:36,280 with complexity since if you build something with MOBX, etcetera, you 875 00:49:36,280 --> 00:49:40,448 still need to wrangle all of your JavaScript objects by yourself. 876 00:49:40,448 --> 00:49:44,783 Like, if you want to have, like, a filter or map or group by, you gotta 877 00:49:44,783 --> 00:49:45,983 implement all of that yourself. 878 00:49:45,983 --> 00:49:51,683 And the app user experience that I want to enable with Overtone 879 00:49:52,348 --> 00:49:54,428 is this will be very common. 880 00:49:54,428 --> 00:49:58,668 Think about it, like, in Notion when you have the tables feature and 881 00:49:58,668 --> 00:50:01,393 you have You configure a few sorts. 882 00:50:01,393 --> 00:50:03,073 You configure some group buys. 883 00:50:03,073 --> 00:50:04,293 You have different views. 884 00:50:04,673 --> 00:50:08,033 Those are all things that get very boilerplatey to implement 885 00:50:08,033 --> 00:50:13,398 with JavaScript, and those are all things databases are super good at. 886 00:50:13,778 --> 00:50:18,098 And this is what got me over the fence to say, like, actually, let's 887 00:50:18,098 --> 00:50:22,643 embrace what the database is good at, and build a bit of, like, the 888 00:50:22,863 --> 00:50:25,238 React nice to have things around it. 889 00:50:25,878 --> 00:50:31,608 And I think the the core of what Riffle is is really like that combination 890 00:50:32,423 --> 00:50:37,483 of a underlying SQLite database and put a reactivity system on top of it. 891 00:50:37,783 --> 00:50:42,638 And reactivity system in that regard is, like, how React Components compose, 892 00:50:42,698 --> 00:50:46,798 and if one thing changes, then the other thing updates to the minimal degree. 893 00:50:47,048 --> 00:50:48,728 That's what Riffle is doing. 894 00:50:48,728 --> 00:50:53,833 And A very simple idea with many implications and remarkably powerful. 895 00:50:54,658 --> 00:50:55,138 Yeah. 896 00:50:55,138 --> 00:50:59,568 You know, I I think you're you're right, and it extends beyond performance too. 897 00:50:59,593 --> 00:51:03,703 I think when you think about the requirements of what a UI needs, I 898 00:51:03,703 --> 00:51:08,288 think that when you remove all the layers that typically sit between a 899 00:51:08,288 --> 00:51:10,388 back end relational database and a UI. 900 00:51:10,878 --> 00:51:13,438 Those layers were there for a reason. 901 00:51:13,438 --> 00:51:15,598 They were solving some problem, and you end up needing to find 902 00:51:15,598 --> 00:51:16,783 ways to solve those problems. 903 00:51:16,783 --> 00:51:23,088 So, often, UIs need tree shaped data to hydrate a tree of a UI. 904 00:51:23,088 --> 00:51:23,588 Right? 905 00:51:23,918 --> 00:51:28,548 Often front end developers don't already know SQL. 906 00:51:28,548 --> 00:51:32,463 And often, actually, SQL, we found can be a mediocre language for 907 00:51:32,463 --> 00:51:33,983 certain parts of UI development. 908 00:51:33,983 --> 00:51:37,213 It often just feels a little bit too low level or something. 909 00:51:37,213 --> 00:51:40,788 Obviously, you know, having worked on Prisma, you, I think, have experience with 910 00:51:40,788 --> 00:51:44,848 some of those problems in the back-end context, but I think some of them become 911 00:51:44,848 --> 00:51:47,349 even more apparent in a front-end context. 912 00:51:47,949 --> 00:51:51,809 Some of the you know, I I don't wanna necessarily necessarily say the ORM 913 00:51:52,189 --> 00:51:55,489 word because I think that's a touchy topic, but I think some of the roles of 914 00:51:56,089 --> 00:51:59,689 associating different kinds of models with each other and things like that, 915 00:51:59,689 --> 00:52:03,449 there's sort of, sometimes feels like there's a need for for that kind of layer. 916 00:52:03,449 --> 00:52:03,949 Right? 917 00:52:04,549 --> 00:52:08,229 I think you know, in our technical prototype stack, what we ended up doing 918 00:52:08,229 --> 00:52:13,633 was stuffing a GraphQL layer in there between SQLite and the UI you know, 919 00:52:13,633 --> 00:52:17,143 because you're a GraphQL expert and that helped alleviate some of these problems. 920 00:52:17,143 --> 00:52:22,598 But, again, I think I see and I think we we see that more as a as a shim. 921 00:52:22,598 --> 00:52:22,918 Right? 922 00:52:22,918 --> 00:52:25,798 Like, sort of, a layer that shouldn't need to be there, but 923 00:52:25,798 --> 00:52:28,538 it's there because the database didn't quite have the right shape. 924 00:52:28,593 --> 00:52:34,703 And I think some of that reflects that maybe no one has ever designed a database 925 00:52:34,898 --> 00:52:39,208 specifically for this role of being embedded so closely to a user interface. 926 00:52:39,983 --> 00:52:40,383 Yeah. 927 00:52:40,383 --> 00:52:40,883 Totally. 928 00:52:40,943 --> 00:52:43,503 I mean, I I think about it this way. 929 00:52:43,503 --> 00:52:48,038 We wanna take one or 2 steps forward, But in order to do that, we also 930 00:52:48,038 --> 00:52:49,898 had to take a step backwards. 931 00:52:50,518 --> 00:52:54,918 And the the step forward that we took is that we get the power of a database, 932 00:52:54,918 --> 00:52:59,398 that we get all of those semantics that a database give us, whether it's group by 933 00:52:59,398 --> 00:53:03,113 and sorting and nested selects, etcetera. 934 00:53:03,173 --> 00:53:07,934 All all of those great things that would really um, freeze up our work 935 00:53:07,934 --> 00:53:12,298 and make some things that we would need to imperatively implement in 936 00:53:12,298 --> 00:53:14,079 JavaScript makes that declarative. 937 00:53:14,698 --> 00:53:20,519 However, the steps that we're taking back is that, In SQLite, it's quite limited. 938 00:53:20,519 --> 00:53:22,199 It doesn't have many data types. 939 00:53:22,199 --> 00:53:24,298 It doesn't even have a Boolean type, etcetera. 940 00:53:24,439 --> 00:53:29,271 So you need to do a lot of translation between the way how SQLite understands 941 00:53:29,271 --> 00:53:34,726 the world and how someone who's, like, a a more sophisticated 942 00:53:35,026 --> 00:53:36,886 TypeScript developer as me. 943 00:53:37,026 --> 00:53:40,466 I'm used to having all of my fancy TypeScript types. 944 00:53:40,466 --> 00:53:45,906 And to create a good translation layer between that embedded SQLite database 945 00:53:45,906 --> 00:53:51,121 and what I want in my JavaScript now we gotta reinvest in that. 946 00:53:51,341 --> 00:53:52,881 And so you've mentioned GraphQL. 947 00:53:53,101 --> 00:53:58,146 That was sort of a technology that I was quite familiar with from prior 948 00:53:58,146 --> 00:54:04,806 work, and I think that's sort of a temporary usage until we we teach SQLite 949 00:54:04,946 --> 00:54:10,130 some of the tricks that TypeScript already knows and until we create a 950 00:54:10,130 --> 00:54:12,791 a better mapping in in between that. 951 00:54:13,090 --> 00:54:18,896 But that's certainly been another, For me, less of a challenge, but it still requires 952 00:54:18,896 --> 00:54:24,442 quite a bit of work to make SQLite feel and a native in a TypeScript setting. 953 00:54:24,742 --> 00:54:28,502 Some people, I think, believe that one of the sort of original sins 954 00:54:28,502 --> 00:54:32,067 of computing, so to speak, is that programming languages and databases 955 00:54:32,287 --> 00:54:34,367 really split into separate fields. 956 00:54:34,367 --> 00:54:38,287 And the idea of, like, the system that you use to wrangle your runtime 957 00:54:38,287 --> 00:54:41,852 in memory state And the system that you use to persist and query your 958 00:54:41,852 --> 00:54:45,962 persisted state are so separate in the way you think about them. 959 00:54:45,962 --> 00:54:49,547 You historically, you have systems like small talk, for which 960 00:54:49,547 --> 00:54:50,907 have much less of a separation. 961 00:54:50,907 --> 00:54:55,308 They're closer to you have objects in your language and you're just saving 962 00:54:55,308 --> 00:54:59,002 those objects and reloading them, And there's much less of a gap there. 963 00:54:59,002 --> 00:54:59,242 Right? 964 00:54:59,242 --> 00:55:02,872 And something I found interesting about some of the more recent work you've 965 00:55:02,872 --> 00:55:06,677 been doing in this space is you know, you've been working on tools that make 966 00:55:06,677 --> 00:55:11,527 it easier to close that gap and let you think about the kinds of in memory 967 00:55:11,747 --> 00:55:16,182 objects that you wanna be thinking about in your program, and turn those into the 968 00:55:16,182 --> 00:55:20,122 things that you wanna be storing in your database and querying and vice versa. 969 00:55:20,422 --> 00:55:23,511 And I think that's again one of the really interesting challenges in 970 00:55:23,511 --> 00:55:29,001 this space is handling that impedance mismatch between a relational database 971 00:55:29,141 --> 00:55:31,936 and, your TypeScript code or whatever. 972 00:55:31,936 --> 00:55:35,266 Do you wanna talk a bit about that area you've been working on? 973 00:55:35,280 --> 00:55:35,521 Yeah. 974 00:55:35,521 --> 00:55:36,021 Totally. 975 00:55:36,161 --> 00:55:39,940 I think this is also, like, a for for you, like, a broader umbrella 976 00:55:40,001 --> 00:55:44,406 of of your work that contextualizes everything you've been doing over the 977 00:55:44,406 --> 00:55:48,566 past few years and will probably still be the foundation for for the the 978 00:55:48,566 --> 00:55:50,666 years to come as Malleable software. 979 00:55:51,001 --> 00:55:56,801 For me a common theme seems to be all around schema management and 980 00:55:56,801 --> 00:56:01,796 kind of fighting that impedance mismatch from different contexts. 981 00:56:02,106 --> 00:56:07,971 And so I've been trying uh, to make that simpler in the context of of Riffle. 982 00:56:07,971 --> 00:56:12,651 And in a way that nicely brings us back to the initial topic that we talked about 983 00:56:12,651 --> 00:56:18,003 with Cambria since it's not just Already hard to deal with that appease mismatch 984 00:56:18,463 --> 00:56:23,366 between your application, types that are expressed, for example, in TypeScript 985 00:56:23,506 --> 00:56:28,086 and the way how a database thinks about it how it stores the the data. 986 00:56:28,651 --> 00:56:31,051 But both can also change over time. 987 00:56:31,051 --> 00:56:33,311 You wanna implement new features, etcetera. 988 00:56:33,531 --> 00:56:39,356 So your database schema might change, Your app types change, so you also get a 989 00:56:39,356 --> 00:56:44,881 deal with with schema change management here, which hopefully, we'll we'll 990 00:56:44,881 --> 00:56:49,551 get to bring some of the goodness of Cambria in into the fold here as well. 991 00:56:49,551 --> 00:56:55,346 Schema migrations is still Sort of a untamed problem, but we're we're 992 00:56:55,346 --> 00:56:56,786 getting ahead of ourselves here. 993 00:56:56,786 --> 00:57:00,941 So, if Someone in the audience thinks about, okay. 994 00:57:01,081 --> 00:57:02,541 Riffle sounds great. 995 00:57:02,881 --> 00:57:04,261 Can I use it? 996 00:57:04,351 --> 00:57:08,846 You've been mentioning that you've been doing this as part of your PhD at MIT. 997 00:57:09,146 --> 00:57:11,485 What is the current state of Riffle? 998 00:57:12,085 --> 00:57:12,565 Yeah. 999 00:57:12,565 --> 00:57:15,525 I get asked this question from time to time, so it's probably 1000 00:57:15,525 --> 00:57:16,745 good to provide an update. 1001 00:57:17,235 --> 00:57:19,415 So Riffle was a research project fundamentally. 1002 00:57:19,610 --> 00:57:23,310 The goal was to explore this idea and see if it was possible or a good idea. 1003 00:57:24,280 --> 00:57:28,780 It ended up being part of my PhD thesis, and I wrapped up grad school. 1004 00:57:29,335 --> 00:57:33,805 And at this point, sort of the the core Riffle project itself is is, 1005 00:57:34,665 --> 00:57:36,185 I would say, it's basically over. 1006 00:57:36,235 --> 00:57:40,149 We published a paper at the UIST HCI conference this year that 1007 00:57:40,149 --> 00:57:41,689 summarizes some of what we learned. 1008 00:57:42,019 --> 00:57:44,177 However the ideas are not, dead. 1009 00:57:44,557 --> 00:57:48,107 So, actually, you, Johannes, have been sort of carrying the torch forward 1010 00:57:48,107 --> 00:57:51,067 to some of these ideas and building them into a new library that you're 1011 00:57:51,067 --> 00:57:56,452 building, that has sort of replaced Riffle as the foundation for your work 1012 00:57:56,452 --> 00:58:00,746 on Overtone and so maybe you could talk a bit about your ongoing work there. 1013 00:58:01,532 --> 00:58:01,851 Yeah. 1014 00:58:01,851 --> 00:58:02,351 Totally. 1015 00:58:02,651 --> 00:58:07,602 So for me, what's been the most valuable thing over the course of 1016 00:58:07,602 --> 00:58:12,596 the past few years in terms of our collaboration is, a, that collaboration, 1017 00:58:12,897 --> 00:58:17,301 that partnership, and really doing a lot of research and exploratory work 1018 00:58:17,462 --> 00:58:23,121 together and then, yeah, b, having sort of, like, a prototype implementation 1019 00:58:23,342 --> 00:58:24,621 of what that could look like. 1020 00:58:24,621 --> 00:58:29,136 But it was really a prototype implementation that could prove 1021 00:58:29,136 --> 00:58:30,836 out those different ideas. 1022 00:58:31,536 --> 00:58:37,072 But to make actual progress with Overtone, I was running into a lot of 1023 00:58:37,072 --> 00:58:42,126 the limitations of the those prototypes where it was working on the happy path. 1024 00:58:42,526 --> 00:58:47,346 The not so happy path was unexplored and started causing 1025 00:58:47,486 --> 00:58:49,006 a bunch of problems for me. 1026 00:58:49,006 --> 00:58:53,891 So this caused me not to throw out the baby with the bathwater and reach back 1027 00:58:53,891 --> 00:58:56,951 for something like MobX or or Redux. 1028 00:58:57,696 --> 00:59:04,436 But it has led me to yeah, where put on my dev tool builder hat again. 1029 00:59:04,932 --> 00:59:11,041 And I started productionizing the ideas of Rifflemore, and I did 1030 00:59:11,041 --> 00:59:15,316 that under a new umbrella, which is a library called LiveStore. 1031 00:59:15,856 --> 00:59:17,856 It is not yet open source. 1032 00:59:17,856 --> 00:59:22,101 I'm hoping to get it open source sometime this year. 1033 00:59:22,611 --> 00:59:23,171 Right now. 1034 00:59:23,171 --> 00:59:28,291 If someone is curious to give it a try it is possible right now if 1035 00:59:28,291 --> 00:59:30,786 you are sponsoring the the project. 1036 00:59:30,867 --> 00:59:32,786 That's a topic for another day. 1037 00:59:32,786 --> 00:59:35,550 I'm hoping to make development of LiveStore sustainable. 1038 00:59:36,330 --> 00:59:41,510 And through GitHub sponsorship is one way how I'm currently planning to do so. 1039 00:59:41,810 --> 00:59:46,820 But, yeah, the ideas of Riffle live on and possibly multiple projects in the 1040 00:59:46,820 --> 00:59:49,080 future, LiveStore being one of them. 1041 00:59:49,140 --> 00:59:53,635 I'm sure your work on Riffle has inspired more folks to implement 1042 00:59:53,635 --> 00:59:55,405 similar ideas in the future. 1043 00:59:55,705 --> 00:59:59,005 So that's that's what I can contribute right now. 1044 00:59:59,655 --> 00:59:59,975 Yeah. 1045 00:59:59,975 --> 01:00:02,295 I'm really excited to see where your work with Livestore goes. 1046 01:00:02,295 --> 01:00:06,185 You know, I think You have some some cool stuff cooking and places you're trying 1047 01:00:06,185 --> 01:00:11,030 live store, and I'm sure you're gonna keep learning a ton more about where 1048 01:00:11,030 --> 01:00:13,210 this approach works and new challenges. 1049 01:00:13,350 --> 01:00:13,850 Right? 1050 01:00:13,910 --> 01:00:17,180 But it's very exciting to me that these ideas are living on in your work. 1051 01:00:17,825 --> 01:00:18,225 Yeah. 1052 01:00:18,225 --> 01:00:26,225 And so Geoffrey and I are still touching base every so often, and I share my 1053 01:00:26,225 --> 01:00:28,925 updates and progress on LiveStore. 1054 01:00:28,945 --> 01:00:34,629 And Now step by step I get to make progress on some parts that we haven't 1055 01:00:34,629 --> 01:00:40,754 quite got to yet while working on the Riffle research project and 1056 01:00:40,754 --> 01:00:46,534 where I get to unlock some progress where Geoffrey thinks, oh, yes. 1057 01:00:46,834 --> 01:00:50,099 Finally, we're getting to that point that we haven't gotten 1058 01:00:50,099 --> 01:00:52,039 to while working on Riffle. 1059 01:00:52,419 --> 01:00:59,536 And I now I'm I have to face all of those bigger, implications that 1060 01:00:59,536 --> 01:01:02,736 we've been well aware of, but we just haven't gotten to them yet, whether 1061 01:01:02,736 --> 01:01:07,731 it's schema migrations or making the technology actually local-first. 1062 01:01:07,941 --> 01:01:12,261 So introducing syncing and collaboration capabilities, and I wanna do so 1063 01:01:12,261 --> 01:01:16,846 in a way that is compatible with different kinds of syncing approaches, 1064 01:01:16,986 --> 01:01:20,826 whether it might be something like electric SQL or possibly something 1065 01:01:20,826 --> 01:01:23,326 like Auto Merge or Yjs in the future. 1066 01:01:23,626 --> 01:01:28,606 So there in a way, we've come really far, and in a way, we are just getting started. 1067 01:01:28,881 --> 01:01:31,381 So I'm I'm super excited about that. 1068 01:01:31,981 --> 01:01:37,801 So we've been talking a lot about SQLite, Riffle, LiveStore, But you've 1069 01:01:37,801 --> 01:01:40,061 since moved on to to new projects. 1070 01:01:40,121 --> 01:01:44,945 So and I think you're still at Ink and Switch even more so than for I 1071 01:01:44,945 --> 01:01:49,746 think you're now full time at Ink and Switch and are already in new projects. 1072 01:01:49,746 --> 01:01:53,286 So which sort of problems are you currently looking at? 1073 01:01:53,886 --> 01:01:54,206 Yeah. 1074 01:01:54,206 --> 01:02:00,025 So since finishing my PhD earlier I guess last year over the summer, I've now 1075 01:02:00,025 --> 01:02:03,895 for a few months been full time at the Ink and Switch Research Lab where Peter 1076 01:02:03,895 --> 01:02:05,676 Van Hardenberg again is the director. 1077 01:02:06,276 --> 01:02:10,256 You know, they're where a lot of the look they they coined the term local-first. 1078 01:02:10,276 --> 01:02:10,515 Right? 1079 01:02:10,515 --> 01:02:14,261 And so they're what got me into this space in in some sense, and I'm 1080 01:02:14,421 --> 01:02:16,341 Really excited to be full time there. 1081 01:02:16,391 --> 01:02:19,291 I'm leading our malleable software research track now. 1082 01:02:19,431 --> 01:02:22,791 And so that's basically a research track where we explore these ideas 1083 01:02:22,791 --> 01:02:24,236 around customizable software. 1084 01:02:24,456 --> 01:02:28,776 And we really are interested particularly in the intersection 1085 01:02:28,836 --> 01:02:32,091 of the local-first architecture and the malleable software agenda. 1086 01:02:32,091 --> 01:02:36,111 And we have a lot of ideas for how those 2 things can be kind of complementary 1087 01:02:36,171 --> 01:02:38,191 to each other as I described earlier. 1088 01:02:39,066 --> 01:02:41,006 We have some fun experiments brewing. 1089 01:02:41,656 --> 01:02:46,856 one thing is that we're increasingly trying to use our own local-first tools. 1090 01:02:46,856 --> 01:02:50,331 So one Little project I worked on in my past few months there is 1091 01:02:50,501 --> 01:02:54,441 spinning up a writing tool that we use internally at the lab. 1092 01:02:54,846 --> 01:02:59,436 We used it to write our last essay that we published and that's based on the auto 1093 01:02:59,436 --> 01:03:01,696 merge stack that the lab has developed. 1094 01:03:01,836 --> 01:03:05,871 And it's a really nice way to sort of, Again, just get some authentic 1095 01:03:05,871 --> 01:03:08,511 experience using the stack and understanding the challenges and 1096 01:03:08,511 --> 01:03:10,450 the and the and the good stuff. 1097 01:03:10,671 --> 01:03:11,171 Right? 1098 01:03:11,771 --> 01:03:16,011 We're then kind of using that stack as a foundation to explore a lot 1099 01:03:16,011 --> 01:03:18,331 more speculative stuff going forward. 1100 01:03:18,381 --> 01:03:18,796 You Yeah. 1101 01:03:18,796 --> 01:03:22,635 Some of the ideas we're excited to explore are the potential for version 1102 01:03:22,635 --> 01:03:24,975 control in a local-first environment. 1103 01:03:25,065 --> 01:03:29,680 If you have, a layer like auto merge in your stack, which is really designed 1104 01:03:29,680 --> 01:03:34,565 around not just local-first data, but also storing, past history of 1105 01:03:34,565 --> 01:03:38,585 documents, what can you do with that potential to unlock for end users. 1106 01:03:38,915 --> 01:03:43,010 And another theme we're gonna explore, and have started exploring a bit already 1107 01:03:43,070 --> 01:03:48,290 is not just data in a local-first way, but code in a local-first way. 1108 01:03:48,350 --> 01:03:53,800 So if you put code on people's devices in a way that they can mod 1109 01:03:53,800 --> 01:03:58,060 themselves what does that unlock in terms of customizing our software? 1110 01:03:58,348 --> 01:04:03,138 This is sort of a fully maximalist local-first approach and it's something 1111 01:04:03,138 --> 01:04:07,103 that Peter and the lab have explored in the past but it's, you know, there's a 1112 01:04:07,103 --> 01:04:11,343 project called Pushpin, which I encourage people to look at if they haven't 1113 01:04:11,343 --> 01:04:15,503 heard of it, which is basically, an exploration of what happens if you have 1114 01:04:15,753 --> 01:04:20,733 local-first data plus flexible tools that can op that can operate on that data. 1115 01:04:20,988 --> 01:04:25,628 And I'm excited to keep pushing in those directions and see if we can basically 1116 01:04:25,628 --> 01:04:29,473 give people more control and empowerment over their computing experience on 1117 01:04:29,473 --> 01:04:31,333 top of this local-first data stack. 1118 01:04:31,933 --> 01:04:32,833 That is incredible. 1119 01:04:33,213 --> 01:04:38,838 I'm very tempted to also somehow contribute more in those various 1120 01:04:38,838 --> 01:04:40,378 topics that you've been mentioning. 1121 01:04:40,518 --> 01:04:41,018 But 1122 01:04:41,543 --> 01:04:46,343 My day has just so many hours, and I think I have still a lot of work ahead 1123 01:04:46,343 --> 01:04:48,683 of me with LiveStore and and Overtone. 1124 01:04:49,368 --> 01:04:53,308 However, I think there will be many problems that will have positive overlap. 1125 01:04:53,608 --> 01:04:56,168 I think we're still not done with the Cambria problem. 1126 01:04:56,168 --> 01:04:58,508 Maybe we get to collaborate there in the future. 1127 01:04:58,723 --> 01:05:02,823 We've been doing also some really interesting exploratory work around 1128 01:05:03,043 --> 01:05:07,283 what does it mean for an app to have version control for for users. 1129 01:05:07,283 --> 01:05:11,248 That is something I'm really interested in so I'm I'm sure 1130 01:05:11,248 --> 01:05:15,668 we'll we'll get another stab at collaborating on some project together. 1131 01:05:16,268 --> 01:05:19,148 But, yeah, Geoffrey, I've been looking forward to this for a long 1132 01:05:19,148 --> 01:05:23,983 time and really excited to share what we've been working on over the past 1133 01:05:23,983 --> 01:05:25,843 few years with a broader audience. 1134 01:05:26,383 --> 01:05:30,223 And thank you so much for for taking the time and sharing all of those 1135 01:05:30,223 --> 01:05:32,173 stories and and insights with us. 1136 01:05:32,323 --> 01:05:32,613 Thank you. 1137 01:05:32,636 --> 01:05:32,828 you 1138 01:05:33,048 --> 01:05:33,768 Thanks so much. 1139 01:05:33,768 --> 01:05:34,748 It's been fun. 1140 01:05:35,348 --> 01:05:37,998 Thank you for listening to the localfirst.fm podcast. 1141 01:05:38,218 --> 01:05:42,418 If you've enjoyed this episode and haven't done so already, please subscribe and 1142 01:05:42,418 --> 01:05:44,218 leave a review wherever you're listening. 1143 01:05:44,988 --> 01:05:47,858 Please also consider telling your friends about it, if you think they 1144 01:05:47,858 --> 01:05:49,348 could be interested in local-first. 1145 01:05:50,228 --> 01:05:53,878 Thank you again to Expo and Crab Nebula for supporting this podcast. 1146 01:05:54,148 --> 01:05:54,948 See you next time.