Building Software

Engineering Fundamentals for the Agent Era

When AI agents write the code, engineering is the work around it: deciding what to build, proving that it works, understanding how it runs, operating it, securing it, and directing what the agents may do.

When agents execute, people still own six things

Each thing the agent does is paired with a mistake it makes there and the part you own that catches it.

The agent

You own

  1. The agent writes the code

    • A mistake it makes: An export feature marked done that silently omits archived records, because no criterion said whether to include them.

      You own Intent

      Core 1

      Deciding what you want precisely enough that done is defined before anything gets built.

  2. The agent reviews it

    • A mistake it makes: A failing test 'fixed' by changing its expected value to match the buggy output.

      You own Verification

      Core 2–4

      Tests are the definition of done, written down and run on every change.

    • A mistake it makes: Money stored and calculated as floating-point numbers, producing totals that are off by a cent.

      You own Understanding

      Core 5–12

  3. The agent approves changes

    • A mistake it makes: A migration that locks a large table, or drops a column the running version still reads.

      You own Operation

      Core 13–15

      Seeing what production is doing and changing it without betting the system on each release.

    • A mistake it makes: API keys or passwords hardcoded in source code or committed to the repository.

      You own Security

      Core 16–18

      Know what is sensitive, where the boundaries are, and who is allowed to do what.

  4. The agent coordinates other agents

    • A mistake it makes: An agent reviewer approving another agent's change because both share the same wrong assumption.

      You own Direction

      Core 19–22

      How agents work and fail, how to hand them work, how to check what comes back, and what stays yours.

AI agents can now write most of the code in a project, and they increasingly review it, coordinate other agents and approve changes. Code can be entirely machine-written and still be good engineering. The difference between engineering and vibe coding is the thinking around the code: knowing what you want, knowing how the system behaves, and having evidence that it does what you meant.

Automation has a known trap, which Lisanne Bainbridge named the ironies of automation in 1983: machines take over the easy work and leave people the hardest parts, with less practice at them. Airline pilots fly on autopilot most of the time and still train to fly by hand, because they are the backup when it fails. This curriculum is that training for software.

Read the paper: Ironies of Automation (Lisanne Bainbridge, Automatica, 1983)

Read first How Agents Work and How They Fail

If you use agents today, read How Agents Work and Fail first; it needs nothing else in the map.

A call to a client-library option that does not exist, such as a retries setting the library never had, written with full confidence.

Contents

Each area names the specific mistakes agents make that its knowledge lets you catch, the depth a working developer needs, and a drill built on flawed agent output. Its competencies are things you should be able to do without AI; they are the learner's test. Depth is how far a working developer needs to go.

1

Intent: Deciding What to Build

Deciding what you want precisely enough that done is defined before anything gets built.

  1. Framing the Problem

    A mistake it teaches you to catch: A CSV export button with column pickers built for a request whose real need was the same monthly report sent to an accountant.

    Depth: do
  2. Core 1
    Requirements and Acceptance Criteria

    A mistake it teaches you to catch: An export feature marked done that silently omits archived records, because no criterion said whether to include them.

    Depth: do
  3. Domain Modeling and Invariants

    A mistake it teaches you to catch: A lifecycle modeled as scattered booleans (isPaid, isShipped, isCancelled) that allows impossible combinations such as shipped but never paid.

    Depth: do
  4. Design Documents and Decision Records

    A mistake it teaches you to catch: A public API field named and shipped during a small bug fix, making the name permanent for every client.

    Depth: do
2

Verification: Testing as the Core Discipline

Tests are the definition of done, written down and run on every change.

  1. Core 2
    Tests as Executable Specifications

    A mistake it teaches you to catch: A failing test 'fixed' by changing its expected value to match the buggy output.

    Depth: do
  2. Core 3
    Engineering Robust Tests

    A mistake it teaches you to catch: Everything mocked, so the tests never touch a real database and miss every query bug.

    Depth: do
  3. Property-Based Testing and Test Quality

    A mistake it teaches you to catch: Code that passes every hand-written example and fails on an input nobody thought of, such as an empty string, a huge number or combining characters.

    Depth: do
  4. Core 4
    Continuous Testing and Fast Feedback

    A mistake it teaches you to catch: A failing test marked as skipped so the pipeline turns green.

    Depth: do
3

The Machine: How Code Actually Runs

From source code down to silicon and out across the network.

  1. Hardware and the Operating System

    A mistake it teaches you to catch: A whole file or table loaded into memory when the job needed to stream it, which works in testing and crashes on real data.

    Depth: explain
  2. Core 5
    Languages, Compilers and Runtimes

    A mistake it teaches you to catch: A blocking call inside an async handler that stalls every other request on the event loop.

    Depth: explain
  3. Core 6
    Representing Numbers, Text and Time

    A mistake it teaches you to catch: Money stored and calculated as floating-point numbers, producing totals that are off by a cent.

    Depth: do
  4. Networks and Protocols

    A mistake it teaches you to catch: A state-changing action exposed as a GET request, which link prefetchers and crawlers will trigger.

    Depth: explain
4

Math and Algorithms

Enough logic, complexity, statistics and estimation to check a claim without asking another model.

  1. Logic and Discrete Math

    A mistake it teaches you to catch: An inverted or incomplete condition, such as a less-than where less-than-or-equal was needed, or a compound check negated incorrectly.

    Depth: explain
  2. Core 7
    Algorithms, Data Structures and Complexity

    A mistake it teaches you to catch: A nested loop over two lists, taking quadratic time, where a hash map lookup would make it linear.

    Depth: do
  3. Probability and Statistics

    A mistake it teaches you to catch: Average latency reported while a slow tail, which most users hit at least once per session, stays hidden.

    Depth: explain
  4. Back-of-the-Envelope Estimation

    A mistake it teaches you to catch: A design that needs tens of thousands of writes per second from a single database node sized for a few thousand.

    Depth: do
5

State: Data, Concurrency and Distribution

The hardest bugs live where data is stored, shared or spread across machines.

  1. Core 8
    Data Modeling and Databases

    A mistake it teaches you to catch: Lists stored as comma-separated strings or opaque JSON blobs, making queries slow and integrity impossible to enforce.

    Depth: do
  2. Core 9
    Transactions and Consistency

    A mistake it teaches you to catch: A read-modify-write on a balance or counter with no transaction or lock, losing updates under concurrent requests.

    Depth: do
  3. Concurrency and Race Conditions

    A mistake it teaches you to catch: Check-then-act races, such as checking stock and then decrementing it in two separate steps.

    Depth: explain
  4. Core 10
    Distributed Systems and Partial Failure

    A mistake it teaches you to catch: Retries without idempotency that charge a customer twice when the first attempt had actually succeeded.

    Depth: do
6

Design: Structuring Systems That Stay Understandable

Structure is what lets a system keep changing without breaking.

  1. Managing Complexity

    A mistake it teaches you to catch: A factory, an interface and a configuration loader added for a feature that has exactly one implementation.

    Depth: do
  2. Components and Architecture

    A mistake it teaches you to catch: Business rules written directly inside HTTP handlers or UI components, where they can't be reused or tested alone.

    Depth: explain
  3. Interfaces and APIs

    A mistake it teaches you to catch: A breaking change to a public API, such as a renamed field or changed type, shipped without a version or a migration path.

    Depth: do
  4. Core 11
    Error Handling and Failure Paths

    A mistake it teaches you to catch: A catch-all handler that logs the error and returns a default value, so failures look like successes.

    Depth: do
  5. Core 12
    Where Logic Meets the Database

    A mistake it teaches you to catch: N+1 queries: one query for a list and then one more for every item, usually hidden inside an ORM's lazy loading.

    Depth: do
  6. Frontend and Backend

    A mistake it teaches you to catch: Authorization, pricing or discount logic enforced only in the browser, where any user can change it.

    Depth: explain
7

Operations: Running Software in Reality

Seeing what production is doing and changing it without betting the system on each release.

  1. Core 13
    Debugging

    A mistake it teaches you to catch: A symptom patched with a null check, a retry or a broad try/catch while the actual cause stays in place.

    Depth: do
  2. Core 14
    Observability

    A mistake it teaches you to catch: Whole request bodies logged, including passwords, tokens and personal data.

    Depth: do
  3. Reliability, Redundancy and Recovery

    A mistake it teaches you to catch: Backups that were never restored and turn out to be empty, partial or corrupt when they are needed.

    Depth: do
  4. Core 15
    Shipping Change Safely

    A mistake it teaches you to catch: A migration that locks a large table, or drops a column the running version still reads.

    Depth: do
  5. Performance and Capacity

    A mistake it teaches you to catch: Code optimized where it is not the bottleneck, while the real cost sits in a query or a network call.

    Depth: do
8

Security: Boundaries, Data and Trust

Know what is sensitive, where the boundaries are, and who is allowed to do what.

  1. Security Boundaries and Threat Modeling

    A mistake it teaches you to catch: An internal service that trusts any caller on the network because it is considered internal.

    Depth: do
  2. Core 16
    Authentication and Authorization

    A mistake it teaches you to catch: An endpoint that returns any record whose ID you put in the URL, because it checks that you are logged in but not that the record is yours.

    Depth: do
  3. Core 17
    Sensitive Data and Secrets

    A mistake it teaches you to catch: API keys or passwords hardcoded in source code or committed to the repository.

    Depth: do
  4. Protecting Data in Transit and at Rest

    A mistake it teaches you to catch: TLS certificate verification disabled in a client to get past an error.

    Depth: explain
  5. Core 18
    Untrusted Input and Injection

    A mistake it teaches you to catch: A database query or shell command built by string concatenation with user input.

    Depth: do
  6. Dependencies and the Supply Chain

    A mistake it teaches you to catch: An import of a package that does not exist, or of a lookalike name an attacker registered to catch exactly that mistake.

    Depth: explain
9

Directing Agents: Delegation, Review and Accountability

How agents work and fail, how to hand them work, how to check what comes back, and what stays yours.

  1. Core 19
    How Agents Work and How They Fail

    A mistake it teaches you to catch: A call to a client-library option that does not exist, such as a retries setting the library never had, written with full confidence.

    Depth: do
  2. Core 20
    Prompting and Specifying Work for Agents

    A mistake it teaches you to catch: An agent told to 'make the tests pass' that deletes or weakens the tests.

    Depth: do
  3. Core 21
    Reading and Reviewing Code You Did Not Write

    A mistake it teaches you to catch: A change that passes the tests but alters behavior outside the requested task.

    Depth: do
  4. Evals: Testing AI Behavior

    A mistake it teaches you to catch: A prompt change shipped because it looked better on three examples.

    Depth: explain
  5. Orchestration, Permissions and Guardrails

    A mistake it teaches you to catch: A CI agent given the organization-wide deploy token because scoping one to the repository was more setup, so any repository it touches can ship to production.

    Depth: explain
  6. Core 22
    Accountability: Owning Code You Did Not Type

    A mistake it teaches you to catch: A 600-line agent change approved within a minute, with approval treated as a formality.

    Depth: do

What you can now learn more shallowly

Syntax and language trivia.
Agents write valid code in any mainstream language. The time you used to spend memorizing grammar is better spent reading code fluently and knowing what it does at run time.
Framework and library API recall.
Exact function names and options can be looked up or generated. Knowing what a framework does underneath matters more, and it is also how you spot an API that does not exist.
Boilerplate and scaffolding.
Project setup, CRUD handlers, configuration and glue code are cheap to generate and easy to check against a working example. Save your attention for the code that encodes business rules.
Hand-writing standard algorithms.
You will rarely implement a balanced tree or a sort yourself, but you still need to know what each one costs and when to choose it.
Mechanical translation and upgrades.
Porting between languages, library versions or frameworks is mostly mechanical. What stays with you is knowing where their behavior differs, such as integer overflow, async semantics and time handling.