skip to content

For an ancestor-provided value holding frequently changing data, what decides how costly each change is?

level: seniorimportance: should knowfreq 54%

answer

  1. reach and notification are separate
  2. granularity is the runtime's, not the pattern's
  3. coarse channel: the provision is the unit
  4. fine-grained: the read is the unit
  5. split provisions by change rate

basics

~20 s

The runtime's propagation granularity, not the pattern. A coarse channel notifies every consumer in the subtree on any change; a provided fine-grained reactive value notifies only the computations that read the changed part; a provided plain collaborator notifies nobody.

solid answer

~50 s

Provision answers two separate questions, and only the first belongs to the pattern: how a descendant reaches the value, and how it learns the value changed. The second is the runtime's. Where the channel carries one opaque value and change is detected by comparing that value's identity, every consumer in the subtree is notified on every change, whether or not the part it reads moved - so a wide, fast-changing value wakes the whole subtree. Where the provided value is a fine-grained reactive cell, the read subscribes at the point of use and a write notifies only the computations that read it. Where you provide a plain collaborator object, provision propagates nothing at all; anyone who wants notification arranges it separately. The same design is therefore cheap in one runtime and a hot spot in another.

go deeper

for a junior

Know that reading an ambient value is not free: something has to tell the consumer it changed, and how narrowly it tells depends on the framework.

for a middle

Explain the difference between reaching a value and being notified about it, and state what a coarse identity-compared channel does to consumers that read only one field.

for a senior

Demonstrate measurement: identify which consumers wake on a given change, then restructure the provisions so unrelated readers stop paying for each other.

for a principal

Own the rule for the codebase: what may ride the tree channel at what change rate, and when data should stop riding the tree at all.

Ambient provision gets contradictory reputations - "use it freely" in one ecosystem, "never put changing data in it" in another - and both pieces of advice are locally correct. The reason is that the pattern only owns half the problem. ## Two questions, one pattern - **Reach**: how does a descendant get hold of the value? That is provision, and it works the same way everywhere: a provider scopes a key to its subtree and a read resolves upward to the nearest one. - **Notification**: how does a consumer learn the value is now different? That is the runtime's reactivity model, and it varies enormously. Cost lives almost entirely in the second question. Reaching the value is a lookup that happens once per read; being notified happens on every change, for every consumer the channel considers affected. ## Three propagation shapes | what is provided | what counts as a change | who gets notified | where the cost lands | |---|---|---|---| | one opaque value on an identity-compared channel | the provided value is no longer the same value as before | every consumer in the subtree, regardless of which part it reads | proportional to consumers x change rate | | a fine-grained reactive cell | a write to that cell | only the computations that actually read that cell | proportional to real readers of that cell | | a plain collaborator object | nothing - provision does not watch it | nobody | none from provision; notification must be built separately | The middle row is the one people generalise from and the top row is the one that bites. On a coarse channel the unit of notification is **the provision**, not the read: a consumer that touches one field of a ten-field value is treated exactly like a consumer that touches all ten. ## Why the same design gets opposite advice Take one wide provided value holding the session, the theme, a draft form value that changes per keystroke, and a cached list: - On an identity-compared channel, every keystroke produces a new value, and every consumer in the subtree is notified - including the one that only renders a theme-coloured border. The pattern looks expensive, and the received wisdom becomes "keep changing data out of the ambient channel". - With fine-grained tracking, the draft is its own cell; a keystroke notifies the computations that read the draft and nothing else. The same wide provision is unremarkable, and the received wisdom becomes "provide whatever you like". - With a provided collaborator that owns the draft internally, nothing is notified at all, and a consumer that expected to update will simply never update - a correctness surprise rather than a cost one. None of these is the pattern being good or bad. They are three different answers to the notification question, wearing the same shape. ## What this means for membership - **Slow-changing ambient values are safe everywhere**: theme, locale, session, a configured client. They change orders of magnitude less often than components render. - **Fast-changing data needs a channel with read-level granularity**, or it does not belong on the tree channel at all. A value that lives outside the tree with its own per-consumer subscription is a different mechanism with different tradeoffs, and choosing it is the honest answer when the write rate is high. - **Wide bags of unrelated values are the worst case on a coarse channel**, because unrelated features pay for each other's changes and the cost grows with both the number of readers and the total write rate across everything in the bag. ## Designing for a coarse channel 1. **Keep the provided identity stable** across updates that did not actually change anything, so the channel does not report a change that is not one. 2. **Split one wide provision into several narrow ones that match how consumers read.** Notification granularity follows the provision, so making provisions match read patterns is the only lever the pattern itself gives you. 3. **Separate by change rate, not by topic**: put the fast-changing part in its own provision even if it is conceptually related to slow parts, so slow readers stop waking. 4. **Provide a stable handle rather than a snapshot** when consumers need current data at high frequency - and accept that the handle's own notification mechanism, not provision, is now what you are relying on. ## How to tell which runtime you are in - Write to one field of a provided value while a consumer reads only another field. If that consumer is notified, the channel is coarse. - Ask where the subscription is recorded: at the read site inside the consumer, or at the consumer's attachment to the provision as a whole. - Replace a provided object with an equal-but-new copy. If consumers are notified, changes are being detected by identity rather than by content or by tracked reads.

  • How do you establish whether the channel you are providing over is coarse or fine-grained?
    Run the discriminating experiment: write to one field of a provided value while a consumer reads only a different field, and observe whether that consumer is notified. Then check where the subscription is recorded - at the read site inside the consumer, or at the consumer's attachment to the provision as a whole. The first is fine-grained, the second coarse.
  • Why is a wide bag of unrelated values the worst case on a coarse channel?
    Because notification follows the provision rather than the read. Every consumer of the bag is woken by every change to any part of it, so unrelated features pay for each other's write rates, and the total cost scales with readers multiplied by all writes in the bag. Splitting by read pattern restores proportionality.
  • Does keeping the provided value's identity stable help on a fine-grained channel too?
    Less, because there the unit of notification is the cell a consumer actually read, not the container handed down. Stability still helps anything that compares the container - derived values, equality-based guards, or code that stores it - but it is not the main lever the way it is on an identity-compared channel.

saying these in an interview costs you the question

  • Says ambient provision is inherently slow regardless of runtime
  • Thinks a consumer reading one field is spared when another field changes on a coarse channel
  • Mutates the provided object in place and assumes every runtime notices
  • Blames the pattern for cost the reactivity model decides
  • Mixes fast-changing and slow-changing data in one wide provision
  • Recreates the provided value every update to be safe