Building Software
Sections

Contents Introduction

Who this course is for

Who the course serves, who should start somewhere else, what you need before the first lesson, and what you can do once you finish.

Lesson 0.1 of the Introduction, a 6-minute read.

Your agent hands back a pull request. The tests pass, the diff is tidy, and the summary says the feature is done. You read it, it looks fine, and you merge it. A week later a customer is charged twice, and when you open the diff again you can point at the line that did it, the same line that looked fine a week earlier.

This course is for the person in that story. It teaches what you need to know for that line to look wrong before it ships.

Who it is for

The idea under the course fits in a few sentences. Agents can now write most of the code in a project, and they write it quickly and fluently. The work that stays with you is everything around the code: deciding what should be built, getting evidence that it was built, knowing how it behaves once it runs, keeping it running and safe, and setting limits on what the agents may do. That work is engineering, whoever typed the code.

The course teaches that work, and it is written for a few kinds of reader.

On the left, a large highlighted group, Start here, holds four readers: someone who ships with an agent every day, who learns to find its mistakes in review; someone who builds by prompting, who gets a working model of what happens underneath; an experienced engineer, who learns what changes with agents; and a team lead, who gets the questions to ask. On the right, a group, Start elsewhere, holds three readers. Never read code, learn one language first, leads down to CS50x, free and starts from zero, and an arrow labelled come back runs from CS50x into the Start here group. Below it, framework tutorial, this course has none, and prompt tricks, none here either.
Four kinds of reader start here, each for a different reason. Someone who has never read code learns one language first, CS50x for example, and comes back; the course has no framework tutorials and no prompt tricks.

You ship with an agent every day. Most of what it writes is fine. Every so often it hands you a change whose tests pass and which is still wrong, and you cannot say why until something breaks. Maybe the test checked what the code does instead of what it should do, or two requests arrived at once and one of the writes disappeared. The course names those mistakes area by area and shows you what each one looks like in a diff, so you can find them in review.

Three boxes stacked top to bottom and joined by arrows. The top box says it works, not sure why, with a note beside it reading every change a gamble. The middle box, highlighted, says working model, what happens underneath. The bottom box says a claim you check, with that model.
Without a model of what happens underneath, "it works" is something you hope. With one, it becomes a claim you can check.

You have built most of your projects by prompting agents, and you can read a little code. Your apps work, and you are not sure why, so every change feels like a gamble. The course gives you a working model of what happens underneath, from how the program runs to what its database does when two requests arrive together. With that model, "it works" becomes a claim you can check.

You are an experienced engineer and want to know what changes when agents write the code. Much of the material will be familiar, and you can move fast through it. The parts most likely to be new are the agent mistakes listed at the top of each page and the drills built on flawed agent output. Read the Directing Agents section in full; it covers delegation, review and accountability.

You lead a team and approve work that agents did. You need to know what to ask for before you accept a change, such as which tests prove it and what happens when one of its steps fails. Each area of the course gives you the questions to ask.

Where each of you starts:

  • If you ship with agents today, read How Agents Work and How They Fail first.
  • If you are an experienced engineer, take a section's test before its lessons and read only what you miss.
  • If you lead a team, read the Directing Agents section in full.
  • Everyone else can take the check at the end of this page and then begin at Section 1.

The next lesson lays these routes out in full.

Who should start somewhere else

If you have never read or written code, Section 1 will stop you within a few screens. The lessons show real TypeScript and SQL and ask you to predict what it does, and that takes practice with at least one language, which this course assumes you already have. Learn the basics of one mainstream language first: values and variables, conditionals, loops, functions, and running a program from a terminal. Harvard's CS50x is free and starts from zero. Come back when you can read a twenty-line function and say what it returns.

If you want a tutorial for a specific framework, tool or agent product, this course has none. Products change every few months. The course teaches what stays true across them: how numbers and text are stored, what a transaction guarantees, what a test can and cannot prove, where trust changes hands in a system. Tools appear in the lessons as examples of an idea, after the idea.

If you want prompt tricks, you will not find those either. The Directing Agents section does teach how to hand work to an agent. It treats that as writing down what you want, what the agent may touch and how you will check the result, which is the same skill you would use to brief a colleague.

What you need before the first lesson

You can check each of these now.

  • You can read short functions, conditionals and loops in one mainstream language. The lessons use TypeScript and SQL. If you read JavaScript, Python, Java, C# or Go, the rest is mostly new spelling for ideas you know.
  • You can open a terminal, run a command and read what it prints.
  • It helps to have used an AI coding assistant, though you do not need to. Many drills start from something an agent produced, and they are easier to picture if you have watched one work.

You do not need to install anything to read the lessons or run their code. The runnable examples run in your browser.

If you are close to a beginner, read Reading the code in this course before Section 1. It covers the TypeScript, SQL, diffs, test output and shell lines the lessons use, by reading one piece of agent-written code line by line. The readiness check at the end of this page tells you whether you need it.

What you can do when you finish

The course is built around six things people still own when agents write the code. Each one has its own part of the course, and each turns into something you can do.

  • Intent: you can write down what a change must do, including its edge cases and what must never happen, in terms someone else can check, before any code exists.
  • Verification: you can tell a test that proves a behavior from one that only runs the code, and write tests that fail when the code is wrong.
  • Understanding: you can trace how a piece of code runs, from how its numbers are stored to how its data reaches the database and crosses the network, well enough to predict where it will break.
  • Operation: you can find the cause of a production failure from evidence instead of guesses, and ship a change in a way you can undo.
  • Security: you can see where untrusted input crosses a boundary, where a permission check is missing, and where a secret or someone's personal data leaks.
  • Direction: you can decide what an agent may touch, review what it brings back, and answer for what ships under your name.

Each subsection page lists, under You understand it when you can, what you should be able to do without an AI once you have learned that area. Use those lists to judge whether the course worked for you.

Now take the six questions below. If you get five or six right, go on to How this course works or straight to Section 1. If you miss two or more, read Reading the code in this course first.

Are you ready to start?

Six short pieces of code like the ones in the lessons. If you get five or six right, start the course. If you miss two or more, read Reading the code in this course first; it teaches what these questions use.

  1. 1An agent wrote this function to total the larger prices in a cart. What does the last line print?
    TypeScript
    function total(prices: number[]): number {
      let sum = 0;
      for (const p of prices) {
        if (p > 10) sum = sum + p;
      }
      return sum;
    }
    
    console.log(total([5, 12, 8, 20]));
    Show the answer

    Answer B. The loop visits every price, but the if lets a price into the sum only when it is greater than 10. That keeps 12 and 20 and skips 5 and 8, so the sum is 32. 45 is the total of every price, which is what you get if you read the loop and skip the condition.

  2. 2What does this print?
    TypeScript
    function label(count: number | string): string {
      if (count === 0) return "none";
      if (count === 1) return "one";
      return "many";
    }
    
    console.log(label("0"));
    Show the answer

    Answer C. === is true only when both sides have the same type and the same value. The string "0" and the number 0 have different types, so both checks are false and the function reaches return "many". With ==, JavaScript would convert the string to a number first and return none, which is why careful code uses ===. Comparing a string to a number this way never throws.

  3. 3What does ids hold after this runs?
    TypeScript
    const orders = [
      { id: 1, total: 40, paid: true },
      { id: 2, total: 15, paid: false },
      { id: 3, total: 60, paid: true },
    ];
    
    const ids = orders.filter((o) => o.paid).map((o) => o.id);
    Show the answer

    Answer A. filter keeps the elements for which its function returns true, so orders 1 and 3 survive. map then turns each surviving order into whatever its function returns, here the id. [40, 60] would need o.total in the map, and [true, false, true] is what map((o) => o.paid) gives without the filter.

  4. 4After the last line runs, what are a and b?
    TypeScript
    async function getCount(): Promise<number> {
      await new Promise((resolve) => setTimeout(resolve, 50));
      return 3;
    }
    
    const a = getCount();
    const b = await getCount();
    Show the answer

    Answer B. Calling an async function hands back a promise straight away, a placeholder for a value that arrives later. await pauses the code until that promise settles and then gives you the value inside it, so b is 3. Without await, a stays the promise itself, and code that treats it as a number gets the wrong thing.

  5. 5Which names does the last query return?
    SQL
    CREATE TABLE users (name TEXT, plan TEXT, active INTEGER);
    INSERT INTO users VALUES
      ('Ana', 'pro', 1),
      ('Ben', 'free', 1),
      ('Cy', 'pro', 0),
      ('Dee', 'pro', 1);
    
    SELECT name FROM users WHERE plan = 'pro' AND active = 1;
    Show the answer

    Answer D. WHERE keeps a row only when its whole condition is true, and AND needs both parts to hold. Cy is on the pro plan but has active = 0, so that row fails the second part. Ana, Cy and Dee is the answer to plan = 'pro' on its own, and all four names is what OR would return.

  6. 6An agent's pull request contains this hunk. What does it change about who can edit a document?
    Diff
    @@ -10,4 +10,4 @@ function canEdit(user: User, doc: Doc): boolean {
       if (user.role === "admin") return true;
    -  if (doc.ownerId === user.id) return true;
    +  if (doc.ownerId === user.id || doc.public) return true;
       return false;
     }
    Show the answer

    Answer C. A line starting with - is removed, a line starting with + is added, and a line starting with a space is unchanged context. So the owner check is replaced by one that also returns true whenever doc.public is set, for any user. The admin line is context and still runs. A reviewer who skims the + line sees an owner check and can miss that it widened.