Limit Live Context

limit-live-context

Summary

Readers make mistakes when they must keep too many facts active to understand a change. Reduce live context by moving related facts together, naming intermediate concepts, and keeping dependencies local.

Problem

Long functions and modules make every earlier fact a possible influence on every later line. A reader trying to understand one block must keep prior variables, flags, partial calculations, side effects, and ordering assumptions in mind because any of them might still matter.

This cost grows faster than line count. The problem is not only that the code is long; it is that the reader cannot tell which facts are still live.

Preferred Move

Shrink the active set of facts a reader must hold at once. Keep scopes narrow, end temporary state quickly, group phases into visible blocks, and extract a named helper when a block has a clear purpose and limited interaction with the surrounding code.

When reading a later block, a maintainer should be able to answer: "Which earlier facts can affect this?" If the answer is "most of the function," reduce the live context before adding more behavior.

Tradeoff

Extraction can make context worse when it hides weak facts behind a vague name or forces the reader to jump between files. Prefer local blocks, smaller scopes, and explaining names until a helper has a strong contract.

Some algorithms genuinely require a large shared working set. In those cases, make the shared state explicit, document the invariant, and keep unrelated work outside the algorithm.

Agent Instruction

Before editing a long function or module, identify the facts that remain live across the area being
changed. Narrow scopes, split phases, or extract a helper when that reduces the live context needed
to review the change. Do not extract weak helpers only to reduce line count.

Examples

Bad: later code can depend on any earlier mutation, so the reviewer has to keep the whole function active while reading the final decision.

let mut score = base_score(pattern);
let mut has_examples = false;
let mut has_public_docs = false;

for example in pattern.examples() {
    has_examples = true;
    score += example.weight();
}

for doc in pattern.docs() {
    if doc.visibility().is_public() {
        has_public_docs = true;
        score += 2;
    }
}

if has_examples && has_public_docs && score >= policy.publish_score() {
    publish(pattern)?;
}

Good: each decision names the fact it contributes, and the final condition has a small active set.

let example_score = score_examples(pattern.examples());
let doc_score = score_public_docs(pattern.docs());
let publish_score = base_score(pattern) + example_score + doc_score;

let publishable = example_score.has_examples()
    && doc_score.has_public_docs()
    && publish_score >= policy.publish_score();

if publishable {
    publish(pattern)?;
}

References

Source Use Note
Code That Fits in Your Head: Heuristics for Software Engineering, Ch. 6 adapts Memory limits should shape code organization.
Code That Fits in Your Head: Heuristics for Software Engineering, Ch. 7 adapts Decomposition helps when it reduces the context in view.
Tidy First, Ch. 11 adapts Separating phases can reveal a routine's internal shape.
Tidy First, Ch. 12 adapts Extract helpers when a block has a purpose and small surface.