Skip to content
academia.sh

Lesson 01 / 15

Purpose of Code Review

On the same change, three reviewers on the same axis find 6 defects, three reviewers on separate axes find 15, a single reviewer on five axes finds 22; five reviewers on five axes also find 22, and two unwritten-requirement defects escape all four of the four configurations.

Contents

The Advanced Git course worked with a single unit across twelve lessons: the number of objects an operation touched. Rewriting touched 5640 objects, binary search finished in eleven steps, a hook placed a barrier early or late. The closing lesson left a question those numbers could not answer: the tool changes history, a human makes the decision. Knowing a transformation’s cost does not say whether that transformation should happen.

This course looks at where the decision gets made, and the unit measured changes. There, what was counted was what the tool touched; here, what is counted is where a human looks — and what is left outside that. The question itself changes too: not how many people read a change, but what that reading finds and what it fails to find.

The Three Jobs of Review

Code review is a change being read by someone who did not write it, before it is merged, and that reading being put on record. It has three jobs, and the three are not the same thing.

The first is finding defects: seeing something incorrect in a submitted change before it is merged. The second is spreading knowledge: preventing a change from being known only to its author; the reader becomes a second owner of that code. The third is design alignment: checking whether the change stays pointed the same direction as the rest of the repository.

What this course measures is the first, because it is the one that can be counted. But the three are not independent of each other: the review axis concept established in the next section applies to all three at once. Who looks at which axis determines the defect found, the knowledge spread, and the level at which alignment happens, all at once.

The mechanics of a change request — proposal, discussion, the merge cycle — were established in the Branching and Collaboration course, and the review axis was explicitly left for here; it is not repeated. Reading with a security eye is the subject of the Secure Coding course, and security is not on this course’s axis list. The organizational discussion of team structure and decision rights belongs to the Process, Team, and Delivery course. What is left here is only review’s own numbers.

Two Limits: Axis and Attention

A reviewer is not unlimited. They work with two limits, and every measurement in this course is built on these two.

Axis: a reading does not look at everything at once. The eye looking at the interface searches for the signature, the naming, and the contract; the eye looking at the implementation searches for loop boundaries and edge cases; the eye looking at the test checks whether the assertion actually verifies something. Two eyes passing over the same line see two separate defects, because they are searching for two separate things. This course defines five axes: interface, implementation, test, documentation, style.

Attention: a reviewer reads a limited amount of text in one round. The unit of reading is called a chunk, and a chunk is fifty lines. The number of chunks actually read in one round is fixed; if the change is larger than that, the rest goes unread. In this lesson’s measurement, the change is exactly the size of the attention budget, so no defect in this lesson goes unread. Every defect that is missed will have a single cause: an axis not looked at.

What the Five Axes Search For

The axes are not abstract; each asks a specific question and writes its finding in a specific form. The notes below are the product of five readings looking at the same change from five separate axes.

# taught review-comment example, not executed

interface       Second parameter of the public function has become required;
                code calling with the previous signature no longer compiles.
                Giving a default value would preserve the contract.
implementation  Loop reads the last element when the list is empty; an early
                return is needed for empty input.
test            Test's only assertion is that the call does not throw; there
                is no assertion verifying the return value.
documentation   The behavior the function's description states has changed;
                the comment line describes the old behavior.
style           Indentation is used at two different widths in this file.

This block is an example and is not run; this lesson’s numbers come only from the measurement block. The notes share something in common: all five point at a specific spot in the change and say what would close it. None of them mentions a person. This is a boundary kept throughout the course — review reads the submitted change, not its author.

Their second shared trait is that none can substitute for another. The interface note cannot be written without looking at the signature; the eye writing the style note is not searching for a loop boundary. Two defects sitting in the same line range of the same file require separate readings, because they belong to separate axes. The measurement’s table is the numeric counterpart of this independence.

Spreading knowledge and design alignment carry the same dependency. Someone who reads a change only along the style axis does not become that code’s second owner; they learn the indentation, not the behavior. Likewise, design alignment can only be seen from the interface and implementation axes. Axis choice therefore determines all three of review’s jobs at once.

The Defect of What Was Never Written

Outside the five axes there is a sixth defect class, and it is the setup’s most important part: unwritten requirement. This is not a wrong line inside the change; it is what should have existed but was never written at all.

For an interface defect, the signature is looked at; for a test defect, the assertion is looked at. For an unwritten requirement there is no place to look, because that requirement does not exist as text inside the change. Review looks at what was submitted; it cannot see the absence of what was never submitted. This is not an attention problem either: that class is not on the axis list.

The Measurement’s Setup

The measurement is built on one change with 24 defects scattered through it. Each defect belongs to one of six classes. The oracle is the setup itself: because we placed the defects ourselves, which chunk and which class each one belongs to is known. Four configurations look at the same change, and for each one, found and missed are written together.

  • RA1 — The change is 600 lines, meaning 12 chunks; attention is also 12 chunks. The entire change is read, and no chunk goes unread throughout this lesson.
  • RA2 — 24 defects are distributed across six classes by the setup; the class list and the distribution are the course’s constant and are not changed in any lesson.
  • RA3 — A reviewer sees only the defects on their own axes. A defect outside the axis is not found even if the line has been passed over.
  • RA4 — Multiple reviewers’ findings are a union: if two people find the same defect, it is counted once. The difference between configurations is therefore not the number of people, it is the set of axes covered.
  • RA5 — Two reviewers looking at the same axis find the same set. The setup includes no finding share where the second person completes the first; this is a deliberate simplification and ties the measurement’s result to a single thing: axis diversity.
  • RA6 — The sixth class is on no axis’s search list. This is not a gap, it is a definition.
  • RA7 — The measurement has no round, wait, or feedback-writing; those are the next topics’ variables. Here, a single reading in a single round is counted.
  • RA8 — In a 24-defect set, the smallest measurable difference is 1/24, that is, 0.042. A difference smaller than this cannot be defended with this set.

Measurement

"""Purpose of code review: reviewer count or axis count.

Part 1 - the change and the defects' class distribution.
Part 2 - four configurations: found, missed, missed that no axis looks for.
"""
SEED = 20260815
AXES = ("interface", "implementation", "test", "documentation", "style")
UNWRITTEN = "unwritten requirement"      # not searched by any axis
CLASSES = AXES + (UNWRITTEN,)
ATTENTION = 12                           # chunks actually read in one round
CHUNK = 50                               # lines


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

    def draw(n):
        nonlocal state
        state = (state * 48271) % 2147483647
        return state % n
    return draw


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


def review(d, axes, attention=ATTENTION):
    """A reviewer: sees only in their own axis and only the chunks they read."""
    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


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)
distribution = {s: sum(1 for k in d["defects"] if k["class"] == s) for s in CLASSES}
print(f"change {d['lines']} lines, {d['chunks']} chunks, "
      f"defects {len(d['defects'])}, attention {ATTENTION} chunks")
print("class distribution: " + ", ".join(f"{s} {n}" for s, n in distribution.items()))
print()
print(f"{'assignment':<32s} {'axes':>5s} {'reviewers':>9s} {'found':>7s} "
      f"{'missed':>6s} {'unwritten missed':>16s}")
for name, assignment in ASSIGNMENTS.items():
    b = panel(d, assignment)
    missed = [k for k in d["defects"] if k["no"] not in b]
    unwritten = sum(1 for k in missed if k["class"] == UNWRITTEN)
    axes = len(set().union(*assignment))
    print(f"{name:<32s} {axes:5d} {len(assignment):9d} {len(b):7d} "
          f"{len(missed):6d} {unwritten:16d}")
change 600 lines, 12 chunks, defects 24, attention 12 chunks
class distribution: interface 3, implementation 6, test 3, documentation 3, style 7, unwritten requirement 2

assignment                        axes reviewers   found missed unwritten missed
one reviewer, all axes               5         1      22      2                2
three reviewers, same axis           1         3       6     18                2
three reviewers, separate axes       4         3      15      9                2
five reviewers, five axes            5         5      22      2                2

The Number Does Not Track Reviewer Count

Two of the table’s columns sit side by side, and the found column tracks only one of them.

Reviewer count is 1, 3, 3, 5; defects found are 22, 6, 15, 22. There is no regular relationship between them: one person finds 22, three find 6, five find 22 again.

Axis count is 5, 1, 4, 5; defects found are 22, 6, 15, 22. This column explains what was found, row by row. Five axes give 22, four give 15, one gives 6. This is where the course’s measure comes from: a review’s number is not how many people are looking, it is how many axes are being looked at.

The second and fourth rows say this on their own. Three reviewers on the same axis find 6 defects; all three look at the implementation and there are 6 defects in the implementation class. The second and third people add not a single defect to the first, because they are searching for the same thing. In contrast, a single reviewer looking at five axes finds 22, and five reviewers spread across five axes also find 22. There is a 0 difference between five people and one. This is the second claim: adding reviewers does not find defects; adding axes does.

The third row gives the value in between. Three reviewers cover four axes — one on the interface, one on the implementation, one on both test and documentation — and 15 defects come out. Of the 9 missed defects, 7 are in the style class; no one is looking at that axis. This is the clearest evidence that it is adding axes, not adding people, that works: the same three people find 15 instead of 6 once the axes are spread out. The difference is 9 defects, more than twenty times the set’s resolution.

The Distribution Is Itself a Result

The second line of the output is information that comes before the measurement, but it deserves to be read on its own: style 7, implementation 6, interface 3, test 3, documentation 3, unwritten requirement 2.

The most crowded class is style, holding 7 of the 24 defects, or 0.292 of them. This number explains why the most-noted thing in a review is so often style: a style defect is both more numerous and requires the least information to see. Next comes implementation, with 6 defects, and this class is the opposite — seeing it requires understanding what the code does.

The remaining three axes — interface, test, documentation — each carry 3 defects, totaling 9. All three together are fewer than style and implementation combined; yet all three are classes that require a separate reading, and none is found as a byproduct of another.

The distribution’s practical consequence is the subject of later lessons. If a review spends its attention on the crowded but cheap class, the share left for the expensive classes shrinks; the total found does not show this, but the per-class breakdown does. This is why this course writes found and missed together in every measurement, and why the missed defects’ class is counted separately.

Two Defects Missed in All Four

The last column gives the same value in all four rows: 2.

These two defects belong to the unwritten-requirement class, and they are missed no matter what the configuration is. Whether a single reviewer looks at five axes or five reviewers spread across five axes, they are missed. The missed count drops to 2 and stops there — because no place to look was ever created for the remaining two defects.

This gives the fourth reading: no axis sees the unwritten. Adding an axis raises the found count up to 22; it does not raise it to 24. Putting more people into the review, spreading more axes, or having the same change read a second time will not find these two defects. They can only be caught somewhere outside review — where the requirement gets written.

Where the two defects can be caught is known, and it is before review: where the requirement is written, where the acceptance criterion is set, and where the change’s scope is decided. A single sentence placed there can eliminate a defect review cannot find with any axis. This is why this course’s numbers say not only how good a review is, but also what it can never see.

This is not a defect of review, it is the definition of its limit. A review saying “I found nothing” does not mean the change is correct; it means nothing was found in what was submitted, on the axes looked at. This sentence has three conditions, and all three stand as separate columns in the table.

Summary

  • Review has three jobs — finding defects, spreading knowledge, design alignment — and the thing that determines all three at once is who looks at which axis.
  • A reviewer works with two limits: axis limits them to seeing only the class they search for, attention limits the number of chunks they read in one round. In this lesson the change is exactly the size of the attention budget, so every missed defect’s cause is the axis alone.
  • On the same change, three reviewers on the same axis find 6, three reviewers on separate axes find 15, a single reviewer on five axes finds 22; five reviewers on five axes also find 22. Adding reviewers does not find defects, adding axes does.
  • Two unwritten requirement defects are missed in all four of the four configurations; that class is on no axis list, and review cannot see the absence of what was never submitted.
  • The class distribution is not even: style 7, implementation 6, interface, test, and documentation 3 each. The most crowded class is the one that requires the least information to see.
  • The found count tops out at 22/24 in the best case; the remaining 2 defects are not review’s problem, they are the problem of where the requirement gets written.

Next Step

The table’s single-axis row gave 6 defects, and that axis was implementation. Each of the five axes carries its own share, and the shares are separate from one another: what one axis finds, no other axis finds. The next lesson measures this separateness on the first axis, the interface axis: how does review notice a change that breaks a public interface’s contract, how many axes can see that finding, and how many defects are lost if someone looking at a different axis replaces the reviewer looking at the interface.

To keep your progress and take notes, Log in

My notes

Log in to take notes.

Start typing to search.

↑↓ Esc navigate · open · close