The Hidden Boundary That Makes Fast Systems Possible

Jaeyeol Lee

Hatched by Jaeyeol Lee

Jun 03, 2026

10 min read

86%

0

The question beneath both testing and reactivity

What does a system need to know in order to do less work?

That question sits at the center of two apparently different worlds: software testing and frontend reactivity. In one, a test framework needs to know what happened so it can decide whether to report a pass, a failure, or a formatted stream of results. In the other, a UI framework needs to know what changed so it can decide whether to rerun everything, rerender only a subtree, or simply update a single DOM value. In both cases, performance is not really about raw speed. It is about where the boundary lives between observation and action.

The deepest design choice in modern software systems is not whether they are declarative or imperative, reactive or static, coarse-grained or fine-grained. It is whether the system can localize knowledge. If it can, it avoids unnecessary work. If it cannot, it compensates by repeating work everywhere.

That is the hidden connection between assertion styles in test frameworks and reactivity models in JavaScript UI frameworks: both are different answers to the same architectural problem. How much should the runtime know, and how precisely should it know it?


Protocols, objects, and the cost of knowing too much

Testing frameworks reveal this tradeoff in unusually pure form. A spec-style test reads like a conversation with a harness: define a suite, define a block, make assertions inside it. A TAP-style tool is different. It emits a text protocol, and that protocol becomes the contract. A JUnit-like system goes even further, turning failures into structured output that can be saved, transported, consumed, and converted.

These are not just stylistic differences. They describe three different ideas of where the truth of a test lives.

In a spec-style setup, the test and the runner often share a rich object model. The runner can ask the test framework questions directly, but that direct access is opinionated. The harness knows a lot because it has been granted access to a lot. In TAP or XML-based formats, the test runner knows less in the moment, but the tradeoff is massive interoperability. Anything that speaks the protocol can participate.

This is the first useful frame: rich shared state versus narrow serialized contracts.

The first makes it easy to express intent in a high-level way. The second makes the output portable, durable, and decoupled from the runtime that produced it. One is like a backstage pass. The other is like a shipping container. The backstage pass lets you move quickly inside one venue. The shipping container lets you move across ports, customs systems, and rail lines.

That distinction turns out to matter just as much in reactivity.

The less a system needs to infer, the less work it has to do.

But inference has a price. If the framework only knows that something changed somewhere, it must inspect more of the world. If it knows exactly which value changed and who touched it, it can stay still almost everywhere else.


Reactivity is just testing in disguise

Reactivity is often described as a UI concern, but that is too narrow. Reactivity is a theory of change propagation. It answers a question that sounds simple and is not: when one value changes, what else must be reconsidered?

Coarse-grained systems answer by broad rerun. If the framework does not know what changed, it reruns a component, or a subtree, or a large slice of the app. That is not stupidity. It is a design choice. When knowledge is expensive or unavailable, recomputation becomes the simplest safe move. React and Angular are frequently discussed in this way, where a change can cause a large re-execution cycle.

Fine-grained systems try to shrink the blast radius. Signals, refs, or observable subscriptions create a more exact contract. A value lives in a bucket, and when someone reads it, the system records that dependency. Later, if the value changes, the framework does not guess. It already knows who cared.

This is where the testing analogy becomes powerful. A test assertion is a dependency declaration. It says: “this property matters, and this exact condition is what I am checking.” A coarse test might effectively say: “rerun everything and see if the suite still looks healthy.” A fine-grained one pinpoints the expectation. The system can fail fast because the boundary of interest is explicit.

In that sense, a signal is like an assertion tracker and a DOM node is like a test result. The signal records who is watching. The assertion records what must hold. Both make the system more selective about when to do work.

Consider a simple counter UI. If a button increments a count, a coarse framework may rerender a parent, a wrapper, a display, and even unrelated children. A fine-grained framework can update just the display text. The logic is similar to a test harness that only re-evaluates the assertions affected by a change rather than re-processing an entire results tree.

The key idea is not “less rendering is always better.” The key idea is better localization of responsibility.


Hydration, resumability, and the politics of starting over

The most revealing part of the modern framework debate is not signals versus subscriptions. It is hydration versus resumability.

Hydration assumes that the server rendered a shell, and the client must pick up that shell and attach behavior to it. This often means shipping a lot of code to the browser, reconstructing state, and re-executing parts of the application so the client can become fully interactive. In human terms, it is like arriving at a meeting where someone already filled the whiteboard, and your job is to reconstruct the conversation that produced it before you can contribute.

Resumability takes a different stance. Instead of replaying the past, it preserves enough execution state that the client can continue from where the server left off. That changes the economics of startup dramatically. If no component needs to be downloaded or executed until it is truly needed, the runtime can stay dormant. Only the structural changes, the true forks in the tree, force more code into motion.

This is not merely a performance optimization. It is a philosophical preference for deferred knowledge. The system says: do not make me understand everything upfront if I only need to act on a small part of it later.

That principle mirrors protocol-based testing. A protocol like TAP or XML does not ask the consumer to share the producer’s in-memory objects. It says: here is enough structured information to continue later, inspect later, report later, or move between tools. The value of the result is preserved without requiring synchronized execution contexts.

There is a deeper pattern here. Both resumability and protocol-based test results reject the idea that a runtime should be forced to rebuild itself just because it crossed a boundary. Instead, they preserve the right kind of state so the next system in line can continue with precision.

The ideal boundary is not a wall. It is a memory aid.

It should remember just enough for the next actor to do the minimum necessary work.


The real choice: broad certainty or narrow accountability

The temptation in software design is to frame every tradeoff as a battle between simplicity and complexity. But the more important split is between broad certainty and narrow accountability.

Broad certainty means the framework can always be safe by doing more. Rerun the component. Recompute the subtree. Re-execute the assertion block. Serialize the result after the fact. This style is attractive because it reduces the number of questions the runtime must answer precisely. It is robust in the face of ambiguous changes.

Narrow accountability means the framework knows exactly what it is responsible for, and nothing more. A signal knows who read it. A test assertion knows which condition it is guarding. A resumable component knows which piece of execution can be paused and later resumed. This style reduces unnecessary work, but it demands a more disciplined model of dependencies.

The interesting part is that these are not opposites in the moral sense. Broad certainty is not lazy, and narrow accountability is not virtuous by default. Broad certainty is often the right answer when the cost of tracking fine-grained dependencies exceeds the savings. Narrow accountability is only worth it when the system is large enough, interactive enough, or latency-sensitive enough to benefit.

That is why the best systems are rarely purely one thing. They use broad certainty at the boundaries and narrow accountability inside the hot path. A test suite may emit a formal protocol for interoperability, while still using rich local assertions for clarity. A UI framework may hydrate broadly at first but use signals or compiler analysis to localize updates after startup. Svelte leans on compilation to know what did not change. Vue uses refs as a signal-like primitive. Observables rely on subscription graphs. Qwik pushes the boundary further by making persistence across server and client central to the model.

All of these are variations on the same theme: make the system’s ignorance explicit, then shrink it.

That phrase is worth sitting with. Most performance problems are not caused by the wrong algorithm alone. They are caused by the wrong uncertainty model. The system does not know enough about what changed, so it compensates by rechecking too much. Better boundaries do not merely speed things up. They reduce the amount of world the runtime has to hold in its head.


A practical framework for designing less-work systems

If you are building or evaluating a software system, ask four questions:

  1. What does the runtime know exactly? If it cannot answer this clearly, expect broad recomputation.

  2. What is the smallest useful boundary? Can the system track a value, a node, a subscription, a test point, or a serialized event instead of an entire object graph?

  3. Where is the contract stored? Is it in shared memory, in a protocol, in compiler analysis, or in execution state that can be resumed later?

  4. What work becomes unnecessary if that boundary is precise? This is the real payoff. Do not celebrate locality in abstract. Count the rerenders, the reruns, the downloads, the reparsing, the repeated assertions.

These questions apply surprisingly well outside JavaScript. Build systems, compilers, databases, CI pipelines, and even distributed services all face the same problem. They either carry too much context across a boundary or too little. Too much, and they become tightly coupled. Too little, and they must infer their way through expensive retries.

A healthy architecture usually combines both styles. Use rich local structure where speed of expression matters. Use lean protocols where portability matters. Use fine-grained signals where updates are frequent. Use coarse-grained reruns where dependency tracking would be too costly or too fragile.

The mistake is not choosing one side. The mistake is pretending the boundary does not exist.


Key Takeaways

  • Ask what the system needs to know, not just what it needs to do. Performance often depends on how precisely change is represented.
  • Use rich objects for local clarity, protocols for cross-boundary durability. Shared state is convenient, but serialized contracts are portable and interoperable.
  • Prefer fine-grained dependencies when change is frequent and localized. Signals, refs, and subscriptions reduce unnecessary recomputation.
  • Use broad reruns when dependency tracking would be more expensive than the work itself. Coarse-grained systems are not failures, they are a deliberate tradeoff.
  • Design boundaries as memory, not as walls. The best boundary preserves just enough context to avoid replaying the entire past.

The conclusion hidden in plain sight

We tend to talk about testing and reactivity as separate disciplines because one evaluates correctness and the other manages change. But both are really about the same discipline: teaching a system to notice only what matters.

That is the deeper design aspiration behind assertions, signals, subscriptions, protocols, and resumability. Each is an attempt to stop the software from being distracted by the whole world when only one piece of it has changed.

So the next time a framework promises less rendering, faster startup, or better interoperability, the important question is not whether it is modern enough. The important question is simpler and sharper: what boundary did it learn to respect?

The future of fast software is not about making systems think harder. It is about making them know less, more precisely.

Sources

← Back to Library

Hatch New Ideas with Glasp AI 🐣

Glasp AI allows you to hatch new ideas based on your curated content. Let's curate and create with Glasp AI :)

Start Hatching 🐣