17:04Absolutely.
17:04So, you know, the first principle
I talked about is thinking of an
17:08application as a database query.
17:10Right?
17:10And, actually, to throw a
little more detail in there,
17:13it's not one database query.
17:15It's actually a graph of database
queries with dependencies.
17:17Now that starts to sound kind of
fancy, but I think we all understand
17:21this model from using spreadsheets.
17:23The the metaphor, I think, to
think about is can You make coding
17:27a rich, complex application as
simple as using a spreadsheet.
17:32Spreadsheets dependency tracking
of formulas and automatic
17:36Dependency propagation is the
bread and butter of spreadsheets.
17:38It's one of the key features
that makes them useful.
17:41Right?
17:41When you're using a spreadsheet
and you update a cell, The contract
17:44that Excel gives you is typically
instantly or at least very quickly,
17:48unless you're in a huge spreadsheet,
everything will be up to date.
17:51You're never worried about staleness.
17:53You're never thinking about caching.
17:55That complexity of dependency propagation
is pushed down into the system.
17:59Right?
18:00And I would note, I think this
is a lesson that we've definitely
18:03learned in UI development.
18:05You could definitely say that reactive
UI frameworks like, React JS give
18:10you something like this guarantee.
18:12Right?
18:12They you declare the UI you want and
state and DOM are synced automatically.
18:18The problem that I see is that often
in our web stacks, this reactivity
18:22is partial to one part of the stack.
18:25So in in a common web application,
your React UI, what it's
18:29faithfully representing is not
all the state in your system.
18:33It's some view you currently have in
this tab of some larger state that is,
18:38you know, maybe primarily on a server.
18:41And that introduces a lot of complexity
because all of a sudden, you have
18:44your nice declarative spreadsheety
React thing, but then you have At
18:48some point in your stack, you're
gonna start hitting data fetching.
18:51You're gonna start hitting sending
rights back up to the server.
18:55And, that's just an enormous source
of mental model overhead, I think.
19:00On the flip side there have been some
interesting research projects which come
19:03out from the other side, And people,
for example, have literally tried to
19:06make UIs in things like Google Sheets.
19:09There's a really neat project by Ted
Benson and collaborators called Quiltstep.
19:13Literally, they use Google Sheets to power
your entire back end and all your your,
19:18you know, UI templating and essentially.
19:20And the problem there is normal
spreadsheets aren't really powerful
19:23enough to do that, and they're not
really architected the right way.
19:27one way to think about what we're
trying to do in Riffle is can you take
19:30the beautifully simple model of just
declarative dependency propagation, and
19:35apply that to your entire data stack.
19:38So your mental model as developer should
be, I just have all the data locally.
19:42I'm just writing a spreadsheet
that turns it into a UI, and the
19:47system will take care of the rest.
19:48Full stack reactivity.
19:50That's sort of principle number one.
19:52That makes that makes total sense.
19:54And I think you've Touched on also, like,
the the third principle, which I remember
19:58now is, like, the the unifying the UI
states and sort of the the other app data.
20:03And if you really think about it, where do
you even draw the line between something
20:07being UI state, something being app data?
20:10There is sort of like a arbitrary line.
20:12Maybe I think de facto in most today's
web apps is the app data is, like,
20:17what you fetch over something like
React Query as your as your website
20:22boots up or you have it pre hydrated.
20:25And the app state It's more of like
the in memory stuff that if you
20:29reload the pages, poof, it's gone.
20:32But, ideally, most of the things should
really be treated in a very similar
20:36way when I'm thinking of a native
Mac app, for example, like Finder.
20:41If I close a window and I come back,
The same items are still selected.
20:46I'm still, like, roughly in the the
same position with the the folders that
20:51I've selected and and the hierarchy.
20:53And most web apps, I would actually
suffer from that they they have, like
20:58basically, they're suffering from
dementia when you and insert something
21:02in a form, and maybe you really need to
look up every value and maybe the form
21:08expires, you reload, everything is gone.
21:10That's I think everyone has, like,
those terrible user experiences.
21:14And so treating everything as the
same data, I think is is a kind
21:19of a bold, but in my experience,
like, the the right step.
21:23And then if you can, Therefore, as a
conclusion, kind of, like, have all
21:28the data that you need to work with.
21:30Have that locally.
21:31It simplifies everything to such
a degree that's really liberating.
21:36So that that's sort of the the third the
principle, and I think that's that's a
21:40really bold one that is, I think the most
provocative compared to the traditional
21:45way of building web apps today.
21:48Yeah.
21:48Exactly.
21:48You know, just like you said I think it
can be a disrespectful user experience
21:52to lose people's valuable input.
21:55Even something like Scroll position
or, like you said, intermediate
21:59form state can be thing something
that I put a lot of work into and
22:03I don't wanna necessarily lose.
22:04Right?
22:05Now I think the deeper reason we
end up with software like this
22:10isn't that people don't care.
22:11It's really that we've made it hard to do.
22:14So, again, it's this technical
defaults ruling, the user experience
22:18situation that we talked about where,
You know, imagine you're a product
22:22manager and you get a request to
please persist to this user input or
22:26share this user input across users.
22:28And the engineer says, oh, man.
22:30That was previously React components
data, and now I need to, like, rearchitect
22:34where that data is stored and plummet
through a bunch of places and Add a
22:38database column for it, blah blah blah.
22:40It's all this work.
22:42And the goal of having a
unified system for your state.
22:44It's not that all states
should be treated the same.
22:47Definitely, some state, you know, should
be user local, device local, and so on.
22:51There, Yeah.
22:52Some state you want to reset
on new sessions by default.
22:56So you can think of that as ephemeral.
22:58But If you store it all in one system
and manage it all in one system,
23:02the goal is that it's becomes much
easier to move between, these states.
23:06Right?
23:07one example I love is that someone
who's working on a collaborative app
23:10told me the state of whether a context
menu is open in a spatial canvas app.
23:17They actually realized they needed
it to be shared because when I open a
23:21context menu, my cursor is moving around.
23:22If you can't see the context
you I'm using, you don't
23:25really know what I'm doing.
23:27And so, I think that's a perfect
example of blurring these boundaries
23:30where something that Seems like clearly
quote, unquote, local component state
23:35in a traditional framing might actually
need to be collaboratively synced
23:40or, you know, maybe even persisted.
23:42So that's what I see as the goal of having
this unified state management system.
23:47And in the Riffle work that's
basically the the maximalist
23:50view we took is no react state.
23:52Right?
23:53Every single bit of state in the system
flows through this one database, and your
23:58UI is just derived from that one place.
24:01And You can always reason about
essentially, the pixels on the screen
24:05are a function of the database.
24:07That's it.
24:07Nothing else.
24:08And we found a lot of neat qualities
that that design led to along with
24:13a bunch of interesting challenges.
24:15And and I have to say, I was I was not
on board with that when we got started.
24:20I was so attached to like, everything
is in React, and you have, like, things
24:26inside of React components, etcetera.
24:28And I remember Nicholas, he was, like,
on the on the opposite side there.
24:33And so, like, no.
24:34No.
24:34No.
24:34Like, React should do as little
as possible and, like, have your
24:37state outside, and that didn't
click quite back then for me.
24:42But step by step, I came around
to it, and I'm now also, like, on
24:46a maximalist side of, like, most
state should live outside of React.
24:50And for example, for Overtone,
there's a very simple case where
24:54you for example, for the app
for the playback of your player.
24:58Like, you want your playback
to happen to happen.
25:01You wanna hear something.
25:02Maybe you captured the the time code
of the the current playback progress.
25:07And even if the app is not open,
You wanna still hear things.
25:12If you reload the app you might
just still want to recover at the
25:16the correct playback position.
25:18So all of that state is kinda headless.
25:20So the state still lives on and,
therefore wouldn't quite make sense to
25:25have that be part of React, you say.
25:27Sure.
25:27You could say you have, like, a headless
React component, but that's already
25:32feels a bit backwards at that point.
25:34So Once I've started embracing that,
it was hugely liberating, and now I can
25:40start to reason about my state outside
of the context of React components in
25:46that outside of reactive view state.
25:49So That took me a bit to get
around to it, but I'm fully on board
25:53with that principle now as well.
25:55you know, I'll I'll mention, I
don't think we're the we're not
25:57the only ones who've of this right.
25:58I think um, the idea of having a
reactive state graph separate from
26:02your UI tree is something that other
web dev libraries have explored.
26:07MobX, Recoil, arguably, even something
like Redux, I think shows some of the
26:11power of having this sort of centralized,
outside of your UI tree state management.
26:16So, there's definitely, I think
some broad recognition that this
26:21can be a powerful pattern for for
some of the reasons you mentioned.
26:25You know, but I'll also mention,
like, there are some challenges.
26:27Right?
26:27And, I mean, You've
encountered some of these.
26:29I'd be curious to hear your take.
26:30Some of them that I think immediately
come to mind for people are, one,
26:35Performance is always an easy one.
26:37Like, typically, we expect button
hovers and, you know, selection
26:42changes to happen at 60 120 Hertz.
26:45And we don't expect things like
loading thousands of rows of
26:50data from our core data store to
necessarily happen at the same speed.
26:54And so that mismatch can be an an
an interesting thing to Manage.
27:00Our motto Nicholas's motto to some
extent is just make everything fast.
27:03If everything goes at 120 FPS,
then don't have a problem.
27:06Right?
27:07Easier said than done, but I
think a fun goal to shoot for.
27:11So far, most mostly what
we've been talking about is
27:13conceptually a simplification.
27:16Getting on board with that
different way of thinking about
27:19your your app on a conceptual basis.
27:21And I think for me, it took a little
bit of time to ease into that,
27:26and then, be confronted with the
new challenges that are raising.
27:29We we'll we'll go into the
challenges in a second since
27:32We've encountered quite a few.
27:34But I think we didn't quite touch too
much on the the second principle you've
27:38motivated before, which is, uh, the
synchronous reactivity, and, like,
27:43that should be as fast as possible.
27:45We'll we'll go into the performance
challenges there in a bit.
27:48But when you've said synchronous
reactivity as opposed to
27:54asynchronous reactivity, what what
are the why is this a principle.
27:58Like, what is so important?
27:59Can can you motivate the the
problem and the status quo and
28:02how Riffle is challenging that?
28:04. Yeah.
28:05Absolutely.
28:05This is a really
important principle to me.
28:08I think when we Build web
apps that have a server.
28:11We assume a lot of
asynchrony at many points.
28:15So, obviously, going on the network
to a server is a point of asynchrony.
28:19Even often loading data from
you know, like a local disk.
28:23Right?
28:23We think of as an asynchronous operation.
28:25And because of that, UI development
typically has a lot of reasoning
28:30about asynchrony, which is a really
hard thing to do as a programmer.
28:34For example, you might have a UI
where There are loading states.
28:38And everywhere throughout your app,
you need to think about, am I still
28:42loading, or do I have the data?
28:43And maybe you have a UI that's composed
of different sections, and some of them
28:47might be loaded already and others aren't.
28:49You might have intermediate
states to reason about.
28:51Like, After I select something
in a sidebar, there's some time
28:55where the main other pane of the
app hasn't reacted to that yet.
28:59So It might still be showing the old
thing that was there before I selected
29:02the new thing, or it might be showing a
loading state while I'm loading the data.
29:06And my experience at least personally
has been that We kind of accept
29:10this as just the way it is in UI
development, but it's terrible.
29:13It's it's a lot of
overhead to reason about.
29:16There are many, many more states your
system can be in when you have asynchrony.
29:21Right?
29:21And the the vision for synchronous
reactivity is let's make it again
29:25feel more like a spreadsheet.
29:26So the way I want my UI to feel is
that when I select something, on the
29:31next tick, on the next frame, every
pixel in the UI has fully updated
29:35to reflect that new user input.
29:38And that's obviously good for users
because they didn't have to wait
29:42But it's also good for developers
because you don't have to reason
29:43about the intermediate states.
29:46You can sort of think transactionally
where The state of the world changes,
29:50and, transactionally, we update a bunch
of derived views and queries of that state
29:56which end up in the pixels of the UI.
29:58And there was never any
intermediate state exposed.
30:01And it's It's sort of a subtle point to
get across, but my experience has been
30:06that when you work in a system like
this it just Cuts a lot of complexity.
30:11Yeah.
30:11It's not just a simplification in
terms of architecture that we collapse
30:16the stack from back end and API,
etcetera, and all into the client.
30:21But that's, like, one giant
dimension of complexity.
30:26But there is a second, much less
talked about vector of complexity,
30:31which is like, how is how are
things related to each other?
30:34Can they be synchronously
related or can or do they have
30:38to be asynchronously related?
30:41And this is where I think we're getting
into the area of distributed systems.
30:45I'm sure we'll talk a lot more in future
episodes about broader distributed
30:50systems where they're really needed,
where you have You're you have a device.
30:54You're in the US.
30:55I'm in Europe, and so we are distributed.
30:57However, if we are starting to
treat a local React app that's
31:01running in single thread And we're
coordinating the various React use
31:06states things with React useEffect.
31:08We've kinda accidentally created a
distributed system that's It's really hard
31:13to tame and where it is, there can be many
unintended bugs and just starts becoming
31:19a lot more complex to to think about.
31:22So this is the other part where I
think it really it con where Riffle,
31:27again, liberates so much and simplifies
and frees us of the the accidental
31:33distributed systems problem that
we have in most modern web apps.
31:37I, you know, I, think to 2 principles
that I think about one is don't
31:43make something a distributed system
if it really doesn't have to be.
31:47And 2 is if it has to be,
someone smarter than me should
31:51do the distributed systems part.
31:53Right.
31:53Really, we should be providing
abstractions that allow us to not think
31:58about the hard parts most of the time.
32:01Even, you know, I'm not a CRDT expert,
but I know quite a bit about CRDTs and
32:05have done some work on developing CRDTs.
32:07But and so I, you know, I Probably
know more about CRTs than a lot of
32:11app devs, but I don't wanna think
about distributed systems when
32:15I'm building some product feature.
32:17Right?
32:17And I think That is clearly one of the
core challenges in the local-first space
32:21that I think a number of projects and
companies are trying to address, which
32:25is what are the Good abstractions you
can expose to app developers that allow
32:29them to reason about tricky distributed
systems problems in a in a straightforward
32:36way without needing to turn on your sort
of distributed systems brain as much.
32:42Yeah.
32:42Exactly.
32:42And I I think the Being confronted with
distributed systems problems there is
32:48much more common than most app devs think.
32:52So most of the time when in React, you use
useEffect that that hook to, yeah, somehow
32:59tame your local state, Then you already
have a distributed systems problem.
33:04Things like React suspense and and so on.
33:07That that's kind of like a a solution
to address partially the the distributed
33:12systems nature that you have in React.
33:14So, I remember having when React suspense,
and all of those primitives came out.
33:19I was kinda wondering, how does
that fit into our Riffle world here?
33:24would Riffle at some point support
react suspense, and then at
33:28some point, it clicked for me.
33:30No.
33:30That's, like, addressing a problem
that we've already ruled out
33:34before, and we don't even have to
think about that complexity at all.
33:39And yeah, this is, like, entirely
different approach to addressing
33:44the problems that React, Suspense,
etcetera, is addressing in a, I would
33:49say, in a much simpler overall picture.
33:52Yeah.
33:52I think maybe to avoid overclaiming
here, I'll say there are some trade offs.
33:57Right?
33:57I think Often, these approaches that
involve concurrency are they're optimizing
34:02for either the reality of something
like a slow network request or for
34:05sort of worst case performance making
sure that you keep some things running
34:09fast even if other things are slow.
34:11And I think there's a different approach
you can think about, which is, In a
34:15nutshell, just make everything fast.
34:17And as long as everything's
fast, it'll be simple.
34:19If things get slow, you might end
up with a worse experience than you
34:22might have in a system that, you know
that is designed around concurrency.
34:26For example, maybe in a in a Riffle
style approach, if you're trying to
34:31synchronously paint frames and something
is slow, you might just end up with a ton
34:35of dropped frames and sort of a frozen UI.
34:38Whereas in a system designed to account
for that with better concurrency support,
34:42you might have, you know, a loading
spinner and some things remain responsive.
34:46And so I think Part of the
challenge is figuring out how to
34:49how to balance those 2 approaches.
34:52And as we've seen in our work, I think
sometimes you do need to account for
34:56the reality of sometimes you have to
make a network request because, you
34:59know, you're talking to an external
service or something, and you do
35:02need ways to model concurrency.
35:03It's just that I think We don't
need to, I guess, throw the
35:07baby out with the bathwater.
35:08Like, not everything needs to be
concurrent, and some things can be fast.
35:12I think I don't have much game dev
experience, but I my understanding is
35:15that a lot of video games, essentially,
you know, they paint frames, and
35:19they make sure every frame is fast.
35:20And they don't drop frames because
they make sure the frames are fast.
35:23Right?