Week 3 Studio: Where is the denominator?
Percent of what? Build the same upload twice — counted in bytes, counted in stages — and measure where the two disagree.
11 March 2027
Take the case from week 1 again: 40 MB, 99% in nine seconds, then eleven seconds of nothing.
Here is one ordinary explanation. The bar was counting bytes handed to the network stack. All 40 MB were handed over in nine seconds, because the machine was on a fast connection and the bytes went into a buffer. The eleven seconds were the server hashing the file and writing it. The bar had no denominator for that, so it stopped at 99% and waited — which is the interface admitting, in the only vocabulary it had, that its denominator had run out.
The bar was not lying. It was answering a different question from the one the user was asking.
By the end of this week#
You can:
- name the denominator behind any percentage in a waiting interface, or show that there isn’t one;
- implement byte-counted and stage-counted progress over the same process and measure where they diverge;
- state what a chosen denominator excludes, in a sentence a user could read;
- choose a denominator and defend the choice against the specific way it will mislead.
The idea#
No lecture this week. This section and the 14:00 framing are the teaching.
A percentage is a fraction, and a fraction needs both numbers. Interfaces are usually careful about the numerator and careless about the denominator, which is how you get a bar that is accurate and useless at the same time.
Byte-counted. loaded / total, straight from the platform. Cheap, smooth,
updates often. It excludes everything that is not transfer — hashing,
validation, virus scanning, thumbnailing, durability. On a fast connection
uploading to a slow service, the excluded part is most of the wait.
Stage-counted. stagesCompleted / stagesTotal, from the state model you
built in week 2. Covers the whole process,
including the parts bytes cannot see. It moves in lurches, and it silently
assumes all stages are the same size, which they never are.
Weighted stages are the obvious third option, and they are honest only if the weights come from measurement. A weight you guessed is a number with no source event, which puts it straight into your week 10 register.
The platform is unusually direct about this. A browser progress event carries
a lengthComputable flag, and when it is false, total is meaningless. Most
code reads total without checking. That flag is the platform telling you
whether you have a denominator at all, and it is the subject of
week 4.
View this week’s slides — the 14:00 framing runs from these. They carry the worked example and the exercise brief. On a phone they are small — the deck is built for a projector, and this page carries the same material as prose.
In the room#
Thursday 11 March, 14:00–17:00. No lecture this week.
| Time | What happens |
|---|---|
| 14:00 | Framing (25 min). Denominators, and the exclusion each one hides. Worked on the week 1 case: which denominator makes that interface’s behaviour correct, and which makes it wrong? |
| 14:25 | Build. Two bars, one transfer. |
| 16:00 | Measure. Find the moment the two readings are furthest apart. Write the number on the board. |
| 16:30 | Compare. The spread of numbers across the room is the point — same simulator, same transfer, different models. |
What you start with#
- Your state enumeration and debug readout from week 2.
trace-office-wifi.json, a recorded 60 MB transfer shipped with the prototype, and the replay harness that drives the simulator from it.- A byte-counted bar already wired to the transfer events.
What you build#
- Two bars over one simulated upload: bytes transferred over bytes total, and stages completed over stages known. Both visible at once, both driven by the same run.
- A log of both readings on one timeline, at whatever interval is useful.
- The disagreement number: the largest gap between the two readings during a run, in percentage points, and the moment it occurred.
- A shipping decision: which denominator your prototype uses from now on, stated on screen along with what it excludes.
A worked example#
Both readings from one replay of trace-office-wifi.json, logged on one
timeline:
| t | byte-counted | stage-counted | gap |
|---|---|---|---|
| 4 s | 31% | 25% | 6 |
| 9 s | 74% | 50% | 24 |
| 14 s | 99% | 50% | 49 |
| 21 s | 99% | 75% | 24 |
| 32 s | 100% | 100% | 0 |
Largest disagreement: 49 points at t = 14 s — the moment the bytes finished and verification had not started reporting. That is the 99% pause, in numbers.
Recorded sample data shipped with the course, not a live capture.
Done when#
- Both bars run from one press of Start, and neither is faked from a timer.
- You can state the largest disagreement as a number and say when it happened.
- Your on-screen denominator statement is specific: “bytes sent, which excludes server-side verification” rather than “upload progress”.
The mistake to expect#
Writing the exclusion as a category instead of a consequence.
“Shows upload progress.” — says nothing
“Percentage of transfer.” — still a category
“Bytes sent. Does not include the server-side check, which on this trace took a further eleven seconds.” — a consequence
The test: could a waiting user predict the 99% pause from your sentence? If not, it is decoration.
Before next week#
About two hours.
- Repeat the measurement with the simulator’s slow-network preset. The disagreement usually shrinks, and being able to say why is week 5’s groundwork.
- Find one real interface where you can tell the denominator has run out — a bar that stalls near the end is the usual tell — and write two sentences on what you think it was counting.
If you are joining late#
git checkout stage-03 gives you a prototype with a state enumeration and a
working simulator, and a single byte-counted bar. It is a floor, not an answer:
the stage-counted bar, the log and the decision are yours.
What this week cannot tell you#
Which denominator is right.
There is no measurement in this exercise that settles it, because “right” depends on what the user is waiting to find out, and you have not asked one. What this week gives you is sharper: the knowledge of what each denominator omits, and a number for how much that omission is worth on your own simulated transfer.
The first time anybody other than you reacts to the choice is week 11.
Reading
- ProgressEvent.lengthComputable — MDN
Two paragraphs holding the whole of this week's question: the platform hands you a boolean saying whether a denominator exists, and total is meaningless when it is false.
- XMLHttpRequest: progress event — MDN
What a browser actually reports during an upload, at what granularity. Note what is not in it: nothing about what the server does after receiving the bytes.
The spec
What you bring to the session. Written so a reader can tell whether it has been met without asking you.
- a byte-counted bar and a stage-counted bar run against the same simulated upload
- both readings are logged on the same timeline, and the largest disagreement between them is recorded as a number
- the page states which denominator the prototype ships with, and names what that denominator excludes
Teaching team
- Idris Fenn — tutor