Hacker Newsnew | past | comments | ask | show | jobs | submit | aboodman's commentslogin

Yeah, it's a big part of the tradeoff for this kind of architecture. In Zero, this is a first-class concern via the ConnectionStatus API:

https://zero.rocicorp.dev/docs/connection

Errors and connection are handled in a centralized place so that they automatically get applied to all paths.

Errors immediately disconnect the app and trigger UI. Writes are no longer accepted. After 1 minute of of failed connection attempts, same happens.

This formalizes and enforces the common pattern in popular sync-based apps of detecting disconnects fairly aggressively and warning the user.


If you're interested in this kind of experience for your application, check out Zero (https://zero.rocicorp.dev/).

Live demo: https://gigabugs.rocicorp.dev/.

We also list some alternatives here: https://zero.rocicorp.dev/docs/when-to-use#alternatives.

If you're interested in how these things work internally, check out the Replicache design doc: https://doc.replicache.dev/concepts/how-it-works. Replicache was the predecessor to Zero and the core protocol still works the same way.


this is not local/offline first and also seems massively over-engineered for the type of apps that might use it since now you can't use plain sql and need to learn your ZQL domain specific language/library. I mean look at this code from raw sql example:

```

const markAllAsRead = defineMutator( z.object({ userId: z.string() }), async ({tx, args: {userId}}) => { // shared stuff ...

    if (tx.location === 'server') {
      // `tx` is now narrowed to `ServerTransaction`.
      // Do special server-only stuff with raw SQL.
      await tx.dbTransaction.query(
        `
      UPDATE notification
      SET read = true
      WHERE user_id = $1
    `,
        [userId]
      )
    }
  }
)

```


yeah we specifically decided not to be local/offline-first because these add huge complexity that is not needed for the type of apps we want to support. I spoke about this a bit here if you are interested: https://www.youtube.com/watch?v=86NmEerklTs&t=1764s

As for ZQL:

a) basically all of our customers already use Drizzle/Prisma. So they are very used to custom DSLs, and like them. I know, I was surprised to!

b) You typically use the same code client-side and server-side. There's no branching. The example you pasted is showing an escape hatch for when you want to use custom SQL. The option is there, but it's not the common experience.

This is what a typical mutator looks like:

  ```ts
  // src/mutators.ts
  import {defineMutators, defineMutator} from '@rocicorp/zero'
  import {z} from 'zod'

  export const mutators = defineMutators({
    updateIssue: defineMutator(
      z.object({
        id: z.string(),
        title: z.string()
      }),
      async ({tx, args: {id, title}}) => {
        if (title.length > 100) {
          throw new Error(`Title is too long`)
        }
        await tx.mutate.issue.update({
          id,
          title
        })
      }
    )
  })
```

We are trying to make apps like Notion, Linear, Superhuman easier to create. These apps all uses custom-built sync engines that took their teams many person-years of effort to construct.

Whether this complexity is worth it depends on how badly you want instantaneous response. If you do, you will end up using sync one way or other, and you will end up with something roughly like Zero mutators.


Most of the improvement opportunity is in the offline-first the cache or fast reads already have lots of solutions by using zero I lock my self in thinking in your library's design language and not in terms of what I already know that is raw SQL. If your happy/convenient/recommended path is ZQL then of course people will choose it and only later realize it only works for simpler queries like most ORMs I've been burnt by prisma before and now I don't touch any ORMs and simply use raw sql + sqlc (type safety + auto repo layer from your query.sql)

I would use these DSL if they provide 10x improvement but it seems to me like a downgrade in every way I will need to rely on you to keep this thing running 10 years down the road and hope you are still in business. Whereas raw SQL will probably work as is since past performance is usually indicator of future and sqlite/postgres are 25 years old and if I recall correctly you already had this similar project that is now no longer maintained: https://replicache.dev/ so this by default makes me trust this project less since it will touch critical parts of my app.

Also, imo the custom sync engine path is usually better because most of this turns into logical replication unless you are syncing simple notes and then teams already know what they need and a last-write-wins + row_id,table => changes_log tables isn't that hard the issue is usually that the client and server will need to duplicate functionality and I will be a lot more comfortable duplicating those using raw sql queries since you write those ones and use on both sides. Any half-sync or other optimizations usually just end up causing a lot of headaches in a relational db with foreign keys on.

So, I would use something like this only if it is a sidecar process like litestream seamlessly doing it's thing vs becoming a main concern in my app core. But that again is the issue logical replication vs physical replication and how can a sidecar know the intent.


We do support Replicache: https://i.imgur.com/R1pR58i.png.

But I get it. Unfortunately something like this cannot be a sidecar, or at least I do not know how to make it one. It's central to your app in the way that React is.

Fortunately the category is expanding and there are several sync engines that plug in exactly how Zero does - by replicating your database. You can switch between them easily. So as long as you think you do need a sync engine you aren't that married to Zero specifically.

Here's a demo of that!

https://youtu.be/SNAHZZo21To?si=wgDgxQpbRr-qj-A-&t=1571


Which is exactly why I said this problem is better solved by your own custom sync engine which when scoped to your own problem is not as hard to build as you think the most simpler and effective version is just a change_log and replaying or occasional full sync.

My own app uses something like this and I have yet to encounter any issue whereas I did initially look into using electricsql , zero sync , instantdb , triplit but the amount of lock-in or DSL was not my cup of tea and most of these are now doing "AI Agents" marketing instead of their core original problem which further erodes any trust.


Did you look at PowerSync? It's "just" SQLite on the client. Wound be curious to hear what you think of it in the context of your lock in concerns

Can't recommend Zero enough. It's a really thoughtful piece of software with great abstractions. As well as the obvious performance benefits arising from having data synced and available in the client, I've been blown away by how much it simplifies React code. With a sync engine in place, most client-side state seems to evaporate, you get to think synchronously in most component code, etc.

We've been using Zero for a while now. Originally we were looking to build a Linear sync engine in-house and came across Zero. Probably the closest thing you can get without staffing a team dedicated on this.

user as well; this is exactly the tool if you want a UX where the UI instantly update itself once database changes within milliseconds.

Well that "make a mutation client-side" phrase is doing a lot of work.

Make a mutation to what?

The classic server rendered web-app doesn't have any data to make a mutation to. You could try to patch the UI but that would be a huge pita and not really a scalable (in effort) solution.

If you have an SPA, you still don't really have data on the client-side. You have a bunch of cached query responses. You can update those, but (a) it will be a pita to do correctly, (b) you'll have to do it to every possibly affected query, and (c) you have to remember to undo it at the right time (way more subtle than it appears - think it through!).

A sync engine creates the client-side normalized datastore that allows you to "do a mutation client side". In fact, you're kind of right that once you have a sync engine, just doing a mutation is really easy. The real challenge is all the infra required to enable you to do so.


Make the checkbox turn green. Make the comment appear in the list. Set the date to the new date the user wanted.

That's the mutation.

Whatever your talking about, is irrelevant


> it’s very possible to run a web app backend within ~10ms RTT of most users and have the backend render responses within ~10ms too.

What are you talking about? The only AWS region < 10ms away from us-east-1 is, err, us-east-2:

https://www.cloudping.co/

us-west-1 is 60ms away. eu-centra-1 is 100ms away. asia is 200ms away.

and this is datacenter-to-datacenter traffic. Actual latency over the public internet to residential providers is far worse.

Your database needs to be in exactly one region. So no matter where you put it, the majority of uses on earth are going to be > 100ms away from it.

It doesn't matter where the endpoints are, because the endpoints need to talk to the database to read and write data. Thinking you can replicate some data closer to the users? Congrats you are now the proud owner of a "local-first syncing" database. This replicated database you use (either of your own design or off the shelf) will have all the same problems of client-side syncing. Except you'll still have significant network latency.

There is no getting around physics. You either have quarter-second commits for most users or eventual consistency (aka syncing). Those are the options.


you can home tenants in a data center close to them, run a copy of your app in each region including the datastore. keep a central db for accounts, billing, etc but user content is easy enough to shard regionally.

taken to extreme, cloudflare durable objects & workers let you place data very close to a tenant automatically; but you lose total write throughput on top of sqlite.


This breaks down when someone goes on holiday to Greece for a week, and the RTT over the airbnb wifi is 5 seconds.

Optimistic updates on the frontend are probably simpler too.


oh for sure you start with client side cache & optimistic updates. but u need low latency / regional backend for multiplayer to feel good. I didn’t realize who i was replying to, aaron is probably one of the few people who think about sync engines more than me. anyways we do both at notion and of course we did local cache first client way before we did multi region at Notion.

But this is kind of meaningless unless the tenants themselves are in one geo. Take linear as an example, this strategy works as long as your company that uses linear is all colocated in one area. As soon as you have remote people it falls apart.

Not necessarily. You can do async replication either at the app level or DB level to other regions

Each individual user is fast due to close geo and everyone else has a small (potentially trivial) lag to see writes.

Not sure if such an architecture is worth the complexity, but it's definitely possible.

Actually such architectures are quite old. Back when I worked at Kmart, they had a store server in the office of every store. The store server would asynchronously sync back to corporate (afaik an overnight cron but I think it could be triggered on command). That was the geographically close "edge" server and the store was the tenant. Most ops were quick. For cross tenant queries, clients maintained a list of store numbers and locations. They did some bit twiddling with the store number to calculate a deterministic IP which went to the store server for that store (tenant discovery). With the server IP they could run remote queries directly at the cost of much higher latency since you had to go back through the corporate S2S VPN to headquarters then to the target store.

As for cross geo, you can have writes always be instantly acknowledged at the closest geo location and immediately available to nearby clients while they get asynchronously replicated in the background. Really you'd only see marginal higher write latency when two people are working at the same time in different geographies. That's partially mitigated with time zones


What you are describing is exactly what sync engines do. You can have replicas on the server or replicas on the clients. The tradeoffs are the same except the client-based replicas can be in memory, accessed synchronously directly on the ui thread. No server latency at all.

But it does mean you gracefully degrade so the majority of the company sees the target latency <100ms and the rest of the company sees "not geo-optimized" latency.

Only in the case where there is such a majority of the company that is tightly geolocated.

Again, AWS latency us-west-1 to us-east-1 is 70ms. That's absolute best case for one round-trip that does absolutely no work. And it's ignoring the case of anyone outside of continental US.

Add in actual server-side work, db interactions, and contention - and you're quickly looking at hundreds of ms.


If your users are truly broadly geodistributed, there's no avoiding hundreds of milliseconds of latency if you want strong consistency. You're fighting the speed of light. You can move the source of truth closer to the majority of users with effort without meaningfully regressing performance for the users who aren't tightly geolocated, so you can treat it as a fairly pure optimization.

"Your database needs to be in exactly one region. So no matter where you put it, the majority of uses on earth are going to be > 100ms away from it."

You're assuming a single global database, which ignores the many alternatives.


I’m not. See: https://news.ycombinator.com/item?id=48440209

These systems are designed for the very common case of a global user base. If you have geographically centralized users, you can maybe do something simpler. That is rare in my experience - basically all of our customers have users worldwide. They typically don’t even know where their users are so making ux tradeoffs based on that feels really risky.

But maybe my experience is different than yours. One of the amazing things about the software ecosystem is how big it is. Everyone thinks their view is the common case.


Linus was my boss at Google for nearly 10 years. His main contribution was one of the key people behind Chrome. He's as good as they come.


I was there 2004-2014 and never used an IDE the entire time. From my perspective the most popular editors were emacs and vim. Life was probably different in the Android and Java areas, but there was also a massive chunk (50%+?) of people writing C++ and Python, and I think IDE-less is/was the standard for those folks.


lol I read "as many as 15+ direct reports" and thought it was hilariously low. My manager at google had like 50+ directs in 2010. And he was the best boss I've ever had.

Popular conception of what a manager is is wildly unambitious.

Weekly 1:1 is performative and useless. It's not what makes a good manager. What makes a good manager is:

  * Having excellent domain knowledge and judgement
  * Having the respect of the team, to settle disputes
  * Solving problems when needed
  * Hiring and retaining an excellent team
  * Picking the right things to work on
... etc ...

If a manager is doing these things well I don't need a standing meeting at all. Or we can meet quarterly to check in.

Email is a thing.


Interesting. I'd define all of those tasks as the job of a team/tech lead, rather than a manager. I've worked at places where the same person did both roles, and it was not always a great mix.


If you think hiring, prioritizing, planning, and cross-team negotiation are all tasks of a tech lead and not a manager, then what is the job of an engineering manager in your opinion?


IMO purely people management (1:1s, promotions, goal-setting, staffing/resourcing, involvement in hiring).


But how can you know who to promote, how to balance resources, or who to hire if you're not leading the project?

People management is about managing the company's resources to achieve goals. If you are not the one leading the implementation of those goals, you are not going to be able to:

  * reason about what the right about of resources should be
  * see opportunities for optimization
  * forecast future need
You will be completely dependent on a technical lead who does have that information. So then what is your independent role? Just to shuttle information between the technical lead and others?


The most common split I'm aware of is tech lead / eng mgr. The eng mgr does "people stuff" like hiring/firing and cross-org negotiation, and tech lead does "technical stuff".

But the thing is this makes no sense. Tech issues always turn into people issues - when there is a disagreement, who adjudicates? How can a manager adjudicate something they don't understand. And how will engineers respect / follow the decision?

And people issues invariably become tech issues. How can you hire the right people if you don't understand the tech? How will you know when to fire?

This setup makes no sense to me and i have very rarely seen it work. It seems like it was a product of an earlier time when there was a lot of money floating around and provided a way to (a) shield senior eng from dealing with people problem they just didn't want to, and (b) provide cushy jobs to professional managers that didn't know much about the tech.

But it doesn't work. There's no way to do the shielding well and a person with hiring/firing power needs to know what the fuck is going on.

Really good eng leaders must be both good at tech and good at people. That's the job.


Median tenure at a lot of tech companies is around 18 months. If you meet quarterly with your manager, the median employee is only going to meet with their manager 6 times, total! Not to mention people change jobs, and org charts change, so even if you don't leave after 18 months your manager might. How can you build a real relationship with only 6 meetings total?


Do you people only interact with your manager via 1:1? I was constantly interacting with my boss - design meetings, code reviews, product decisions, whiteboard sessions, in slack, in irc ... he was always around.

I got to know him much better through these productive interactions then awkward smalltalk in a 1:1.

And it kind of make sense to meet privately quarterly since perf reviews are also quarterly and that's the only reason I can really think of for a private scheduled face-to-face.

Of course I could always just ask for a private meeting anytime I wanted, which I guess I did from time to time. But it always for a product reason: a tough tech choice I was wrestling with or similar.


I guess it depends on the culture. In a lot of work cultures those other meetings are all work, and if you are fully remote (especially while others are not)* then there's no water-cooler talk.

Plus I think the regularity/cadence of it is supposed to provide some psychological safety. Asking for a one-off meeting feels like overkill for a normal 1:1, and yet a little intimidating for the type of 1:1 that you really need to have a 1:1 for (like discussing interpersonal issues).

* I suppose if everyone's fully remote, in theory the water-cooler talk moves to Slack.


This is stupid and irrational. It's like seeing someone eat 100 cakes, and then assuming everyone can do it. And then getting diabetes afterwards.

It seems quite counterproductive to assume such a system would scale to everyone else, or that everyone else could possibly implement this. This is cowboy levels of human resource management, not careful engineering.


I mean a branching factor of 50 vs a branching factor of 7 is a massive difference. A team of 50 can either be run by one manager and a two-level tree or like 8 managers (!!) and a three-level tree. Think about the difference in execution (and expense) in these two companies.

If you can do it w/ the first model why on earth would you not?


This is "Steve Jobs looking at someone on a fruit diet" and thinking "I can do it too" levels of reckless.

Hell, Dunbar's Number is 150 people, and you expect to have 50 directs? That's literally 1/3 of your 150 being occupied by directs. It seems clearly infeasible the more you think about it.


I mean I have 7 reports right now and we're a startup. And fully remote. And I'm still contributing as an IC too.


A manager who is also contributing code is almost an entirely different role than a manager who is not contributing code. Typically the former should not exist in a smaller org and in a larger org it makes sense to shift to the latter because there's enough non-code work to do that you might as well dedicate whole people to the task.

Different roles though.


Congrats, Instant team. Genuinely happy for y'all.


Thank you! Awesome work with Zero, been a fan of you since listening to your episode on the local first podcast!


But that is a kind of silly way to compare. Broccoli isn't very filling _and_ it doesn't have very much protein in it. That doesn't change the fact that it lack protein.

The question is if I'm preparing a meal that I want to be filling, healthy, and energizing, how should I do it. Broccoli isn't a good answer to the protein part of that question.


Protein may be associated with satiety, but so is fibre, of which beef has none.


I live in Hawaii where the Toyota Tacoma is basically the state mascot. I owned almost exclusively sedans before I moved here. A friend from the bay area moved here several years ago and argued he wouldn't need a pickup, but ended up getting a Rivian within a year or so.

The pickup is more practical than a van here because you end up hauling a lot of dirty/sandy/wet stuff. Yes, you could put this in your van, but hooray now you have sand and water in your van that you need to clean out (and you do need to because the heat will turn it into mildew immediately if you don't). The bed of the truck is outside. It dries out on its own. The sand falls out on its own.

I can't speak for other parts of the US, but use cases can be subtle and I would be slightly cautious about deciding that 300M people and a several trillion dollar market has been completely irrational for decades.


Alaska checking in. Nobody is hauling a skidoo around here in a van. You also won’t see anyone towing a trailer with one or two machines with anything other than a truck, because nothing else is going to hack it in the mountains with all that. I currently just drive mine up a ramp into the truck bed, I can quickly park and get off and go and back on again. Very versatile combo to get around with.

Right tool for the job. I drive an AWD Prius with winter tires to get groceries in the snow.


When I lived in anchorage ages ago Subarus were really popular.

Everyone with a truck had to put a bunch of weight in the back to manage the roads in the winter.


It’s the same here in Fairbanks. We also have an Outback that we drove here when we moved a decade ago (towing a trailer, no less). That and the Prius both handle fabulously with winter tires. Since I only use the truck for hauling, it’s always weighted in the back!


Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: