2Lesson 2 of 4

How programs execute

Tracing the path from source code to results—and learning to verify logic written by any mind

Program testing can be a very effective way to show the presence of bugs, but it is hopelessly inadequate for showing their absence.

Edsger Dijkstra,The Humble Programmer (1972)
Conceptualize

Lesson 1 gave us a model: a computer remembers things and follows instructions. But what actually happens between the moment code is written and the moment results appear?

Most beginners think code runs “magically.” Type some JavaScript, hit run, something appears. This lesson builds a mental model of execution—what the computer actually does when it runs your code.

The execution model

When you run a program, the computer does three things:

  1. 1
    Parse — Read your source code, check it's valid (correct syntax, matching brackets)
  2. 2
    Execute — Follow instructions one at a time, top to bottom
  3. 3
    Output — Produce results (display something, save a file, send a network request)

By default, code runs top to bottom, one line at a time. This is called sequential execution. Think of it like reading a recipe—step 1, then step 2, then step 3.

This is a simplification. Real execution involves interpreters, compilers, bytecode, optimization passes, and more. We're ignoring all of that—on purpose. The sequential model is accurate enough for reasoning about program logic, which is what matters now.

🏭

Mental model: The assembly line

Imagine a factory with stations arranged in a row. At each station, a worker performs one specific task:

  • Station 1: Add wheels to the frame
  • Station 2: Attach the steering wheel
  • Station 3: Install the engine
  • Station 4: Paint the car

The product moves down the line, one station at a time, in order. You cannot paint before adding wheels. You cannot skip the engine and come back later.

Code execution works the same way. Each line is a station. The computer moves from one to the next, performing each operation in sequence.

Specify

Now that we have the conceptual model, let's get precise. By the end of this lesson, you should be able to answer:

  • 1.What are the only two ways to break sequential execution?
  • 2.How does the computer evaluate a conditional?
  • 3.How does the computer execute a loop?
  • 4.Given any simple program, can you trace through it and predict the output?

That last question is the real test. If you can trace execution, you can verify logic—regardless of which mind wrote the code.

Generate

Breaking the line: control flow

Most programs aren't straight lines. You need decisions (“if the user is logged in, show dashboard; otherwise, show login”) and repetition (“for each item in cart, calculate subtotal”).

There are exactly two ways to break sequential execution:

1. Conditionals (branching)

Take different paths based on a condition. Keywords: if, else, switch

2. Loops (repetition)

Repeat a block of code multiple times. Keywords: for, while, forEach

That's it. Every program is these patterns combined: sequential (do this, then that), conditional (sometimes do this instead), and loop (repeat this).

Conditionals: choosing a path

Think like the computer. When it reaches an if statement, it evaluates the condition. If true, run the first block. If false, run the else block (if one exists). Only one path executes.

let temperature = 75;
if (temperature > 80) {
console.log("It's hot outside!");
} else {
console.log("It's nice outside!");
}

Trace it. Temperature is 75. Check: is 75 > 80? No. Skip the first block. Run the else block. Output: “It's nice outside!”

This is computational empathy—putting yourself in the computer's position, following its logic step by step.

Loops: repeating work

Think like the computer again. A loop has three parts: initialization, condition check, and update. The computer checks the condition before each iteration. When the condition becomes false, it exits and continues.

for (let i = 1; i <= 3; i++) {
console.log("Iteration", i);
}
// Output:
// Iteration 1
// Iteration 2
// Iteration 3

Trace it step by step:

  1. Set i to 1. Check: 1 ≤ 3? Yes. Run block. Print “Iteration 1”.
  2. Increment i to 2. Check: 2 ≤ 3? Yes. Run block. Print “Iteration 2”.
  3. Increment i to 3. Check: 3 ≤ 3? Yes. Run block. Print “Iteration 3”.
  4. Increment i to 4. Check: 4 ≤ 3? No. Exit loop.

A more practical example—processing items:

let cart = ["apple", "banana", "orange"];
let total = 0;
for (let item of cart) {
console.log("Processing:", item);
total = total + 1;
}
console.log("Total items:", total);
// Processing: apple
// Processing: banana
// Processing: orange
// Total items: 3

A note on functions

There's one more control flow concept: functions. A function bundles code you want to reuse.

function greet(name) {
return "Hello, " + name;
}
console.log(greet("Alice")); // Hello, Alice

When the computer sees greet("Alice"), it jumps to the function definition, runs the code with name set to “Alice”, returns the result, and continues from where it was called.

We'll go deeper on functions later. For now: they affect control flow by “jumping” to the function body.

💡

Programs are deterministic

Given the same inputs, a program produces the same outputs. No randomness (unless you add it). If temperature is 75, the else block always runs. If you loop from 1 to 3, you get exactly 3 iterations. This is why tracing works—you're following the exact path the computer took.

Try it: trace this program

Before running, trace through mentally and predict the output:

let count = 0;
for (let i = 1; i <= 5; i++) {
if (i % 2 === 0) {
count = count + 1;
}
}
console.log(count);

Walk through it:

  • i = 1: Is 1 % 2 === 0? No (1 is odd). Skip. count stays 0.
  • i = 2: Is 2 % 2 === 0? Yes. Increment count to 1.
  • i = 3: Is 3 % 2 === 0? No. Skip. count stays 1.
  • i = 4: Is 4 % 2 === 0? Yes. Increment count to 2.
  • i = 5: Is 5 % 2 === 0? No. Skip. count stays 2.
  • Loop exits. Print count: 2

Now run it in your browser console to verify.

Critique

Now we stress-test the model. Where does it break down? What are we glossing over?

What this model doesn't explain

  • Asynchronous code — Real programs often wait for network requests or user input. Execution isn't always strictly top-to-bottom. We'll address this later.
  • Parallel execution — Modern computers run multiple instructions simultaneously. Our sequential model ignores this.
  • Optimization — Compilers and interpreters rearrange code for performance. The execution order you see isn't always what actually happens.

These are real complications. But for understanding logic—for tracing what a program should do—the sequential model works. It's a useful simplification, not the full truth.

Mind + mind: one writes, the other verifies

Here's where understanding execution becomes essential.

When minds collaborate on code—human and AI, or any combination—one often generates logic while another verifies it. Say the requirement is “send a reminder if the user hasn't logged in for 7 days.” One mind might generate:

if (daysSinceLogin > 7) {
sendReminderEmail();
}

Looks right. But trace it: if daysSinceLogin is exactly 7, the condition is false. No email. Was that the intent? Maybe the requirement meant “on day 7” (===) or “7 or more days” (>=).

If a mind can't trace execution, it can't catch this. The code runs. If it's subtly wrong, nobody notices until users complain—or worse, nobody ever notices.

Tracing execution isn't just an academic exercise. It's how minds verify each other's work.

Self-check: spot the bug

The intent: “Print numbers 1 through 5.”

for (let i = 1; i < 5; i++) {
console.log(i);
}

Trace it. i starts at 1. Check: 1 < 5? Yes. Print 1. ... Eventually i is 5. Check: 5 < 5? No. Exit.

The output is 1, 2, 3, 4. Not 1 through 5. The condition should be i <= 5, not i < 5.

Off-by-one errors like this are everywhere. Tracing catches them.

⚠️When bugs kill: The Therac-25

Between 1985 and 1987, a computerized radiation therapy machine called the Therac-25 delivered massive overdoses to at least six patients. Three died. Others suffered severe radiation burns.

The cause was a race condition—when two parts of a program access shared data at the same time, and the outcome depends on which one gets there first. It's a bug you can only find by tracing execution carefully.

The machine had two modes: a low-power electron beam and a high-power X-ray beam. When operators edited commands within an 8-second window—faster than the software expected—two routines tried to access a shared variable simultaneously. The display showed “electron mode” while the hardware was configured for X-rays. Patients received 100 times the intended dose—up to 20,000 rads when 200 was prescribed. One described it as “an electric shock” and “fire” burning through her.

Previous versions (Therac-6 and Therac-20) had hardware interlocks that physically prevented dangerous configurations. The Therac-25 removed these, trusting software alone. That software was written by a single programmer, never independently reviewed, never tested for race conditions.

The lesson: Every bug you trace in this curriculum is practice for catching bugs that matter. The off-by-one error in a loop counter is the same category of mistake that killed people. The difference is stakes.

Source: Leveson & Turner, “An Investigation of the Therac-25 Accidents” (IEEE Computer, 1993)

Refine

You've built a model of program execution. Specified what questions it answers. Generated understanding through examples. Critiqued where it breaks down.

What we learned

  • Code executes sequentially—top to bottom, one line at a time
  • Two ways to break sequential flow: conditionals (branching) and loops (repetition)
  • Functions affect flow by “jumping” to the function body
  • Programs are deterministic—same inputs, same outputs
  • Tracing execution step by step is how any mind verifies logic

What's next

You can trace execution now. But reading real code means understanding what it's trying to do, not justhow it executes. That's pattern recognition, variable naming, function structure—the skill of reading code as intent, not just instructions.

That's Lesson 3. The loop continues.

Why this matters for mind + mind collaboration

When collaborating on code, understanding enables trust. If you can't trace what code does, you can't verify it's correct. You're just hoping.

But if you can trace execution—step through conditionals, count loop iterations, follow function calls—you can review code from any source with confidence. One mind writes. Another verifies. Together, working software ships.

If one character, one pause, of the incantation is not strictly in proper form, the magic doesn't work. Human beings are not accustomed to being perfect, and few areas of human activity demand it.

Fred Brooks,The Mythical Man-Month (1975)

Now practice what you've learned

The reading gives you the mental model. The exercises make it stick. Week 2 exercises focus on bug hunting: finding bugs in broken programs and explaining WHY they're wrong.

Start Week 2 Exercises

15 exercises · 5-6 hours

Or continue to Lesson 3: Reading Code to complete the readings first