---
title: 'Code Style and Automation'
source: 'https://academia.sh/en/courses/code-review/code-style-and-automation'
course: 'Code Review and Team Process'
language: en
updated: '2026-08-17T18:10:45+00:00'
license: 'CC BY-SA 4.0'
---

# Code Style and Automation

Once the style axis is handed to a tool, the human's finding drops from 22 to 15 and its style share from 0.318 to 0.000; the total stays the same if all five axes were already covered, and climbs from 15 to 22 in a three-reviewer panel.

The previous lesson's table gave its most expensive closure as the style axis: closing
it missed **7** defects and found dropped to **15**. The same axis was also the most
crowded class in the first lesson's class distribution, where a note was made — that
this class requires the least information to see.

The two traits together set this axis apart from the others and open a question: **does
this axis require a human's reading at all.** The lesson measures that question. The
style axis is handed to a tool, and three things are counted: what the total found
becomes, how much the human's own finding shrinks, and which classes that finding is
made up of.

## What the Style Axis Searches For

The style axis looks at the code's **appearance**: indentation width and consistency,
line length, whitespace placement, bracket position, import order, the case convention
of names, trailing whitespace, end-of-file newline.

There is something missing from this list, and the distinction sits inside the course:
**choosing a name** is not the style axis's job. Whether a name is meaningful is a
judgment and is read on the implementation axis; which case convention that name is
written in is a rule and is read on the style axis. Naming itself is the subject of the
Clean Code course and is not repeated here.

The part that enters the measurement is one sentence: **what determines a style
defect's correctness is not a judgment, it is a writable rule.** A rule that can be
written can be applied, and a rule that can be applied can be handed off. None of the
other four axes carries this trait: whether a signature breaks a contract, whether a
body is correct, whether an assertion is meaningful, and whether a text contradicts the
code all require judgment, not a rule.

## The Decision Itself and Applying the Decision

A style discussion is two separate jobs, and confusing them is what burns the most
rounds.

**The first job is the decision itself:** which indentation width, which line length,
which ordering. This is given once and written into a text. The decision is not
inherently right or wrong on its own; its value lies in consistency.

**The second job is applying the decision:** checking, on every change, whether the
rule was actually applied. This job is redone on every change and involves no judgment;
the rule's text is compared against the code's text.

What gets handed off is the second job. A **formatter** applies the rule to the code; a
**linter** reports where it was not applied. Both are a tool class and make no decision
— they carry out a rule already given to them. How these tools are wired in is the
subject of the Continuous Integration and Delivery course, and how they are set up in
frontend projects is the subject of the Frontend Quality course; neither is repeated
here. The only thing measured here is **what is left in review after the handoff.**

Skipping this distinction shows a single symptom in practice: the same style issue gets
re-argued from change to change. What is argued is, on the surface, a line of code; in
reality, it is a decision that was never written down.

Writing the rule therefore comes before setting up the tool, and is independent of it. A
written rule ends the argument even without a tool: the finding is no longer a
preference, it is a reference to a text, and the tool only adds execution on top of
that. The reverse order does not work — installing a tool in a repository with no rule
hands the decision over to the tool's settings, and the argument moves to the
configuration and continues there.

```text
# taught review-comment example, not executed

before handoff
  style   Indentation is used at two different widths in this file.
  style   Line length is over the limit in four places.
  style   Import order differs from the rest of the file.

after handoff
  (no review note on the style axis; the rule is now written into the tool)
  interface  Second parameter of the public function has become required.
  test       Test's only assertion is that the call does not throw.
```

This block is an example and is not run; the lesson's numbers come only from the
measurement block.

## The Tool's Two Differences

The tool entering the measurement differs from a reviewer at two points.

**It is single-axis.** It looks only at the style class and finds nothing from the
other four classes. The rule is the one axis that can be written; the tool has no
counterpart on the axes that require judgment.

**It has no attention.** A reviewer reads a limited number of chunks in one round; the
tool reads the entire change, and that limit does not apply to it. At this lesson's
scale the two limits coincide — the change is 12 chunks, attention is also 12 chunks —
so the difference does not show up in the numbers. The condition of the difference is
still known, though, and it is outside this topic.

## The Measurement's Assumptions

- **RA39** — The shared setup is unchanged: 600 lines, 12 chunks, 24 defects, attention
  12 chunks. The class list and distribution do not change.
- **RA40** — The tool finds only defects in the style class, and finds all of them; the
  chunk limit does not apply to it.
- **RA41** — The tool produces no false finding. The setup does not include the tool
  counting something outside the rule as a defect; the measurement is therefore in the
  tool's favor, and this is stated explicitly.
- **RA42** — In the "without tool" column the human can carry all five axes; in the
  "with tool" column no reviewer carries the style axis.
- **RA43** — Reviewer count is held the same in both regimes; the handoff adds no one
  to the panel and removes no one.
- **RA44** — The tool does not count as a reading and does not enter the reviewer
  column; its finding sits in a separate column.
- **RA45** — The cost of the handoff — writing the rule, setting up the tool, wiring the
  pipeline — is not in the measurement. The only thing measured is found and missed
  defects.
- **RA46** — The ratio is the style defect count in the human's finding divided by the
  human's total finding. Resolution at the defect level is **1/24 = 0.042**.

## Measurement

```python
"""Code style and automation: what changes when the style axis is handed to a tool.

Part 1 - the same panels without and with the tool; the human's find and the total found.
Part 2 - the class distribution of the human's finding in the two regimes.
"""
SEED = 20260815
AXES = ("interface", "implementation", "test", "documentation", "style")
UNWRITTEN = "unwritten requirement"
CLASSES = AXES + (UNWRITTEN,)
ATTENTION = 12
CHUNK = 50


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):
    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 formatter(d):
    """The tool class: only looks at the style axis, no attention limit."""
    return {k["no"] for k in d["defects"] if k["class"] == "style"}


FULL = set(AXES)
HUMAN = FULL - {"style"}
d = change(600)
tool = formatter(d)

PANELS = {
    "one reviewer": ([FULL], [HUMAN]),
    "three reviewers, separate axes": ([{"interface"}, {"implementation"},
                                        {"test", "documentation"}],
                                       [{"interface"}, {"implementation"},
                                        {"test", "documentation"}]),
    "three reviewers, same axis": ([{"implementation"}] * 3,
                                    [{"implementation"}] * 3),
    "five reviewers, five axes": ([{a} for a in AXES],
                                   [{a} for a in sorted(HUMAN)] + [HUMAN]),
}
print(f"{'panel':<32s} {'without tool found':>18s} {'with tool: human':>16s} "
      f"{'tool':>4s} {'total':>6s} {'missed':>6s}")
for name, (a, b) in PANELS.items():
    plain = panel(d, a)
    human = panel(d, b)
    total = human | tool
    missed = [k for k in d["defects"] if k["no"] not in total]
    print(f"{name:<32s} {len(plain):18d} {len(human):16d} {len(tool):4d} "
          f"{len(total):6d} {len(missed):6d}")

print()
print(f"{'regime':<20s} {'human found':>12s} "
      f"{'style share':>11s} {'ratio':>5s}")
for name, axes in (("style with human", FULL), ("style with tool", HUMAN)):
    b = review(d, axes)
    style = sum(1 for k in d["defects"]
                if k["no"] in b and k["class"] == "style")
    print(f"{name:<20s} {len(b):12d} {style:11d} {style / len(b):5.3f}")
remaining = sorted({k["class"] for k in d["defects"]
                    if k["no"] in review(d, HUMAN)})
print("classes of human's finding while style is with tool: " + ", ".join(remaining))
total = review(d, HUMAN) | tool
missed = [k for k in d["defects"] if k["no"] not in total]
print(f"human plus tool: found {len(total)}, missed {len(missed)}, "
      f"no axis searches for "
      f"{sum(1 for k in missed if k['class'] == UNWRITTEN)}")
```

```
panel                            without tool found with tool: human tool  total missed
one reviewer                                     22               15    7     22      2
three reviewers, separate axes                   15               15    7     22      2
three reviewers, same axis                        6                6    7     13     11
five reviewers, five axes                        22               15    7     22      2

regime                human found style share ratio
style with human               22           7 0.318
style with tool                15           0 0.000
classes of human's finding while style is with tool: documentation, implementation, interface, test
human plus tool: found 22, missed 2, no axis searches for 2
```

## When the Tool Changes the Total

The top table's first and last rows say the same thing: **22 and 22.** If all five axes
were already covered by humans, the tool's contribution to the total found is **0**.
The tool does not look anywhere no one was already looking.

The second row shows the reverse. Three reviewers covered four axes — interface,
implementation, test, documentation — and found **15** without the tool. Once the style
axis is handed to the tool, the total climbs to **22**. No one was added to the panel or
removed; the one axis that was not covered got covered, at a cost of **7** defects. **A
three-person panel got matched to a five-person panel's number.**

The third row repeats the same rule on the narrowest panel. Three reviewers were looking
at the same axis and finding **6**; the tool raises this to **13**. Missed is still
**11**, and **9** of that comes from the three axes no human is looking at. The tool
closes one axis; it does not close the others.

The pattern comes together in one sentence: **the tool's contribution equals the size
of the axis the humans did not cover.** This is the axis side of the course's second
claim — the tool behaves like a person too: what grows the number is not its presence,
it is that the axis it covers had not been covered before.

**When** the tool's contribution happens does not show in the table but changes the
review. The tool runs the moment the change is submitted, and the seven defects it finds
are closed before review even begins: no note gets written, no reply is expected. Even
in rows where the total stays the same, the review's **subject matter** shrinks, and the
part that shrinks is exactly the part that required no judgment.

The last column carries the sixth class in all four rows. In the best case with the
tool, missed is **2**, and both are in the unwritten-requirement class.
**Automation does not raise the ceiling of found above 22.** The tool looks at what was
written, just like review; what was never written, it too cannot see.

## Where Attention Shifts

The bottom table looks at the same handoff from the human's side, and the numbers here
change even in the rows where the total stayed fixed.

With style on the human, a single reviewer's finding is **22** defects and **7** of that
is in the style class; the ratio is **0.318**. With style on the tool, the human's
finding drops to **15** and the style share is **0**; the ratio is **0.000**. The
human's finding is left with four classes: interface, documentation, implementation,
test.

What changes is not the total, it is **the content of the review.** Before the handoff,
about a third of a review's findings are rule defects; after, it is zero. Every
remaining finding comes from an axis requiring judgment, and what gets discussed in the
review text shrinks in the same proportion: applying the rule is no longer up for
discussion, because the text deciding it was written once and its application is now
carried out on its own.

There is an honest limit here that needs to be stated. At this scale, the freed reading
has **no** numeric return: the change is 12 chunks, attention is also 12 chunks, so the
human's reading was not being exhausted to begin with. Redirecting the attention freed
from the style axis to another axis changes no number, because the other axes were
already being read in full. For the freed attention's counterpart to show, a single
condition is required: **what there is to read has to be larger than the attention
budget.** No such case has been built in this setup, and it is not this topic's
variable.

## Two Assumptions Built in the Tool's Favor

The measurement holds the tool stronger than it might be in reality at two points, and
both affect how the result should be read.

**The tool finds the entire style class.** A formatter applies only the rules written
for it; a style defect outside the rule set — a file layout that differs from the rest
of the repository, an inconsistent abbreviation style — is invisible to it and stays
with the human. The measurement has no such remainder; if it did, the "style share
0.000" row would have come out above zero.

**The tool produces no false finding.** When the rule set does not match the rest of
the repository, the tool also reports spots that are not defects. These findings do not
enter review, but they cost time and require the rule to be rewritten, and this cost is
not included.

Both assumptions are set deliberately. The purpose is to show that even **in the tool's
best case**, the total stays at **22**: what sets the ceiling is not the tool's quality,
it is the axis list itself.

## Summary

- The style axis looks at the code's appearance and separates from the other four at
  one point: what determines its correctness is not a judgment but a **writable rule**.
  Choosing a name is not on this axis; the case convention of a name is.
- A style discussion is two jobs: **the decision itself** is given once and written into
  a text, **applying the decision** is repeated on every change. What gets handed to the
  tool is the second.
- The tool's contribution to total found equals the axis humans did not cover: **0** if
  five axes are already covered, **15** to **22** on a three-reviewer panel, **6** to
  **13** on three reviewers on the same axis.
- Automation does not raise the ceiling: missed in the tool's best case is **2**, and
  both are in the unwritten-requirement class. The tool too looks only at what was
  written.
- The handoff changes the review's content even where the total stays fixed: the
  human's finding goes from **22** to **15**, its style share from **0.318** to
  **0.000**, leaving only the four axes requiring judgment.
- At this scale, the freed attention's numeric return is **0**, because the change is
  not larger than the attention budget.

## Next Step

This topic's six lessons moved a single variable: **the axis looked at.** Raising axis
count pushed found from **6** to **15** and then to **22**; closing an axis cost exactly
the size of its class; adding people changed nothing. All these measurements shared one
silent assumption, and this lesson said it out loud: **the change was always exactly the
size of the attention budget**, meaning what there was to read
could be read.

The next topic lifts that assumption. The axis looked at is held fixed, and this time
**what there is to look at** grows. The question is this: do the defects axis diversity
earns stay in place once the change stops being fully readable, or does the found ratio
collapse independent of the axes?
