Skip to content
academia.sh

Lesson 07 / 15

Change Size

Attention is fixed at 12 chunks; the same 24 defects are found 22 times at 100 lines, 18 times at 900 lines, 2 times at 2400 lines, and 36 of 2400 lines' chunks go unread.

Contents

The previous lesson handed the style axis off to a tool and measured attention shifting to another axis. The pattern built across the topic was this: adding axes raised the number of defects found. A single reviewer looking at five axes found what five reviewers found; what grew the number was not who looked, but which axis was looked at.

This lesson’s question comes from the opposite direction. Let the axis count stay fixed and let what is being looked at grow. Same reviewer, same five axes, same defects — only the change is 2400 lines instead of 100. With axis diversity left entirely intact, what happens to the number found?

Attention Is a Budget

The shared fixture’s reviewer works with two limits. The first is axis: they see only the defects on the axes they look at. The second is attention: the number of chunks actually read in one review round is limited. A chunk is 50 lines, attention is 12 chunks. This means roughly 600 lines are actually read in one sitting.

Attention being a budget is the fixture’s most important assumption, and it agrees with observation. A reviewer does not read a change at the same intensity start to finish; first chunks are read carefully, later ones are scanned faster and faster, and past a point reading gives way to approval. The fixture hardens this decline into a binary: the first 12 chunks are read, the rest are not. The hardening does not exaggerate the number, since chunks that stop getting read in reality are not completely blind either — but it makes the pattern visible.

The first consequence of this is arithmetic. If the change is under 600 lines, every chunk is read and the attention limit never engages; the only thing limiting is the axis list. Once the change passes 600 lines, every added chunk goes into the unread set. Attention does not grow; the change does.

Same Defects, Four Sizes

The constraint that makes the measurement meaningful is this: all four sizes carry the same 24 defects. The fixture does not grow the defect count along with the change’s size. This is deliberate. If the defect count also grew, a falling ratio would not be surprising; held constant, the ratio’s drop has exactly one source — the unread chunk.

The class distribution is also the same at all four sizes: interface 3, implementation 6, test 3, documentation 3, style 7, and unwritten requirement 2. The sixth class is the class no axis searches for: the defect of what was never written. Review looks inside the submitted change; it cannot see the absence of what was never submitted. This lesson shows those two defects separately in the missed column, because they keep going missed regardless of size and are not the cause of the drop.

The only thing that changes is the line count. Line count sets the chunk count, and chunk count sets the area defects are spread over. Defects are scattered across this area; since attention stays fixed, as the scattering area grows, an increasing share of defects falls into unread chunks.

The measurement’s assumptions:

  • RC1 — All four sizes are generated from the same shared fixture: 24 defects, the same class distribution, the same oracle. Since we placed the defects ourselves, which chunk each one sits in is known.
  • RC2 — The only thing that changes is the line count. The axis assignment is fixed: one reviewer, all five axes. Attention is fixed: 12 chunks.
  • RC3 — Reading starts at the first chunk and stops once attention runs out. A defect in an unread chunk goes unseen no matter which axis its class is on.
  • RC4 — In the second measurement, review takes a starting chunk; this changes where the attention limit is placed, not the size of attention itself. Every window still reads 12 chunks.
  • RC5 — Splitting does not redistribute defects. Same 2400 lines, same 48 chunks, same 24 defects; only the reading happens in four separate windows.
  • RC6 — The set’s resolution is 1/24, that is, 0.042, at the defect level; 1/12 at the chunk level. A smaller difference cannot be defended with this set.

Measurement

"""Change size: same 24 defects, four sizes, fixed attention.

Part 1 - unread chunks stay fixed as size grows, found ratio falls.
Part 2 - what changes when the same 2400 lines are read in four windows.
"""
SEED = 20260815
AXES = ("interface", "implementation", "test", "documentation", "style")
UNWRITTEN = "unwritten requirement"
CLASSES = AXES + (UNWRITTEN,)
ATTENTION = 12       # chunks actually read in one round
CHUNK = 50            # lines
SCALES = (100, 300, 900, 2400)


def rng(seed):
    d = seed % 2147483646 + 1

    def r(n):
        nonlocal d
        d = (d * 48271) % 2147483647
        return d % n
    return r


def change(lines, defect_count=24, seed=SEED):
    r, defects = rng(seed), []
    chunk_count = max(1, lines // CHUNK)
    for i in range(defect_count):
        defects.append({"no": i + 1, "class": CLASSES[r(6)],
                         "chunk": r(chunk_count)})
    return {"lines": lines, "chunks": chunk_count, "defects": defects}


def review(d, axes, start=0, attention=ATTENTION):
    """A reviewer starts at the given chunk and reads up to attention chunks."""
    read = set(range(start, min(start + attention, d["chunks"])))
    return {k["no"] for k in d["defects"]
            if k["class"] in axes and k["chunk"] in read}


FULL = set(AXES)
d0 = change(600)
distribution = {s: sum(1 for k in d0["defects"] if k["class"] == s) for s in CLASSES}
print("class distribution: " + ", ".join(f"{s} {n}" for s, n in distribution.items()))
print()
print(f"{'lines':>6s} {'chunks':>6s} {'read':>6s} {'unread':>7s} "
      f"{'found':>6s} {'missed':>6s} {'unwritten missed':>17s} {'ratio':>6s}")
for lines in SCALES:
    d = change(lines)
    b = review(d, FULL)
    missed = [k for k in d["defects"] if k["no"] not in b]
    unw = sum(1 for k in missed if k["class"] == UNWRITTEN)
    print(f"{lines:6d} {d['chunks']:6d} {min(ATTENTION, d['chunks']):6d} "
          f"{max(0, d['chunks'] - ATTENTION):7d} {len(b):6d} {len(missed):6d} "
          f"{unw:17d} {len(b) / len(d['defects']):6.3f}")

print()
big = change(2400)
total = set()
print(f"{'pass':>5s} {'chunk range':>12s} {'found':>6s}")
for i, start in enumerate(range(0, big["chunks"], ATTENTION)):
    b = review(big, FULL, start)
    total |= b
    print(f"{i + 1:5d} {f'{start}-{start + ATTENTION - 1}':>12s} {len(b):6d}")
missed = [k for k in big["defects"] if k["no"] not in total]
print(f"four-pass total: found {len(total)}, missed {len(missed)}, "
      f"ratio {len(total) / 24:.3f}")
print("missed classes: " + ", ".join(sorted({k["class"] for k in missed})))
class distribution: interface 3, implementation 6, test 3, documentation 3, style 7, unwritten requirement 2

 lines chunks   read  unread  found missed  unwritten missed  ratio
   100      2      2       0     22      2                 2  0.917
   300      6      6       0     22      2                 2  0.917
   900     18     12       6     18      6                 2  0.750
  2400     48     12      36      2     22                 2  0.083

 pass  chunk range  found
    1         0-11      2
    2        12-23     12
    3        24-35      2
    4        36-47      6
four-pass total: found 22, missed 2, ratio 0.917
missed classes: unwritten requirement

Where the Ratio Collapses

The top table’s first two rows are boring, and they should be. At 100 lines there are 2 chunks, at 300 there are 6; both are under attention, and unread chunks are 0 in both. Found is 22, missed is 2, and both of the missed are unwritten requirement. That is, as long as the change stays under attention, size has no effect at all; the only thing missed is already the class no axis searches for.

In the third row, the limit engages. 900 lines is 18 chunks, 12 are read, 6 chunks go unread. Found drops to 18, the ratio becomes 0.750. Of the 6 missed, 2 are unwritten requirement, and the remaining 4 are defects that were readable but were not read. By class, these sit on axes the reviewer is looking at — implementation and style. They are on the reviewer’s list, they are in the oracle, only not in front of their eyes.

The fourth row is the collapse. 2400 lines is 48 chunks and attention is still 12; 36 chunks go entirely unread. Found drops to 2, the ratio becomes 0.083. Defect count did not change, class distribution did not change, the reviewer’s axis list did not change. Only the change grew.

The class list in the missed column also widens in this row. At 900 lines, the missed were spread across two axes; at 2400, the 22 missed spread across all six classes at once. The loss from closing off an axis is confined to that axis and it is known where it looks; the loss from an unread chunk is independent of axis and where it falls is unknown. The two losses are not the same: the first is a decision, the second is an accident.

The difference between the two rows fits one sentence: the ratio tracks read chunks over total chunks. At 900 lines, 12/18 is read and the ratio falls to 0.750; at 2400, 12/48 is read and it falls to 0.083. Falling below 12/48 = 0.250 itself is because defects are not spread evenly across chunks: the first 12 chunks hold only 3 defects, and one is unwritten requirement. In a large change, where the reviewer happens to stop becomes a gamble.

Whether the differences sit inside the measurement’s band also needs checking. The drop from 22 to 18 is a difference of 4/24 = 0.167; since the set’s resolution is 0.042, this is four steps above it and defensible. The drop from 18 to 2 is 16/24 = 0.667 and needs no argument. In contrast, the difference between 100 and 300 lines is 0 — the set has nothing to say, and saying it has nothing to say is itself a result.

Where a Large Change Comes From

The numbers show a limit, but they do not show why it gets crossed. No one writes a 2400-line change in one sitting; that size accumulates. There are three common sources of accumulation, and all three are about flow, not writing.

The first is branch lifetime. The distinction built in the Branching and Collaboration course turns into a number here: a short-lived branch produces a small change, a long-lived branch grows a little every day and by review time is not a single purpose but a week’s total. The second is mixed classes: renaming, moving files, and format fixes arrive in the same change as a behavior change. The third is generated files: a dependency lock file, a compiled output, or a regenerable table growing the line count while carrying nothing inside it a reviewer can decide on.

All three share the same consequence, and it is the measurement’s fourth row: attention stays the same, chunk count grows. The remedy for all three is given not during review but before it — shortening branch lifetime, separating classes, keeping generated files out of review. Once 48 chunks land on the review table, only one thing can still be done: send it back.

Splitting Does Not Shrink Lines, It Grows Read Chunks

The bottom table reads the same 2400 lines in four windows. The change was not split, defects were not rescattered, attention was not grown — reading was done four times, each time through a different 12-chunk window. The result: 2 + 12 + 2 + 6 = 22 found, 2 missed, ratio 0.917.

This is the same ratio as the 100-line change. What determines the number found is not the change’s line count but the number of chunks read. When 2400 lines are read in four windows, all 48 of the 48 chunks get read and none go unread. The 2 missed defects are still the unwritten requirement class, and splitting does not touch them: no window shows what was never written.

The imbalance between windows is also instructive. The first window yields only 2, the second 12 defects. The window read in a single pass is the poorest window in defect terms. A reviewer reading the change in one round has no way of knowing this; which chunks are dense is learned only after reading all of them.

Splitting’s cost does not show in the number, but it is real: four windows mean four separate readings. This cost gets paid later in this topic, as wait time and review round count. What needs recording here is that the cost exists and is predictable — the price of finding 22 defects is splitting the reading into four.

The Limit of a Reviewable Change

The measurement gives a practical limit: a change is reviewable when it fits into as many chunks as the reviewer’s attention. With the fixture’s numbers, this is roughly 600 lines. The number itself is the fixture’s assumption and varies team to team; what does not vary is that a limit exists, and that crossing it makes the ratio drop silently.

Silently is the key word here. An unread chunk produces no feedback. A review of a 2400-line change also gets approved, it also closes, and someone looking from outside cannot tell the two reviews apart. Approval is not proof of having been read. The measurement’s 22 missed defects also entered the code right after an approved review.

The way to keep within the limit is to split the change, but splitting cannot be arbitrary. Each piece must be understandable on its own and correct on its own; otherwise the reviewer reads the piece, does not understand what it does, and waits for the next piece — another name for deferring the reading. The workable splitting criteria are: single purpose (a piece does one thing), standalone correctness (the system does not break if the piece merges alone), and separating moved from changed (renaming, moving files, and format fixes stay out of a behavior change).

The last criterion pays off the most. If a format fix grows a change by 300 lines, those 300 lines are 6 chunks, and 6 chunks of attention have been stolen from the behavior change. The previous lesson handed the style axis off to a tool; this lesson shows the same handoff’s second payoff — the axis handed off removes not only the discussion but the chunk from review too.

There are also changes that cannot be split. If a single interface’s name is changing and appears across two thousand lines, breaking it into pieces leaves every piece broken on its own — the first criterion collides with the second. What can be done here is not splitting but declaring a reading order: the author writes which chunks of the change need a decision and which repeat the same pattern. The bottom table shows why this works — two of the four windows yield 2 defects, one yields 12, one yields 6. Marked chunks would keep the reviewer’s first 12 chunks from being a gamble.

This declaration is not an accountability tool and should not be used as one. What it measures is not the person’s attention but the change’s readability: the same 48 chunks give a different result once their order is declared. The next two lessons carry this distinction forward — what gets measured, every time, is a property of the change and the process, not the person.

Summary

  • Attention is a budget: the number of chunks read in one review round is fixed (12 chunks, 600 lines, in the fixture). If the change is larger than that, every added chunk goes into the unread set.
  • Same 24 defects, same axis list: at 100 and 300 lines, 22 are found (0.917); at 900, 18 (0.750); at 2400, 2 (0.083). Defect count did not change, only the change grew.
  • 2400 lines is 48 chunks and 36 chunks go entirely unread; the 12 chunks read are the poorest window in defect terms, which is why the ratio falls even below 12/48.
  • When the same 2400 lines are read in four windows, found rises to 22, ratio to 0.917. What determines this is not line count but the number of chunks read.
  • The 2 missed defects stay the same at every size and in every window: unwritten requirement. Neither shrinking the size nor splitting shows what was never written.
  • Approval is not proof of having been read; an unread chunk produces no feedback, and two reviews look the same from outside.

Next Step

When a change is a reviewable size, the reviewer finds 22 defects. But a found defect is not a fixed defect: the gap between them is closed by a review comment, and what the comment says determines how many review rounds it takes to close the defect. The next lesson measures the same 22 findings written two ways — a note stating what should change and why against a note that only says what was seen — and which note form forces a change to close with the defect still open.

To keep your progress and take notes, Log in

My notes

Log in to take notes.

Start typing to search.

↑↓ Esc navigate · open · close