advanced
1 min answer
An issue tracker with local-first behaviour keeps a client-side store, a sync engine, and a server. A product manager asks for a new field on an issue. In a well-separated design, how many places should change, and what does the answer tell you?
Show the full answer Hide the answer
The ideal and the reality
The ideal answer is "one place — the schema — and everything else is generic." The realistic answer for a local-first product is three: the schema, any index or query that must be efficient over the new field, and any conflict-resolution rule the field needs. Anything beyond that is a leak.
What good separation looks like here
- The sync engine should not know what an issue is. It moves versioned records, resolves conflicts by declared policy, and handles ordering and reconnection. If adding a field requires editing the sync engine, domain knowledge has leaked into transport.
- The client store should not know how sync works. It reads and writes locally and observes changes. If a UI component has to reason about pending mutations, the boundary is wrong and every future feature pays for it.
- The conflict policy is a legitimate per-field concern, and pretending otherwise is the more common mistake. A last-writer-wins title and a set-union label list are genuinely different, and the honest design declares the policy in the schema rather than hiding it in the merge code.
Why the count is the diagnostic
Counting the places a small change touches is the cheapest architecture assessment available, and it needs no diagram. If a one-field change touches nine files across four layers, the layers are not separating concerns; they are repeating one concern at four altitudes. That is the signature of layering applied by convention rather than by responsibility, and it costs a fixed tax on every feature for the life of the system.