unrust

Skill guide

What is code tracing?

Published · Updated

Published by Unrust. Scoring and editorial method

Quick answer

Code tracing is the process of simulating a program's execution one step at a time so you can predict what it will do before you run it. You follow values through assignments, branches, loops, function calls, and mutations. It is especially useful when code looks plausible but the state changes somewhere unexpected. The habit is not about avoiding execution forever; it gives you a hypothesis to test and makes debugger output easier to interpret.

Trace state, not just lines

Reading top to bottom is not enough. A useful trace records the values that can change the outcome: variables, collection contents, a loop counter, a return value, and whether two names point at the same object.

On a small example, write a tiny table. After each meaningful line, note what changed. That discipline catches the moment where an assumption stops matching the code.

Worked example: a loop with continue

Predict total before reading the table. Start at zero and record the branch decision before changing the accumulator. The value 5 takes continue, so that iteration never reaches the addition.

JavaScript: a loop with a skipped iteration
let total = 0;
for (const value of [2, 5, 4]) {
  if (value > 4) continue;
  total += value;
}
Trace table: total after each iteration
Iterationvaluevalue > 4Actiontotal
StartNot assignedNot evaluatedInitialize0
12falseAdd 22
25trueSkip addition2
34falseAdd 46

Worked example: an alias is not a copy

Assigning an array to another variable keeps a reference to the same array. A spread copy makes a new outer array. In this example the elements are numbers, so changing copy[0] cannot change original[0]. With nested objects, the copy would still share those inner objects.

JavaScript: shared reference versus shallow copy
const original = [8, 3];
const alias = original;
const copy = [...original];
alias.push(5);
copy[0] = 1;
// original: [8, 3, 5]
// alias:    [8, 3, 5]
// copy:     [1, 3]
State after each mutation
After statementoriginalaliascopy
const copy = [...original][8, 3][8, 3][8, 3]
alias.push(5)[8, 3, 5][8, 3, 5][8, 3]
copy[0] = 1[8, 3, 5][8, 3, 5][1, 3]

Use execution to check a prediction

Running code is not a failure of reasoning. The useful sequence is predict, run, compare, and explain the difference. If the program surprises you, do not stop at the output. Find the exact state transition you failed to model.

This turns a one-off debugging session into a reusable mental model. Over time you need fewer full traces, but the discipline remains available when code gets strange.

Interactive reasoning check

Predict the final total

In the loop above, what is the value of total after the loop finishes?
Read the reasoning without answering

The continue statement skips the rest of the current iteration and jumps to the next one. Here it skips total += value whenever value > 4, so only 2 and 4 contribute to the total.

A small practice loop

  1. 01Take a function under fifteen lines and predict its return value before running it.
  2. 02Record the state after every assignment, branch, and mutation that can affect the result.
  3. 03Run the code, then explain the first step where your prediction and the actual execution diverged.

Common questions

Is code tracing the same as using a debugger?

No. A debugger observes real execution. Tracing is your mental model of execution. Used together, they are stronger: predict first, then use the debugger to check the state transition you were unsure about.

What should I write down while tracing code?

Write down the state that changes the result: variable values, collection contents, aliases or references, loop counters, branch conditions, and return values. Ignore lines that do not change relevant state.

Sources and scope

  • JavaScript array semantics

    MDN

    Reference for array copying and mutation. The examples and trace tables here are original teaching material.

Check your own starting point

Unrust uses short, timed, unassisted drills to give developers a per-skill snapshot. One session cannot explain the cause of a result, but it can show you what is worth practicing next.

Take the free diagnostic