skip to content

Two teams share one flat keyspace and one writes entries under the key user:1042 — what should that key carry instead?

level: juniorimportance: must knowfreq 70%

answer

  1. nothing here enforces a name
  2. the key is the model
  3. whose entry is this?
  4. owner, entity, identifier, format version

basics

~20 s

On a shared flat keyspace the key string is the entire addressing model, so it must say whose it is: an owning prefix, then the entity, then the identifier, and a format version where the value's shape may change.

solid answer

~50 s

`user:1042` names an entity and an identifier and nothing else, so it is a name any other team on the tier may also choose — and the store has no schema to object. Write the key from a template of segments joined by one separator fixed across the organisation: an **owning prefix** naming the team or service, the **entity**, the **identifier**, and a **format version** where the value's serialized shape may change under a rolling deployment. The prefix is the segment doing the work: it makes an entry attributable to whoever wrote it, and it means a second team arriving on the tier does not silently land on top of yours. The separator is a convention rather than something the store enforces, and stores differ in which bytes a key may hold, so fix it against the store you actually run.

go deeper

for a junior

Recall the four segments and why they exist: owner, entity, identifier, and a format version where the value's shape can change. Be able to say out loud that nothing in the store stops a second team writing the same name.

for a middle

Explain the failure mechanics, not the convention: one name addresses one entry, a write replaces the value, and both callers still succeed. Say what the separator does and does not guarantee, and what happens when an identifier contains it.

for a senior

Show that you have enforced a convention rather than written one — keys built through a single function, a format version segment planned before the first shape change, and a clear statement that a prefix buys attribution rather than isolation.

for a principal

Frame it as an organisational contract: what every key on a shared tier must encode so an entry is attributable years later, and how you get a convention adopted when nothing in the store will ever reject a key that ignores it.

## The store has no schema, so the key is the addressing model An in-memory store of this class has no table, no column list and nothing that declares what may exist. The address string is the model: the only promise is that a value written under a key comes back under that same key. A relational engine refuses a second table with a name already taken; here nothing refuses anything. So `user:1042` is not a declaration that these entries belong to your service. It is a claim on a name, made by whoever wrote first and taken over by whoever writes next. That is why interviewers open here. An unprefixed key is cheap to type and expensive on a tier two teams share, and the cost arrives months later, in someone else's service. ## What a collision actually looks like Two services writing the same key do not get an error. One name addresses one entry, and a write replaces the value that was there. Both writes succeed, both reads succeed, and nothing fails at the moment the two designs meet: - if the two services store **different shapes**, the reader fails to parse a value it did not write — a confusing failure a long way from its cause; - if they store the **same shape with different meanings** — one counting attempts, the other counting successes — nothing fails at all, and the number is simply wrong; - if one service attaches a lifetime to the entry and the other does not, each is surprised by the other's behaviour without ever seeing the other's code. ## The segments a key on a shared tier should carry | Segment | The question it answers | What goes wrong without it | |---|---|---| | Owning prefix | Whose entry is this? | Two teams claim one name; nobody can attribute an entry found later | | Entity | What kind of thing is it? | `1042` alone is meaningless to the next reader | | Identifier | Which one? | Every instance of the entity fights for one name | | Field | Which part of the thing? | Only relevant where the design addresses parts separately rather than holding the whole thing under one key | | Format version | Which shape is the value in? | Two deployed versions of an application read each other's writes and cannot parse them | A worked template: `acme:billing:invoice:5561:v2`. Read left to right it says the organisation or team, the service or domain, the entity, the identifier, and the shape of the value. Someone who finds that key in a listing two years from now can answer who to ask. The field segment is conditional in a way worth stating: whether one entry per field is even an option depends on the store. Where the server treats values as **opaque bytes it only hands back**, every change is a full read-modify-write and a key per field is the only way to address a part. Where the server understands the value as **structure it can read or change in part**, the same design can be one entry addressed by field instead. The naming choice follows that, not the other way round. ## The separator is a choice, not a rule A colon is conventional and nothing more; the store does not parse it, does not index it and does not reserve it. Stores differ in which bytes a key may contain and how long a key may be, so fix the separator against the store you run rather than against habit. The one hard requirement is that the separator must not appear inside a segment value — an identifier that is an email address or a free-text name will eventually contain whatever character you picked, and then a reader splitting the key gets the wrong segments. Either choose a character that cannot occur, or encode the segment on the way in. The same discipline applies to prefixes that are prefixes of each other: `user` is a prefix of `username`, so any convention that matches on a leading string should match on the separator too. ## What a prefix does not buy you - It **reserves nothing**. Another team can still write your name; the prefix makes that unlikely and always attributable, not impossible. - It isolates **names only**. Where the store offers a named container above the key as an alternative to a prefix, that container isolates names only as well: the memory, the ceiling and the operator stay shared. - It says nothing about **where an entry lives** when the keyspace is split across nodes; what a segment does to placement is a separate subject. - Longer keys are not free, but how much those extra bytes cost is a sizing question rather than a naming one. ## Put the convention in code, not in a document A convention that lives only in a wiki page is followed until someone is in a hurry. Build keys through one small function per service — owner, entity, identifier in, key string out — so that the convention has exactly one place to be wrong, and so that changing it later is a change to one function rather than an archaeology exercise across every call site.

  • Where in the key does a format version belong, and what does it buy during a rolling deployment?
    Put it at the end, alongside the identifier, so the owner and entity segments stay stable. During a rolling deployment two application versions run at once; if the value's serialized shape changed, a version segment means each writes and reads its own shape rather than handing the other a value it cannot parse. Old-shape entries then age out or are removed deliberately once no reader wants them.
  • Your convention fixes a separator, but an identifier already contains that character — what breaks, and what do you do?
    Splitting the key gives the wrong segments: an identifier containing the separator reads as two segments, so tooling and any prefix match attribute the entry to the wrong owner or entity, and two different identifiers can produce the same key string. Either pick a separator that cannot occur in any identifier you accept, or encode the segment on the way in so the raw character never reaches the key.
  • Does adding an owning prefix stop another team writing your entries?
    No. Nothing in the store reserves a name; a prefix is a habit, not a lock. What it buys is that an accidental clash becomes unlikely, and that every entry found later is attributable to an owner who can be asked. Keeping two teams genuinely apart by credentials, quotas or separate deployments is a different lever entirely.

A shared filing room where anyone may create a folder with any label. The room does not stop two departments labelling a folder invoices, and nothing announces the clash — the second department's folder simply stands where the first one did. The only defence is the label itself: department, document kind, number.

saying these in an interview costs you the question

  • Thinks the store rejects a key another team has already written.
  • Treats the separator as something the store parses or enforces.
  • Believes an owning prefix isolates memory or capacity, not just names.
  • Assumes every store offers a named container above the key.
  • Puts a mutable attribute such as a status into the identifier segment.
  • Says an unprefixed key is fine because their service is the only writer.