Skip to content
academia.sh

Lesson 10 / 15

Review Metrics

Three reviewers on the same axis produce 6 review rounds, 36 units of wait, and 3 remaining defects; one reviewer on five axes gives 2 rounds, 12 units, and 0 remaining, and the same gap turns into 2 versus 15 rounds of staying open in the review queue.

Contents

Three lessons arrived at the same two numbers. Change size set the chunks read and what was found; note style set how fast the found closed; the resolution rule set whether it closed at all. In all three, the result was a review round count and an amount of wait.

This lesson takes those two numbers directly as metrics and adds a third: what review does not to a single change but to the review queue. What is asked is this — what does each of these three numbers measure, which decision does it support, and what does it hide when read alone.

Three Metrics

Wait time is the span from the moment a change enters review to the moment it closes. In the shared fixture, every review round adds 6 units to wait; wait is a direct function of review round count.

Review round count is how many times a change goes back and forth before it closes. It has one source, and the previous three lessons showed it three separate ways: work that does not close in the first round. A defect not seen in the first round, a closing criterion not written, and an argument not resolved all land in the same place.

Review queue health is a metric not of a single change but of all changes open at the same time. A team’s review capacity is limited: only a certain number of changes can be reviewed at once. As every change takes more review rounds, capacity stays tied up longer and changes coming in behind it wait. Queue health shows whether this backlog is forming.

Why Metrics Are Not Reported Per Person

These three metrics are the process’s metrics, and they are not reported per person, because what produces every row of the table is not people’s effort but the axis assignment — three reviewers producing 6 review rounds happens even though all three do their job flawlessly.

The measurement’s second row proves this. There are three reviewers, all three find every defect on the axis they are responsible for, and the result is 6 of 24 defects. If a per-person number were produced, all three reviewers would look weak; yet the only thing that needs to change is that all three are looking at the same axis. When a metric is tied to the wrong subject, the fix goes to the wrong place too.

A second justification comes from the previous lesson. When note style changed, the number of defects found never changed — it stayed fixed at 22. That is, note count and defects-found count are independent of each other. In a system that reports note count per person, what grows is note count, not defects found.

The measurement’s assumptions:

  • RC20 — The shared fixture does not change: 600 lines, 12 chunks, 24 defects, fixed class distribution. The only thing that changes is the axis assignment.
  • RC21 — Four assignments are measured: one reviewer on all axes; three reviewers on the same axis; three reviewers on separate axes; five reviewers on five axes. Every reviewer’s attention is 12 chunks.
  • RC22 — Found defects are fixed in every review round; the remaining defect carries to the next round, and each round clears half of what was found. A change can stay open for at most 6 review rounds.
  • RC23 — One review round adds 6 units to wait, independent of assignment.
  • RC24 — In the review queue, one change enters per round; 12 changes enter in total. The team’s capacity is 3 simultaneous reviews.
  • RC25 — All changes in the queue are reviewed with the same assignment; this is why every one of them takes the same review round count.
  • RC26 — The queue measurement is tracked across 60 rounds; this span is enough for all changes to close in all four of the four assignments.
  • RC27 — The set’s resolution is 1/24 = 0.042 at 24 defects; wait and review round are counted per unit.

Measurement

"""Review metrics: found, review round, wait, and queue health.

Part 1 - what four axis assignments find and miss.
Part 2 - the same assignments' review round, wait, and remaining defects.
Part 3 - what the same rounds do to the review queue.
"""
SEED = 20260815
AXES = ("interface", "implementation", "test", "documentation", "style")
UNWRITTEN = "unwritten requirement"
CLASSES = AXES + (UNWRITTEN,)
ATTENTION = 12
CHUNK = 50
CAPACITY = 3          # changes reviewable at the same time
INCOMING = 12          # changes entering the queue during the measurement


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, attention=ATTENTION):
    read = set(range(min(attention, d["chunks"])))
    return {k["no"] for k in d["defects"]
            if k["class"] in axes and k["chunk"] in read}


def panel(d, assignments, attention=ATTENTION):
    found = set()
    for axes in assignments:
        found |= review(d, axes, attention)
    return found


def round_cycle(found, defect_count, wait_per_round=6):
    """Each round fixes what is found; the remainder carries to the next round."""
    remaining, rnd, wait = defect_count - len(found), 1, wait_per_round
    while remaining > 0 and rnd < 6:
        rnd += 1
        wait += wait_per_round
        remaining -= max(1, len(found) // 2)
    return rnd, wait, max(0, remaining)


def queue(rnd, incoming=INCOMING, capacity=CAPACITY, duration=60):
    """One change enters per round; at most `capacity` are reviewed at once."""
    pending, working, done, snapshot = [], {}, [], 0
    for t in range(1, duration + 1):
        if t <= incoming:
            pending.append(t)
        for no in [n for n, b in working.items() if b == t]:
            done.append((no, t))
            del working[no]
        while pending and len(working) < capacity:
            working[pending.pop(0)] = t + rnd
        if t == incoming:
            snapshot = len(pending) + len(working)
    return snapshot, max(b - g for g, b in done), max(b for _, b in done)


FULL = set(AXES)
ASSIGNMENTS = {
    "one reviewer, all axes": [FULL],
    "three reviewers, same axis": [{"implementation"}] * 3,
    "three reviewers, separate axes": [{"interface"}, {"implementation"},
                                        {"test", "documentation"}],
    "five reviewers, five axes": [{a} for a in AXES],
}
d = change(600)

print(f"{'assignment':<32s} {'reviewers':>9s} {'found':>7s} {'missed':>6s} "
      f"{'unwritten missed':>17s}")
for name, assignment in ASSIGNMENTS.items():
    b = panel(d, assignment)
    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"{name:<32s} {len(assignment):9d} {len(b):7d} {len(missed):6d} {unw:17d}")

print()
print(f"{'assignment':<32s} {'round':>5s} {'wait':>6s} {'remaining':>10s}")
for name, assignment in ASSIGNMENTS.items():
    rnd, wait, remaining = round_cycle(panel(d, assignment), len(d["defects"]))
    print(f"{name:<32s} {rnd:5d} {wait:6d} {remaining:10d}")

print()
print(f"review queue: one change enters per round, {INCOMING} changes, "
      f"capacity {CAPACITY}")
print(f"{'assignment':<32s} {'round':>5s} {'open at round 12':>17s} "
      f"{'longest open':>13s} {'last close':>11s}")
for name, assignment in ASSIGNMENTS.items():
    rnd = round_cycle(panel(d, assignment), len(d["defects"]))[0]
    snapshot, longest, last = queue(rnd)
    print(f"{name:<32s} {rnd:5d} {snapshot:17d} {longest:13d} {last:11d}")
assignment                       reviewers   found missed  unwritten missed
one reviewer, all axes                   1      22      2                 2
three reviewers, same axis               3       6     18                 2
three reviewers, separate axes           3      15      9                 2
five reviewers, five axes                5      22      2                 2

assignment                       round   wait  remaining
one reviewer, all axes               2     12          0
three reviewers, same axis           6     36          3
three reviewers, separate axes       3     18          0
five reviewers, five axes            2     12          0

review queue: one change enters per round, 12 changes, capacity 3
assignment                       round  open at round 12  longest open  last close
one reviewer, all axes               2                 2             2          14
three reviewers, same axis           6                 9            15          27
three reviewers, separate axes       3                 3             3          15
five reviewers, five axes            2                 2             2          14

What Lengthens the Round

Reading the first two tables side by side gives the topic’s conclusion. When three reviewers work the same axis, 6 defects are found, the process costs 6 review rounds and 36 units of wait, and 3 defects still remain in the end. When one reviewer looks at five axes, 22 defects are found, the process costs 2 review rounds and 12 units, remaining is 0.

The comparison matters because the second row has three times as many reviewers. Three people produce six times the wait and end up unable to deliver three defects; one person does the same job with a third of the wait, and flawlessly. What lengthens the review queue is not reviewer count, it is what goes unseen in the first round.

The link is straightforward arithmetic. If little is found in the first round, a lot of defects remain; the remaining defects clear in later rounds at only half the speed of what was found; so finding little means both more review rounds and defects left at the limit. When three reviewers spread across separate axes, 15 are found and the process closes at 3 rounds / 18 units: same three people, only the axis spread changed.

The rightmost missed column is 2 in every row. All four of the four configurations miss the two unwritten requirement defects. This number does not fall by adding reviewers or by adding axes — no axis searches for what was never written. In reading the metrics, this row serves as a floor: 2 of 24 defects sit where review can never reach, and a process’s target is 22. A reading that does not know the floor calls every review incomplete and sets an unreachable number as the goal; a metric’s ceiling is the ceiling of the process it measures.

The Health of the Queue

The third table shows what the same gap does outside a single change. The team is the same team, capacity is 3 simultaneous reviews, one change enters per round.

When review round count is 2, the queue is healthy: at round twelve only 2 changes are open, the longest open stays 2 rounds, and the last change closes at round 14. When review round count is 3, the system sits exactly at the limit — capacity 3, service time 3 — and the open count settles at 3.

When review round count is 6, the queue breaks down. At round twelve, 9 changes are open; the longest open climbs from 2 rounds to 15; the last change closes at round 27. On a single change the gap was 2 versus 6; in the queue it is 2 versus 15. Once capacity runs out, delay does not just add — it compounds.

A simple rule of queue health follows from this: the queue grows once review round count exceeds capacity. This has nothing to do with how many people are assigned to review, and everything to do with how many rounds a review takes to close — and the previous three lessons each showed, one by one, where that number comes from.

The arithmetic of the backlog is simple too. With capacity 3 and service time 6, the system can close at most 0.5 changes per round, while 1 change arrives per round. On top of that, the first closing cannot happen before round 7; of the 12 changes arrived by round twelve, only 3 have closed and 9 are open. Stopping the inflow does not erase this backlog right away: the last-arriving change reaches its turn at round 21 and closes at round 27. The queue does not recover at the speed it broke down.

What the Three Metrics Hide Alone

No metric is read alone, because each one can take the same value for two separate reasons.

Short wait can be a good sign or the sign of a change that was never read. In the change size lesson, a 2400-line review also got approved in a single round; defects found was 2. Read alone, wait makes this review look exemplary.

Few review rounds comes either from finding a lot in the first round or from finding nothing at all. What separates the two is the second table’s last column: remaining defects. In the disagreement lesson, the deferral rule gave 2 rounds / 12 units — the same as the table’s best row — but left 8 defects in the code.

A healthy queue comes either from reviews that close fast or from changes that never enter the queue at all. The remedy for all three is the same: metrics are read together with found and missed defects. This is why every table in this topic has carried both sides.

Which Metric Supports Which Decision

A metric’s value is only as good as the decision it supports. The three metrics look at three separate decisions and do not substitute for one another.

Review round count supports the axis-assignment decision. The second table gives this directly: the same three people produce 6 rounds on the same axis, 3 rounds on separate axes. When round count rises, the question to ask is not “who is slow,” it is which axis is going unlooked-at.

Wait time supports the change-size decision. Wait is six times the review round count, and what sets review round count is what gets found in the first round; what most reduces the first round’s find is the unread chunk. Lengthening wait is, most often, the sign of a change sent to review that does not fit inside attention.

Queue health supports the capacity decision. The third table shows the backlog starting exactly when service time exceeds capacity. The decision here runs two ways: either review round count is lowered, or simultaneous review capacity is raised. The two do not cost the same — the first is paid with axis spread and change size, the second with time taken from other work.

Read together, the table reduces to a single sentence: every fix that raises what is found also fixes wait and the queue. The measurement has no row that contradicts this; the two configurations that find the most are also the ones with the least wait and the healthiest queue.

Summary

  • The three metrics are the process’s metrics: wait time, review round count, and review queue health. They are not reported per person, because what produces their values is the axis assignment — three reviewers producing 6 review rounds happens even though all three do their job flawlessly.
  • Three reviewers on the same axis find 6 defects, cost 6 rounds / 36 units, and leave 3 remaining; one reviewer on five axes finds 22, costs 2 rounds / 12 units, leaves 0. Three times the reviewers, three times the wait.
  • What lengthens the review queue is not reviewer count but what goes unseen in the first round: finding little produces both more review rounds and defects left at the limit.
  • In a queue with capacity 3, the longest open is 2 rounds when review round count is 2, and 15 rounds when it is 6; open changes at round twelve rise from 2 to 9. Once capacity is exceeded, delay compounds.
  • All four of the four configurations miss the 2 unwritten requirement defects; this is the floor metrics are read against — the most review can ever reach is 22 of 24.
  • No metric is read alone: short wait, few review rounds, and a healthy queue can each take the same value in both the best and the worst case; what separates them is defects found and missed.

Next Step

In this topic, review always stayed around a single change: a change arrives, is read, notes are written, it closes. The third table took the first step outside that circle and showed changes waiting on one another. But what if the change itself is not a starting point but an element inside a longer chain? The next topic treats review as one stop on that chain: where the element stands before it reaches review and after it closes, and what share of the total time review holds.

To keep your progress and take notes, Log in

My notes

Log in to take notes.

Start typing to search.

↑↓ Esc navigate · open · close