
Replicache: Easy Offline-First for Existing Applications - aboodman
https://replicache.dev/
======
dstaley
For something that's open-source, production ready thanks to the lovely folks
at Mozilla, and ready to host on your own infrastructure check out Kinto[1].
Replicache and Kinto have overlapping feature sets, but my guess is that
Replicache is probably a bit more optimized (especially if the delta updates
are truly as small as possible). That being said, of all the problems I've run
into implementing sync for my applications with Kinto, the size of update
requests hasn't been one of them. Also while Kinto can support live
subscriptions, the only plugin implementing them currently relies on a third-
party.

The biggest difference I see between them is that Replicache sits in front of
your server, whereas Kinto _is_ your server.

Disclosure: I'm a contributor to Kinto, primarily working on transitioning the
JavaScript libraries to TypeScript.

[1] [https://docs.kinto-storage.org/en/latest/](https://docs.kinto-
storage.org/en/latest/)

~~~
aboodman
I'm sorry to say that I didn't know about Kinto. Thanks for the link!

Kinto seems, is in some ways, the opposite design approach to Replicache.
Replicache answers the question: I have this existing web service with a whole
complex backend stack, how do I make it work offline-first?

Kinto answers the question: I have this website, and I don't _want_ a backend
stack. Where can I store data and have it work offline-first?

I think the problem Kinto is solving is also important, thanks for sharing it.

------
aboodman
Hi Hacker News!

I'm starting a new company attempting to solve the offline-first / mobile-sync
problem once and for all.

Replicache makes your mobile, web, or desktop application blazingly
responsive, by buffering all reads and writes to a local cache (aka "offline-
first").

This is something I've been thinking about on and off for over fifteen years,
on major projects at Google as well as my previous vc-backed startup. I
previously thought there was no satisfying general solution, but happy to say
I think I was wrong: Replicache is pretty dang easy, and it works with any
existing stack.

We're looking for groups to partner with would like early access. If that
sounds interesting, please reach out!

\- Aaron

~~~
Semaphor
Sorry, no technical comments but a UI one: Please change the font/style.
Depending on monitor color settings, the paragraph text in Retina Thin is
really hard to read, but even on my other monitor it’s still a problem with
the letter "s" [0]. I think it’s a problem with the thinness and white on dark
background. It was hurting my eyes and permanently distracting me while trying
to read the copy.

[0]: [https://i.imgur.com/Ia0roKn.png](https://i.imgur.com/Ia0roKn.png)

~~~
aboodman
Thank you for this feedback, I'll ask our designer for his advice. Perhaps we
can detect high density monitors and only do Retina in that case or something.

------
lootsauce
This looks really interesting. I have been digging deep into sync for the past
few months and am very interested in how this works. I am currently trying to
understand automerge and delta patching trying to implement from scratch. I
have looked at Gun and couch db + pouch db but both did not feel like the
right answer.

~~~
aboodman
Be aware that CRDTs like automerge are solving a different (and harder)
problem than Replicache. They are trying to implement convergence in an
asynchronous system where there is _no central authority_. See the excellent
article [https://www.inkandswitch.com/local-
first.html](https://www.inkandswitch.com/local-first.html) for more on this
type of application.

Most classic web services don't have this requirement because they do in fact
have a central authority -- the service itself.

Moreover, for web services, it is _crucial_ that the central authority
actually be authoritative. You don't want client and server state kind of gets
smooshed together arbitrarily, but for the client's view of the state to be a
mere suggestion - one which the server _always_ overrides.

So my view is that CRDTs are not really an appropriate basis for building this
kind of feature in a web service.

However I think the tech is awesome (Replicache actually started out as a true
CRDT and moved to its current design after extensive iteration with
customers).

See [https://www.figma.com/blog/how-figmas-multiplayer-
technology...](https://www.figma.com/blog/how-figmas-multiplayer-technology-
works/) for how Figmas came to same conclusion wrt CRDTs for their service.

\--

(P|C)ouchDB:

\- Using couch as your backend db ends up being a nonstarter for most
applications. A distributed multitenant database is a big big thing and a
hugely important technical decision. Most orgs are not going to go with couch
just to get sync. See [https://medium.com/wandering-cto/mobile-syncing-with-
couchba...](https://medium.com/wandering-cto/mobile-syncing-with-
couchbase-6f076d8c7e08#deca) for an example of this.

\- The couchdb replication protocol offers no help with conflict resolution.
It just tells you there was a conflict and gives you two conflicting
documents. This isn't practical for most applications.

~~~
daleharvey
PouchDB author here, your project looks great good job.

I certainly agree that switching backends to CouchDB has made it hard for
people to adopt Pouch/Couch. I have often considered how I could make Pouch
work with arbitrary data sources, but as you well know its a tricky problem.

However I dont understand from your website or comment here about how conflict
resolution is easier? Given the situation of having 2 clients recieving an
initial data of {key: value}, the clients go offline, 1 client writes {key:
foo} and the other writes {key: bar}, the clients then both reconnect. What is
the new state?

~~~
aboodman
Hi Dale,

Thank you for the comment. I think there is a technical difference and an
ergonomic difference:

1\. The technical difference is that when you do conflict resolution with
Replicache you have more information, specifically the intent of the
mutations. Consider something very simple like a positive-only counter. The
parent is `1` and the forks are `2` and `0`. Is the correct resolution `2`? Is
it `0`? Or is it `1`? There's no way to know because we don't know what the
intent of those changes was. Was fork 1 incrementing? Was it multiplying? Was
fork 2 decrementing? By how much? Now multiply this simple example by real
applications with many developers, many features, and many client versions in
the wild. Having the intent of each change travel with the change is crucial.

2\. The ergonomic difference is that conflict resolution in Replicache isn't
something separate that is done after-the-fact. Replicache applies mutations
to the server by calling normal HTTP APIs, just with potentially old
arguments. This forces developers to consider conflict resolution at the point
they are writing APIs, and keeps conflict resolution code colocated with the
corresponding services.

~~~
sizediterable
> This forces developers to consider conflict resolution at the point they are
> writing APIs

Would an example of what you have in mind be writing an atomic "/increment"
endpoint instead of a "/set?value=possiblyOldValue+1" endpoint? (using GET
notation instead of POST just to make illustration easier)

~~~
aboodman
Yep.

~~~
zffr
From what I can tell from the website, replicache retries HTTP requests
periodically until they succeed. With an non-idempotent request like
`/increment` how does replicache know when to stop retrying?

if request succeed, but the response fails, could replicache increment twice?

~~~
aboodman
The APIs Replicache calls at customer service must be idempotent. Replicache
passes a version vector to the customer that customer uses to ensure this, and
to enforce causal consistency.

Customers must make several relatively small changes to their backends to
support Replicache, including this one.

------
sizediterable
I'm curious how well Replicache composes together with web state management
libraries such as Redux and Apollo GraphQL. My closest experience with
something like Replicache's offline view is optimistic responses in
GraphQL[1]. Maybe some more web-specific examples can be added to the site?

[1]
[https://www.apollographql.com/docs/react/performance/optimis...](https://www.apollographql.com/docs/react/performance/optimistic-
ui/)

~~~
aboodman
Apollo's optimistic responses are similar Replicache's local writes. The
difference is that Replicache's offline writes automatically refresh every
affected subscription and ensures the entire UI is consistent with the latest
changes. You don't need to manually modify affected queries:
[https://www.apollographql.com/docs/react/performance/optimis...](https://www.apollographql.com/docs/react/performance/optimistic-
ui/#adding-to-a-list).

How Replicache composes with Apollo needs more thought. Off the top of my
head, I think that Replicache replaces the need for Apollo's unified cache,
but not with many of its other features. For example, it's easy to imagine
Replicache being one of several data sources backing Apollo. In fact we have a
customer who has done something like that already, and it's quite nice because
the consuming code doesn't even need to know whether a GraphQL query is coming
from offline data or the server. That can even change over the life of the
product as more features in an application become offline-enabled.

~~~
sizediterable
Thanks for a thorough explanation!

