33:41Yeah.
33:42So the meta comment there is that like,
after you think about it for a really
33:46long time, a lot of these approaches
end up actually being the same, but it
33:50really matters, I think, in terms of
contrasting different frameworks and
33:54solutions and introducing people to
the idea in the first place, from which
33:59angle you approach it and like the.
34:01It's like a replicated local database
that's relational is a very obvious one.
34:06And there's a lot of people
doing that really well now.
34:08the document one is an obvious one.
34:11I think you'll be able to
predict what, what my issue with
34:14it is that it like makes you.
34:16Put the boundaries, but
I'm basically doing that.
34:18I'm doing what AutoMerge is doing.
34:20It looks like state, and I'll say
that a bit more precisely in a second,
34:24but again, it's a bit more granular.
34:26And the way I describe it typically,
like the audience that I have in mind
34:31is actually not full stack developers
or backend developers who are very
34:35familiar with relational databases,
but in my case, frontend developers who
34:41are familiar with Local UI state on the
one hand and kind of making requests
34:45to APIs as like the only external
system they ever need to worry about.
34:49So the story I tell this Imagine
Frontend developer is that imagine
34:55if you could kind of mock up an app
just based on local, like React use
35:01state or like equivalent things,
and you build your UI around that.
35:06but then magically your app actually works
and like all of the status persistent
35:12and you can share it with other users
and, you have permissions on there and
35:18you still only wrote front end code.
35:21That's kind of the Jazz story and that's
what the API looks and feels like.
35:25So if, if you build an app with Jazz,
typically the first thing you do is.
35:30You actually do something kind of database
y, which is that you define a schema
35:33just to describe kind of what is the
shape of data, which kinds of objects
35:38are the main abstractions in my app.
35:40interestingly, you don't have to model
users at all because that's just baked in.
35:44So it's very nicely like, what
are just the concepts that are
35:48specific to your domain that
you're, addressing with your app.
35:52And once you have the schema, you can
just start having state of objects in
35:58that schema and build UI around it.
36:00And you can create objects of different
types out of your schema locally, and you
36:04can create like, groups, which is kind
of like the permission structure in Jazz
36:08and put objects in groups and then like
give users access rights to groups, all
36:15like you can do these things literally
in an on click handler of a button.
36:19And it feels kind of illegal because
of how simple it is, but that's it.
36:23That's how you build apps with Jazz and
you can get very far with just that.
36:28As apps get more
complicated, you can kind of.
36:31abstract things all kind of similarly
to how there are solutions for not
36:35letting UI state get too complex.
36:38and the other thing you might need to
start, if you want to talk to external
36:41systems like third party APIs, you
can build the server workers that I
36:46talked about a couple of times now.
36:48But the nice thing is you can build.
36:49If you also write them in
TypeScript, for example, you just
36:51share the same data schema that
you're using for the front end.
36:55And it really just feels like
one, one small addition to your
36:59otherwise purely front end code.
37:01That's, that's kind of the
Jazz experience, right?
37:04That makes a lot of sense.
37:05And I've just in parallel.
37:07going through the Jazz landing
page here, where you have, this
37:11really cool chat app and 174 lines
of code embedded here as well.
37:16We can just see exactly that,
like a little schema definition
37:20of this case for this chat app.
37:21There's just like a message.
37:23Class, a message concept
and a chat concept.
37:27and that's it.
37:27You can use it right away in your React
code, in your other code, and fire away.
37:33and you've also have here the user
concept where you see like, okay,
37:38something is owned by me and then the
chat, for example, is owned by a group.
37:44what if I want to go a little bit
more specific here and enforce
37:48certain Permission rules, that
are more specific to my app.
37:54what is the story in progression there?
37:57So the way that that works is that it
doesn't get more complicated than groups
38:03and objects belonging to the group.
38:04So like whenever you create an
object in Jazz and like, I should say
38:08the name for them, we call them co
values, like collaborative values.
38:12You have like co maps
that are kind of like.
38:14JavaScript objects, co lists that are
like collaborative arrays, basically.
38:19and just like you can represent a lot of
different kinds of data with JSON, you
38:24can represent a lot of different kinds of
collaborative data with co values, right?
38:29And each co value has
to belong to a group.
38:32The group is like the scope for
permissions, and it simply has user
38:36accounts in it with a certain role.
38:39The three roles that exist
are Reader, Writer, or Admin.
38:43They do exactly what it says on the tin.
38:45and they then influence what
people can do on co values.
38:49We can talk in detail later how
that works under the hood, because
38:52I think that's interesting as well.
38:53But for now, that's all you need to know.
38:55And that maps quite naturally on onto a
lot of stuff that you want to do in apps.
39:00But then the question is what
about more complicated situations?
39:03And the answer there
again is the granularity.
39:06Because if you wanted to every, each
co value, like imagine like a kind
39:12of tree of co values representing the
state of a more complicated document
39:17or even like a folder of documents.
39:19The way that looks like in Jazz
is that they're actually each
39:22individual CRDTs that just have
plain data as values in their fields.
39:28Or they can have references
to other co values.
39:30And that's how you build this, like,
potentially infinitely big graph,
39:33and you, like, load whatever you
need to, like, display right now,
39:36or what you want to have offline.
39:37But the nice thing is that the
groups that these co values belong
39:41to, and the permission structures,
therefore, are kind of orthogonal
39:44to the, like, data references.
39:46So you can reference a co value, That
belongs to a different group that
39:50has different members or where the
same members have different roles.
39:53And that way you can build permission
structures that are just as granular.
39:57And you can even have like something like
a notion document where like a small block
40:03might only be editable by some people.
40:05does that make sense?
40:07totally.
40:07you, you've been mentioning the reference
concept that is giving you the kind of
40:13like a relation for a key kind of concept
between different kinds of documents,
40:19and I think this is also describing the.
40:22the boundary between one thing that
needs to be synced and then another
40:27thing that needs to be synced.
40:29And if you model a thing like
a network with that, how does,
40:34Jazz, how does it know where to,
uh, how much it needs to sync?
40:39Where does it need to stop?
40:41Is there, so one analogy, for example, in
GraphQL . maybe not everyone is familiar
40:46with that, but it's like a query language
that is language agnostic and can be
40:51implemented with any sort of backend.
40:53And this is where you can also define
a schema kind of similar to this here.
40:58and aside from the schema, describes
the potential graph of queries, or
41:04set of queries in a specific query.
41:08you need to very explicitly say, those
are the things that I want to query.
41:12So let's say we model a file system from
this, where we have folders and files
41:18and folders can have folders and folders
can have folders in a GraphQL query.
41:23You need to say, actually, I want
to, you need to explicitly lay out.
41:27I want to go like all the
way to like level three.
41:30So you need to say, I want to grab
the folders and in that folders, I'm
41:34going to grab again, the folders.
41:36And I want to, there again, grab
the folders, but you can't self
41:39recursively, infinitely, traverse.
41:43Is there a similar kind of explicit
depth to how jazz should sync something.
41:50Is that determined at runtime by
a React component, for example, is
41:56there some sort of middle ground?
41:58How does that work?
41:59So there are kind of, and it's a really
good question because like, that's kind
42:03of, you need a system that solves that.
42:06If you don't have the explicit
boundary of like, this is, we can
42:10either sync all of that or nothing.
42:11Right.
42:12And the file system is a
good example because it's.
42:14It's kind of potentially infinitely deep,
but you're probably only ever looking
42:17at a subset, so how do you do that?
42:19And the way, the quick and dirty way
you do it in Jazz, which is actually
42:24really fun to just, again, super quickly
build your eyes that work, is that,
42:29Jazz tries really hard to make covalues
look like just plain JSON objects.
42:35And if you have co values with references
to each other, they look like JSON trees.
42:40So what do you do then if
like at some point you might
42:43not have a co value loaded?
42:44Well, then it just says that it's
in a TypeScript sense that field is
42:48either the reference thing or null.
42:51And,, if you try and render a
specific tree in a React component,
42:55you can basically just use optional
chaining to like render like this far.
43:00And if it's not loaded, show like
a little spinner or something.
43:03But the funny thing then is that Jazz
notices what you are trying to access.
43:09And it's like, Oh, you're trying
to render like three levels deep.
43:12And you try to access this thing that
we don't have yet in the background
43:16triggers a sync of the needed co value.
43:19And once that's available locally,
it re renders your component.
43:22And now that's not null anymore,
but you actually have the JSON state
43:26for that co value and you render it.
43:28So very naturally by like building
your UI and just deciding to render.
43:34What do you want to render it will
lazily load exactly what's needed.
43:38And you can even manually do
pagination like that by just having
43:41a little stateful, like, oh, I want
to render 10 items and then you only
43:45drill down into the first 10 items.
43:47And then like you hit a button or you
reach the end of a scroll list or like.
43:51Elements become visible on the
screen and you just ask Jazz to
43:54access more of them, even if they're
right now, not, not available.
43:58And in the background, it will load more.
44:00That's the quick and dirty way.
44:01Super nice for prototyping stuff.
44:03It's a bit weird in terms of user
experience, because you end up with a lot
44:08of spinners and they like, they resolve
really quickly because Jazz is fast,
44:12but it still looks unfamiliar to people.
44:15So if you want to give people a more
polished experience of maybe one Loading
44:21thing until a bunch of status available.
44:24That makes sense as a unit.
44:26There is a way of specifically
specifying a loading depth and that's.
44:32That kind of looks like GraphQL lite,
but because you only need to specify
44:38fields that are references, you don't
need to say which plain data fields
44:41you need because they're always loaded.
44:43yeah, you, you, it's, it's
actually very similar to Prisma.
44:46You just say which references you
want resolved and then the Jazz hooks.
44:51Won't give you anything until
all of that is loaded and then
44:54they give it to you as a chunk.
44:56That makes a lot of sense.
44:57So you're basically just specifying
sort of the graph of the references,
45:02not the individual fields of a document,
since you typically want a document
45:06as a whole, that makes a lot of sense.
45:08And that's also, as I'm thinking through
how I would model something for Overtone.
45:13when I have a music app and I want
to listen to music, if I'm currently
45:17ermbarking on a train journey or
on a like traveling somewhere where
45:22I don't have perfect connectivity.
45:25I want to like that lazy loading just
in time as I like click on a playlist.
45:32if I don't have connectivity, then
at that point, it kind of breaks a
45:36bit of like that local-first promise.
45:38but I also understand like,
let's say, Spotify is thinking
45:42about building it in that way.
45:44Spotify can't just sync the entire catalog
of like all of Spotify on a single device.
45:50So there needs to be
like some cutoff point.
45:53And I think while prototyping doing the
just in time lazy loading, that's great.
45:58But then as an app developer, in
this case, for example, me building
46:02Overtone, as I better know, okay.
46:04I want you to find some rules of
like, that stuff should always
46:08be there, like prepared for me
going on a, on a train journey.
46:12And that would probably in this case be.
46:14For all of my playlists, make sure
like all of like the tracks for the
46:18individual playlists are at least
the metadata is there and possibly
46:22then have like also some rules
for pre downloading some tracks.
46:25If I have the rights to do so.
46:28that makes a lot of sense.
46:29And that seems like Jazz provides a really
nice trade off of making, providing a
46:35easy way right away to prototype and
then, dial it in to match the user
46:41experience that you want to provide.
46:43And I guess I met the comment here
with like, because you actually just
46:46now asked a very precise, interesting
question, which is like, well, what
46:50if you ask it to load a chunk of data
and not give it to you until all of
46:54it is there, but then your connection
drops, what should actually happen?
46:59And like nothing being
loaded, then it's actually a.
47:02Like you said, an outcome that
violates local-first a bit.
47:04So there, then we need to be more
refined and be like, well, maybe show
47:09a spinner for everything for like two
seconds and then give up and just show
47:13me everything that was actually loaded.
47:15and what we're getting to there is
that I think like, look, I think
47:19it's starting to become clear how
local-first in general is this cool
47:25new way of building app and how Jazz in
particular things really deeply, how to
47:29make that easy for you as a developer.
47:31But most of the challenges with
local-first and with multiplayer, by the
47:35way, I think are UX challenges where we're
like, well, what, what should happen?
47:40And that's something that we
figure out as we try to build
47:43and dog food, our own apps.
47:45As we see what, our first adopters
build with it and what makes sense
47:51to their particular developers and
how you want to expose all of these
47:54different, like, is it loading?
47:55Is it locally available?
47:57Is it locally available?
47:58But it's like, not quite up to date with
what we know the syncing server has, but
48:03we didn't have a chance to get that yet.
48:05And there's like so much
complexity in there.
48:07And in different situations, you need
to expose like more or less of that.
48:11So I think beyond just like.
48:14Making the sync and making the data
persistence and making the permissions
48:18work, which like we're pretty good
with now, there'll be a lot of like
48:22API design and also like educating
developers and just figuring out UX
48:27together, like as a field, I think.
48:30I definitely agree.
48:31And like just the scenarios that
we've now went through over the
48:34last couple of minutes, I think
already go surprisingly deep.
48:38For example, like the partial, like if you
want to load everything and then you say,
48:42okay, I don't have everything, in some
cases, it's fine to show a partial set.
48:47In some other cases, it might be like
really nerve wracking for a user where if
48:53you don't signal like, Hey, we've just,
we, we can't say this is everything.
48:57We've just fetched so much since
otherwise a user might assume, Oh my gosh.
49:00Like this app has like
lost some of my data.
49:03and so this might, in some cases
might be better to not show anything
49:07and like explicitly let the user
know, like, Hey, we're sorry.
49:12when you come online again, we'll do
our best to get everything in here.
49:15sometimes you also like from the data
you fetch, maybe you want to like,
49:19let's say you, you shouldn't build a
bank account this way, but let's say
49:22you build a bank account and you've
just fetched a bit of like your,
49:26your like transactional history.
49:28And it misses your latest, like,
big check that you cashed in.
49:35Basically you added money to your
bank account and it's not in there.
49:38And you think, Oh my gosh, like my bank
account is like lost all of that money.
49:42Obviously you won't build an app like
that, but I think the analogy kind of
49:47like translates where you derive data
from other data and where it could be
49:52like really bad, you missed something.
49:53So this is really interesting to dig
into the user experience aspects.
49:58And that might also make for a really
interesting future conversation,
50:02but I want to, Dig a little bit more
into, into another related topic,
50:07which is the localfirst.fm podcast.
50:10And what brings all of us together
is that we think we can do better
50:14how we build apps, at least in many
app use cases, and Jazz shows for
50:18how many app use cases that applies.
50:21And so that means We, as a whole,
as an ecosystem, we need to convince
50:26the people who are not yet in
that small but growing ecosystem.
50:30We need to convince them that we
have a very interesting way how to
50:34build apps better, that are simpler
to build, better for end users, etc.
50:39And I think each technology has their
own specific, benefits, how that's, is
50:45a, is a good fit for, for certain app
use cases and particular developer types.
50:50Like you want to target more
like the front end developers.
50:53what is your approach to
talking to developers?
50:57How do you want to market Jazz to
reach the right people and sort of the,