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.