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