2 Introduction: This Is Not an AI Class
2.1 Learning Objectives
By the end of this lecture you should be able to:
Describe the three eras of programming practice—
memorization, search, and generation— and identify what each era made cheap and what it left expensive. Explain why this course is not an AI class, and state its actual thesis: when writing code becomes cheap, every other phase of software development becomes the job.
Name the phases of the software development life cycle and explain why undergraduate coursework has historically over-weighted exactly the phase that generative AI is automating.
Apply the five-year test to a piece of technical knowledge: decide whether it is a durable skill or a perishable tool detail, and justify the decision.
List the durable skills this course teaches—
version control and collaboration, code review, testing, CI/CD, full-stack architecture, security and authorization, deployment, evaluation and monitoring— and connect each to a phase of the life cycle. Complete a full-cycle micro-project in which the function body is the least graded artifact: specification, branch, tests, review, and CI carry the weight.
2.2 A Story About qsort
When your instructor was an undergraduate, there was no Google and no Stack Overflow. If you wanted to sort an array in C, you either remembered the standard library or you walked to the shelf and opened the textbook. To this day he can recite that qsort lives in <stdlib.h> and takes exactly these arguments:
void qsort(void *base, size_t nitems, size_t size,
int (*compar)(const void *, const void *));And he can still write the ritual that every C programmer of that
era had memorized—
#include <stdio.h>
#include <stdlib.h>
/* Comparator: cast the void pointers, dereference, compare. */
int compare_doubles(const void *a, const void *b) {
double arg1 = *(const double *)a;
double arg2 = *(const double *)b;
if (arg1 < arg2) return -1;
if (arg1 > arg2) return 1;
return 0;
}
int main(void) {
double data[] = {40.5, 10.15, 100.0, 90.45, 10.12, 25.7};
int n = sizeof(data) / sizeof(data[0]);
qsort(data, n, sizeof(double), compare_doubles);
for (int i = 0; i < n; i++)
printf("%.2f ", data[i]);
printf("\n");
return 0;
}$ gcc sort.c -o sort && ./sort
10.12 10.15 25.70 40.50 90.45 100.00If you can call qsort correctly without looking at an example, you are from that time.
Every generation looks back and shudders. Your instructor’s own
professors told him stories of writing whole programs in assembly,
and assured him he was lucky to be working in a high-level language
like C. Assembly
must have been truly difficult—
To be fair, the programmers of that era only had to hold C and C++
in their heads—
Then the world changed. Google, online documentation, Stack
Overflow, and Discord channels made all of that recall unnecessary.
Nobody today remembers qsort’s argument order, and nobody
needs to. We call Array.sort() or sorted(data) and do
not even ask which sorting algorithm runs underneath. Many
perfectly good working programmers cannot write a binary search
correctly on the first try without testing a few edge
cases—
Here is the same program, one era later:
data = [40.5, 10.15, 100.0, 90.45, 10.12, 25.7]
print(sorted(data))Fourteen lines of memorized ritual became one line you could find in thirty seconds of searching. Higher-level languages and online resources made programmers dramatically more efficient.
But be careful with the conclusion. They did not necessarily make
us better programmers. Efficiency and mastery are different
things: the search era removed the need to memorize, and much of the
memorization skill quietly atrophied. Nothing was lost—
Hold that thought. It is about to happen again, one level up.
2.3 The Third Era
We are now at the beginning of another transition, and it is bigger
than the last one. Generative AI can write code. Not
autocomplete a variable name—
Era | You supply | The tool supplies |
Memorize (1980s-90s) | everything, from memory | a compiler |
Search (2000s-10s) | the structure; you find and adapt the pieces | the idiom, on demand (docs, Stack Overflow) |
Generate (2020s- ) | the specification and the verification | the implementation, drafted end to end |
Notice what just became cheap. Implementing the function body was
the sacred part of software development—
Planning and feasibility
Requirements analysis
Design
Development (coding)
Testing
Deployment
Maintenance
—
Now read the fine print of the third era: if the requirements
and the tests are well specified, an LLM can write the code for
you. The slice you were trained on is the slice being automated.
Industry measurements disagree on how much faster AI makes
developers—
And exactly as in the last transition, the value moves to what the
tool does not supply. In the search era, that was knowing
what to search for. In the generation era, it is everything on
either side of the function body: knowing what to build, specifying
it precisely, verifying what came back, integrating it, securing
it, shipping it, and keeping it alive. In the life-cycle list
above, that is items 1, 2, 3, 5, 6, and 7—
2.4 This Is Not an AI Class
Now we can state what this course is, by first stating what it is not.
This is not an AI class. We will not survey neural architectures for their own sake. We will not chase the model that topped a leaderboard last Tuesday. We will not teach you a catalog of prompt incantations that stop working at the next model release. Shiny AI technology has a half-life measured in months: the specific tools, model names, context-window sizes, pricing tiers, and prompt tricks that are current as you read this will be museum pieces before you graduate. Teaching them as content would be malpractice.
What we teach instead are the skills you will still be using in
five years—
how to take a vague idea and turn it into precise requirements;
how to design a system in layers so that its parts can change independently;
how to use version control not as a save button but as a collaboration protocol—
branches, pull requests, and history that tells the truth; how to review code—
human-written or machine-written— and how to be reviewed; how to write tests that come from the specification rather than from the code, and wire them into CI/CD so they run on every change;
how to build full-stack systems—
APIs, databases, frontends— and reason about the seams between them; how to think about security and authorization as design constraints, not afterthoughts;
how to deploy to the cloud and keep a service running;
how to evaluate and monitor a system whose components are non-deterministic;
and—
running through all of it— judgment: when to trust a tool’s output, how to verify it, and when to throw it away and think.
None of those is an AI technology. Every one of them predates generative AI, and every one of them survives whatever generative AI becomes. What is new is the weighting: AI made the middle of the life cycle cheap, so the surrounding skills are no longer the supporting cast. They are the job.
2.4.1 Then why is there so much AI in the syllabus?
Because the tools belong in the how, not the what.
You will use AI assistants constantly in this course—
A fair question: if the tools churn that fast, why learn today’s
tools at all? Because fluency and durability are not enemies. You
learned to drive in some particular car; the skill was driving.
We teach today’s assistants and today’s frameworks because you
cannot practice judgment on a whiteboard—
2.4.2 The five-year test
Throughout the semester we will apply one filter to everything we touch. Ask of any piece of knowledge: will this still be true, and still matter, in five years?
Knowledge | Five-year test | Why |
the exact arguments of qsort | fails | tool detail; the search era already killed it |
why a comparator must be consistent (a total order) | passes | true in every language, every era |
this month’s best coding model and its context size | fails | obsolete in months |
why generated code must be verified against a specification | passes | a property of statistical generation, not of any model |
the menu layout of a particular AI IDE | fails | UI churn |
branching, code review, and CI as a collaboration protocol | passes | decades old and strengthened, not weakened, by AI |
a memorized prompt “trick” | fails | model-specific behavior |
writing a precise specification with edge cases and acceptance criteria | passes | the scarce input of the generation era |
Common misconception. “Durable skills” does not mean
“old skills only.” Evaluation of non-deterministic systems, for
example, is a young discipline—
Practical implication. When you study for this course, study the invariants. If your notes from a lecture consist of button locations and model names, you took the wrong notes. If they consist of why the workflow is shaped the way it is, you can re-derive the buttons forever.
2.5 The Life Cycle, Reweighted
Let us make the course’s thesis concrete by walking the life cycle and asking, for each phase: what did your education emphasize, what does generative AI automate, and what does this course teach?
Phase | Typical coursework | GenAI today | This course |
Requirements | given in the handout | drafts, from you | you write them |
Design | given as starter code | suggests options | you decide, in layers |
Coding | ★ THE assignment ★ | largely automated | you specify & direct |
Testing | the autograder's job | generates tests | you own the contract |
Deployment | submit server | scaffolds configs | you ship to a cloud |
Maintenance | (deleted after finals) | helps investigate | you monitor & evolve |
Collaboration | (solo, mostly) | reviews PRs | you branch, review, merge |
Read the second column top to bottom: almost everything except coding was done for you. Read the third column: coding is the phase AI handles best, precisely because it is the phase with the clearest inputs and outputs. The fourth column is the syllabus.
2.5.1 Worked example: the same task, three eras deep
Take a task barely bigger than qsort: report the top three scores from an exam, highest first.
Era one (memorization): you write the comparator ritual above, plus the careful pointer arithmetic to take the last three elements. The skill on display is recall and low-level precision. Time: an hour, if your memory is good.
Era two (search): you search “python sort descending take first n,” adapt the top answer, and write:
top3 = sorted(scores, reverse=True)[:3]The skill on display is knowing what to search for and recognizing a good answer. Time: two minutes.
Era three (generation): you ask an assistant and receive not just the line but a function, a docstring, and if you ask, tests. Time: thirty seconds. So is there anything left to do?
Everything, it turns out—
Ties: if three students share the second-highest score, who appears in the top three? The one-liner picks arbitrarily; the requirement has an opinion, and someone must write it down.
Fewer than three scores: return what exists, or raise an error? A specification question, not a coding question.
Where do scores come from—
a file, a database, an API request? That is design. How do we know it works next month when someone “improves” it? That is a test suite and CI.
Who is allowed to see the top scores? Grade data is protected; that is authorization.
The registrar asks in March why the January report was wrong. That is maintenance, and it is only answerable if the history was kept honestly. That is version control.
The function body was the only part of this list an LLM fully
handles—
2.6 What We Will Actually Do
The course is structured around building and shipping real software, with AI assistance at every stage and with the non-coding phases carrying the weight.
Foundations first. (part "Git") as a collaboration protocol—
branches, pull requests, reviews, honest history. A look inside the (part "LLM") so its failure modes stop being folklore (and (part "BuildGPT") for those who want to go all the way down). (part "Claude Code") and the discipline of directing an agent rather than typing at it. Full-stack construction. (part "REST APIs") and (part "FastAPI"); (part "Relational Databases"); (part "Layered Architecture") so the pieces can change independently; (part "Docker"); a (part "ReactTS") frontend. This is the “ordinary software” your AI components will live inside.
Verification as a way of life. (part "Testing") —
unit, integration, property-based— wired into CI/CD; (part "Eval") and monitoring, which do for prompts and models what pytest does for functions. AI as a component. Running a local LLM; (part "Vector") databases and (part "RAG"); (part "Prompting") and context management ((part "Elephant-Goldfish")); (part "MCP"); (part "ai-api"), (part "ai-frameworks"), (part "chatbot"), and (part "Agents").
Shipping responsibly. Security and authorization ((part "RBAC-ABAC"), (part "ai-security")); (part "cloud-deploy"); and the maintenance mindset: logs, metrics, and the assumption that you will be reading this code again in a year.
Throughout, you will document your AI usage—
2.7 Project: TerpTop, the Inverted Assignment
Your first project inverts the grading you are used to. You will
build the top-three-scores tool from the worked example as a
complete, full-cycle micro-repository—
2.7.1 Repository structure
terptop/ |
├── README.md what this is, how to run it |
├── SPEC.md the requirements -- written by YOU |
├── requirements.txt pytest |
├── terptop.py the code (AI-drafted is fine) |
├── test_terptop.py the contract, derived from SPEC.md |
└── .github/ |
└── workflows/ |
└── ci.yml tests run on every push and PR |
2.7.2 Step 1: write the specification first
Before any code—
# TerpTop specification
`top_scores(scores, k=3)` returns the `k` highest scores,
highest first.
Decisions:
- Ties: scores are values, not students; duplicates may all
appear (e.g. top-3 of [90, 90, 90, 80] is [90, 90, 90]).
- Fewer than k scores: return all of them, sorted descending.
This is not an error.
- Empty input: returns []. Also not an error.
- k <= 0: raises ValueError.
- The input list is never mutated.Every line of that file is a decision a language model would otherwise make for you, silently and arbitrarily. Making them explicitly is the era-three skill.
2.7.3 Step 2: branch, then let the machine draft
git init terptop && cd terptop
git add SPEC.md README.md requirements.txt
git commit -m "Spec first: requirements for top_scores"
git switch -c feature/top-scoresNow prompt your assistant—
git add terptop.py
git commit -m "AI draft of top_scores (unverified)"2.7.4 Step 3: the contract, derived from the spec
Write the tests yourself, reading SPEC.md and not
reading terptop.py—
"""test_terptop.py -- contract derived from SPEC.md, not from the code."""
import pytest
from terptop import top_scores
def test_returns_k_highest_descending():
assert top_scores([70, 95, 80, 60, 90]) == [95, 90, 80]
def test_ties_may_all_appear():
assert top_scores([90, 90, 90, 80]) == [90, 90, 90]
def test_fewer_than_k_returns_all():
assert top_scores([75, 60]) == [75, 60]
def test_empty_input_returns_empty():
assert top_scores([]) == []
def test_nonpositive_k_raises():
with pytest.raises(ValueError):
top_scores([1, 2, 3], k=0)
def test_input_is_not_mutated():
scores = [70, 95, 80]
top_scores(scores)
assert scores == [70, 95, 80]Run the suite against the draft. Whether it is green on the first
try depends on how good your specification was—
2.7.5 Step 4: continuous integration
# .github/workflows/ci.yml
name: CI
on: [push, pull_request]
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: "3.12"
- run: pip install -r requirements.txt
- run: pytest -qPush the branch, open a pull request, and request a review from a teammate (or review it yourself in writing, if working solo: what would you flag in someone else’s identical PR?). Merge only on green CI plus an approving review. From this week until the end of the semester, that sentence is how all code moves.
2.7.6 What gets graded
Artifact |
| Weight |
| Why |
SPEC.md decisions (ties, edge cases, errors) |
| 30% |
| requirements are the scarce skill |
tests derived from the spec |
| 30% |
| the contract is yours, never the model’s |
branch / PR / review / honest commit history |
| 25% |
| collaboration protocol |
CI pipeline green on the merged main |
| 10% |
| verification must be automatic |
the function body itself |
| 5% |
| a machine drafted it in seconds; so can another |
That 5% is the course in one number.
2.8 Rules of Engagement
One principle generates every rule: you are accountable for everything you submit.
AI use is expected. Assignments assume an assistant unless explicitly marked otherwise. A few fundamentals must be demonstrated solo, and those will be clearly labeled.
“The AI wrote it” is never a defense. If it is in your submission, you can explain it line by line, and its bugs are your bugs.
Disclose substantively. Where a tool contributed significantly, say so—
in the README, in commit messages, in your usage log. This mirrors emerging professional practice. Guard the prompt. Other students’ code, private data, credentials, and materials you have no right to publish do not belong in a context window.
Verify before you rely. Submitting unread, unverified generated output is the course’s cardinal sin—
not because it is cheating, but because it is bad engineering.
2.9 Practice Exercises
2.9.1 Basic
In your own words, describe the three eras of programming practice. For each era, name one skill it made valuable and one skill it made obsolete.
Apply the five-year test to each of the following and justify your verdict in one sentence: (a) the keyboard shortcut for accepting an inline AI suggestion; (b) the reason tests must derive from the specification rather than the code; (c) the current context-window size of your favorite model; (d) the concept of least-privilege authorization.
List the seven phases of the software development life cycle. For each, state in one sentence what a typical undergraduate project did about it, and what this course expects you to do about it.
The lecture claims abstraction made programmers “more efficient but not necessarily better.” Give one concrete example from your own experience where an abstraction saved you time, and one where not understanding what was underneath it cost you time.
Reread the top-three worked example. Of the six bullets of “everything left to do,” which one would be most expensive to get wrong in a real registrar system, and why?
2.9.2 Intermediate
Build the TerpTop repository exactly as specified, including CI. In your README, record: what your assistant’s first draft got wrong (if anything), which test caught it, and one decision in SPEC.md that the draft had silently made differently before you specified it.
Take a programming project from a previous course. Write the SPEC.md that was implicit in its handout: every requirement, edge case, and error behavior the autograder actually checked. How many decisions had been made for you?
Deliberately give an assistant an underspecified version of TerpTop (“write a function that returns the top scores”) in two separate sessions. Diff the two results. List every decision the model made differently between runs—
each one is a requirement you failed to write. Extend TerpTop through a proper cycle: add bottom_scores(scores, k) via a new branch, a spec update, new tests, a PR, and a review, merging only on green CI. Submit the PR link; the diff and the review comments are the deliverable.
Interview someone who programmed professionally before 2010 (a TA, a parent, an instructor). What did they memorize? What do they no longer memorize? What do they say made someone a good programmer then versus now? One page.
2.9.3 Advanced
Write a two-page argument for the opposite thesis of this lecture: that implementation skill remains the core competency and courses like this one are premature. Use the METR productivity finding, the abstraction-leak argument from the qsort story, and at least one failure mode of generated code as evidence. Then write one paragraph rebutting yourself. (Being able to argue both sides is part of the judgment this course grades.)
Design the 2036 version of this lecture. Assume code generation is essentially solved: models implement any well-specified module correctly. Which phases of the life cycle remain human work, and why? Which of this course’s durable skills survived, and did any of them fail your own five-year test twice over?
The TerpTop grading table weights the function body at 5%. Propose and defend a complete grading scheme for a semester-long team project in the generation era: what artifacts exist, what each is worth, and—
the hard part— how you prevent the weights from being gamed by students who generate the surrounding artifacts too (specs, tests, reviews) without exercising judgment on any of them.
2.10 Summary
2.10.1 Key takeaways
Programming has passed through three eras—
memorize, search, generate. Each made the previous era’s core skill optional and moved the value elsewhere. Generative AI automates the function body: the phase of the life cycle that undergraduate coursework over-weighted, and the one with the clearest inputs and outputs. The surrounding six phases are now the job.
This is not an AI class. Shiny AI technology has a half-life of months; this course teaches the skills that pass the five-year test—
requirements, design, version control, review, testing, CI/CD, full-stack construction, security, deployment, evaluation, and judgment. AI appears in the course in two durable roles: as an instrument you direct with skill and suspicion, and as a component you engineer into ordinary software.
Efficiency is not mastery. Abstraction and generation make you faster; only verification and understanding make you good.
You are accountable for everything you submit. The machine drafts; you own.
2.10.2 Terminology
Term |
| Meaning |
software development life cycle (SDLC) |
| planning, requirements, design, coding, testing, deployment, maintenance |
three eras |
| memorization → search → generation; what programmers supply vs. what tools supply |
five-year test |
| will this knowledge still be true and still matter in five years? |
durable skill |
| a competency that survives tool churn (e.g. code review, specification) |
tool detail |
| knowledge with a shelf life (e.g. a model name, a menu location, a prompt trick) |
specification |
| the explicit record of every decision the code must
honor— |
contract (test suite) |
| tests derived from the specification, never from the generated code |
CI/CD |
| automation that verifies every change and ships the ones that pass |
judgment |
| knowing when to trust, how to verify, and when to discard a tool’s output |
2.10.3 Common mistakes
Hearing “not an AI class” as “anti-AI class.” The tools are used constantly; they are just not the curriculum.
Taking notes on tool trivia (buttons, model names) instead of invariants (why the workflow is shaped this way).
Treating the specification as paperwork to write after the code works—
at which point it records the code’s accidents, not your decisions. Deriving tests from the generated draft, which promotes its bugs into requirements.
Concluding from AI’s coding ability that implementation skill is worthless. Someone still debugs the leak in the abstraction, and it will be the person who understands what is underneath.
Confusing being faster with being better—
the METR perception gap is what that mistake feels like from the inside.
2.10.4 Looking ahead
Next, (part "Git") turns the collaboration protocol sketched in TerpTop into a full toolkit: branching strategies, honest history, pull requests, and review. Soon after, (part "LLM") opens the black box, so that the claim “generated code is statistically typical, not verified” stops being a slogan and becomes something you can predict from the mechanism. Every lecture after that is one more durable skill, with the tools of the moment along for the ride.