Comparing two frameworks' change-propagation models as a lead, what would you ask before committing a long-lived app?
answer
- a discipline, not a benchmark
- what becomes visible, what re-executes
- the boundary and the escape hatch
- what you can inspect when nothing updated
basics
~20 sAsk what makes a change visible, what unit re-executes, what the cost scales with, what discipline every developer must keep, what happens at the boundaries to non-framework code, and how you would debug a propagation that did not happen.
solid answer
~50 sBenchmarks are the least useful input, because at typical sizes all four models are fast enough and the real cost is paid per feature for years. I would ask six things. What makes a change visible - an intercepted write or a later check? What is the unit that re-executes - a component function, a computation, a binding, or a walked subtree? What does work scale with - subtree size, dependent count, or bindings times passes? What discipline does every developer owe it - a new snapshot, a handle read inside a tracked scope, a shape the compiler can prove, or a triggered check? What happens at the boundaries, where state meets code outside the tree and third-party libraries? And when propagation silently does not happen, what can I inspect? Then I would measure the app's own worst screen, not a demo.
go deeper
You are not expected to lead this call. Be able to say that the models differ in what they intercept and in what re-runs, and that each demands a different habit from the developer.
Be ready to describe both candidates in one sentence each - what becomes visible and what re-executes - and to say which of your screens would feel the difference.
Anchor the comparison in the worst screen you actually ship and in the code needed to make each candidate fast there. Name the silent-failure mode of each and how you would diagnose it.
Own the discipline, not the benchmark. Decide where the escape hatch begins, what the review rules are, and which budgets a screen must respect - then say plainly that ecosystem and fluency often outweigh the model itself.
## Why this is not a benchmark question Every one of the four models is fast enough for most screens, and the published comparisons measure the case each model was tuned for. What you are actually choosing is a **discipline the codebase inherits**, paid on every feature by every developer for as long as the app lives, plus a debugging story for the day a change does not reach the screen. Framing the decision that way is most of the answer. ## The questions, in the order they pay off 1. **How does a change become visible?** An intercepted write - a setter, a tracked handle, a compiled assignment - or a later check. This single answer predicts most of the rest. 2. **What is the unit of re-execution?** A component function, one computation, one compiled binding, or whatever a check walks. It determines how much wasted work a careless write causes. 3. **What does cost scale with?** Re-run subtree and output size; dependent count; dependents the compiler could prove; bindings checked times passes. Then ask which of those your app's hardest screen maximises - a wide table, a deep tree, a high-frequency drag. 4. **What does the model ask of every developer, on every feature?** Produce a new value rather than editing one; read through a handle inside a tracked scope; write in a shape a compiler can analyse; make sure a check is triggered and keep inputs reference-stable. This is the recurring bill, and it is where a team's mistakes will cluster. 5. **What happens at the boundaries?** State shared outside the component tree, a third-party library that mutates what you gave it, code in a module the compiler never saw, an integration that writes from an entry point the runtime does not know about. Each model has an escape hatch here, and how good it is matters more than the happy path. 6. **When a change does not propagate, what can I look at?** A live dependency graph you can interrogate, a log of what re-ran and why, or nothing - because a static wiring decision was made at build time. Silent staleness with no artefact to inspect is the expensive failure. 7. **What does the model cost in review and onboarding?** Can a reviewer tell from a diff that an update will reach the screen? A whole-function re-run is easy to read; an implicit dependency graph is precise but invisible in source. 8. **How much of the codebase will sit on the fast path?** If most of your state is shared, cross-module, or owned by non-framework code, you will live on the escape hatch and the headline model matters less than you think. ## What the models look like against those questions | | Visible when | Unit re-run | Cost driver | Standing discipline | |---|---|---|---|---| | Re-run and diff | a setter is called | component function | re-run subtree and output | new values, not edits; opt-in caching | | Read-time tracking | a handle is written | one computation | dependent count | read through the handle, in a tracked scope | | Compile-time rewriting | a rewritten assignment runs | one binding | statically provable dependents | keep writes in a shape the compiler proves | | Dirty checking | the next check runs | a walked subtree | bindings checked, times passes | trigger the check; keep inputs reference-stable | ## What to measure, if you measure Build one screen that is your app's genuine worst case - the widest table, the deepest tree, the highest-frequency interaction you actually ship - in both candidates, then measure input latency at the sizes your product reaches, not at a benchmark's. Record how much code each version needed to reach that number: manual caching, windowing, escape-hatch containers, explicit triggers. The interesting result is rarely which was faster; it is **how much work each demanded to get there**, because that work recurs on every screen like it. ## What not to decide on - Published operations-per-second numbers for a synthetic list. - A single feature name; features migrate between frameworks quickly, models do not. - A team preference expressed without naming the discipline it prefers, which usually means "the one we already know" - a legitimate factor, but say it out loud and price it. ## The honest conclusion to offer For most products the deciding factors are hiring, ecosystem, rendering-on-the-server story and the team's existing fluency, and the propagation model matters mainly where your worst screen is genuinely large or your state genuinely lives outside the tree. Say that plainly. Then commit to the thing the model actually forces: if it is a precise graph, invest in making dependencies legible in review; if it is whole-function re-runs, invest in the conventions that keep re-runs cheap; if it is a compiler, document exactly where the escape hatch begins; if it is a check, budget how large a checked region a screen is allowed to present. The failure a lead is judged on is not picking the slower model - it is adopting one and never establishing the discipline it demands.
- Why is the escape hatch often more decisive than the model's fast path?Because the fast path covers component-local state, which is the easy case, while shared state, third-party integrations and code outside the tree land on the hatch - and those are where the bugs and the architecture live. A model with a clean, well-understood hatch beats a faster one whose hatch is folklore.
- How would you frame this decision for stakeholders who only hear "which is faster"?Reframe it as cost per feature and time to diagnose. Show that both clear the latency bar on your worst screen, then show how much extra code and review discipline each needed to clear it. That converts an unanswerable speed argument into a maintenance number people can weigh.
- What would make you accept the model with the worse worst-case cost?A legible failure story and a team already fluent in it. If a propagation bug is inspectable and the discipline is one everybody already keeps, you ship correct features faster - and the worst-case gap can usually be closed locally with windowing, narrower units or fewer triggers.
saying these in an interview costs you the question
- Decides on synthetic benchmark numbers rather than the app's worst screen.
- Ignores what the model demands of every developer on every feature.
- Never asks what is inspectable when an update silently fails to happen.
- Assumes the fast path matters more than the escape hatch at the boundaries.
- Treats the choice as permanent and ignores hiring and ecosystem entirely.