A prototype you throw away
In Splitting the work into components the agent can build one at a
time you wrote the acceptance test for the import parser, and that test
treats a line that starts with x as a done item. The rule came from the
colleague who asked for the feature. They remember their old app writing
x , and nobody has looked at the file. In this lesson we check that
rule before the parser is built. We write down the one question, have
the agent build the smallest program that answers it, put the answer in
the spec and delete the program.
Let the agent interview you ended with open questions in the spec, and some of them can’t be settled by talking. Whether a file uses one done mark or two is a fact about the file, and a short program finds it out faster than a meeting does. Thomas and Hunt call this a prototype built to learn: it answers a question, it can leave out completeness and robustness, and it is thrown away when the question is answered [1]. With a coding agent, such a program takes little time to write, so trying the idea often costs less than discussing it.
The fixture
Section titled “The fixture”The fixture is in the course repository under
site/examples/coding-with-agents/prototype-to-throw-away/. Copy that
whole directory to a place of its own. The copy holds fixture-repo/,
where the agent works, and a sample/ directory with a script that the
second half of the lesson uses. fixture-repo/ holds SPEC.md, the spec
for the import command of the to-do program, and old-list.txt, a copy
of the colleague’s old file. The other files are for the course’s own
checks. Change into fixture-repo for every step until the Exercise,
except the test change, which is in your copy of an earlier fixture. The
reset is to delete the copy and copy again.
The spec ends with this section:
## Open questions
- Which done marks the old file uses. The colleague thinks it is `x` and a space, but nobody has looked. `old-list.txt` is a copy of the file.If the answer is “only x ”, the parser and its test don’t need a
change. A second mark in the file would make the parser import those
items as open. The test would still pass, because none of its input lines
has that mark.
One question before any code
Section titled “One question before any code”A throwaway prototype is a small program built only to answer one design question, and deleted once it has. The question comes first, written in one sentence, before you ask for any code. Without it, the agent builds whatever seems useful: a parser, then a test for the parser, then a command that calls it. That’s a first version of the import, built without the components and checks that you designed in Splitting the work into components the agent can build one at a time.
A prototype can answer a question when the program prints the answer,
such as a count or two outputs side by side.
“Which done marks does old-list.txt use?” is such a question. “Should
we build the import at all?” isn’t, because no program prints the answer.
“How should the import work?” isn’t either, because it asks for the whole
design.
Which question fits a prototype?
Section titled “Which question fits a prototype?”An engineer is specifying an import command for a small to-do program. It reads a text file that the colleague who asked for it exported from an old app. The spec has open questions, and the engineer wants a coding agent to build a throwaway prototype for one of them.
Which of these questions should the engineer give the agent as the one question for a throwaway prototype?
For which question can a short program print something that settles it?
The smallest program that answers it
Section titled “The smallest program that answers it”Start your coding agent in fixture-repo and give it the question, and
say what the program reads and prints. Say what to leave out, too. Tests,
error handling and structure are effort spent on code that you delete,
and a brief that doesn’t mention them leaves that choice to the agent.
Say also that it may create one file and change nothing else.
Read SPEC.md. Its open question is which done marks old-list.txt uses.Write a throwaway script, count_forms.py, that answers only that. It readsold-list.txt (hard-code the name) and prints how many lines start witheach first word, most common first, the top five.No tests, no error handling, no command-line options. Create onlycount_forms.py, and don't start on the import.Counting first words is enough. A done mark is the first word of its
line, and a mark that the colleague forgot shows up near the top of the
list. The course ships one version of such a script in
sample/count_forms.py, so the output below is checked on every build:
# Throwaway: answers which done marks old-list.txt uses. Delete after.from collections import Counterfrom pathlib import Path
lines = Path("old-list.txt").read_text(encoding="utf-8").splitlines()words = Counter(line.split()[0] for line in lines if line.strip())for word, count in words.most_common(5): print(f"{word}: {count}")The file name is hard-coded, and the whole file is read at once. It has no functions or tests. In the parser each of those would be a defect, and for one run on a short file none of them matters.
Run the course's prototype
Section titled “Run the course's prototype”Run this in fixture-repo, and compare what you see with the output
below.
python3 ../sample/count_forms.pyx: 10 [x]: 4 Buy: 3 Book: 2 Call: 2
Output verified in CI from site/examples/coding-with-agents/prototype-to-throw-away/sample_run.py.
Run the script your agent wrote in the same directory, with
python3 count_forms.py. Its format may differ, and the counts for x
and [x] should be the same. If they differ, one of the two scripts is
wrong, and reading both against old-list.txt tells you which.
What does the prototype brief ask for?
Section titled “What does the prototype brief ask for?”An engineer briefs a coding agent for a throwaway script that counts how the lines of one text file start, to find out which done marks the file uses. The script runs once and is then deleted.
Which two of these belong in the brief for the throwaway script?
Which parts of the brief serve the one answer, and which serve code that someone keeps?
Write the answer down, then delete the program
Section titled “Write the answer down, then delete the program”The output answers the question. The file has two done marks: x
starts ten lines and [x] starts four. A parser built from the spec as
it stands would import four done items as open. The prototype found the
fact, and the decision is still yours. Here the decision is that [x]
marks a done item too. Write it into the behavior and take the question
out of the open questions:
2. A line that starts with `x` or `[x]` and a space is a done item, and the mark isn't part of its text. The old file uses both (10 and 4 lines).The acceptance test changes with the spec. It is the test_importer.py
that you wrote in your copy of the fixture of Splitting the work into
components the agent can build one at a time. Give it one more input
line and its expected item:
def test_parse_lines_keeps_text_and_done_mark_and_skips_blank_lines(self): lines = [ "Buy milk", "", "x Call the plumber", " Water the plants ", "[x] Pay the bill", ] self.assertEqual( importer.parse_lines(lines), [ {"text": "Buy milk", "done": False}, {"text": "Call the plumber", "done": True}, {"text": "Water the plants", "done": False}, {"text": "Pay the bill", "done": True}, ], )A parser that knows only x returns the last line as an open item with
the text [x] Pay the bill, so the test fails on it. You change the test
before the parser is briefed, and the brief’s “Do not change the test”
still holds for the agent. Then delete both scripts, from fixture-repo:
rm count_forms.py ../sample/count_forms.pyThe answer is in the spec, where a fresh session and a reviewer read it. The code that found the answer is gone, so nobody can build on it. In an interview with Venners, Hunt and Thomas compare a prototype to the front of a film set, with no building behind it. They say it is made to be thrown away, and that the code a system keeps is a different kind, which they call tracer code [2].
The script works. Now what?
Section titled “The script works. Now what?”A coding agent wrote a throwaway script that showed which done marks an old to-do file uses: ten lines start with x and four with [x]. The spec for the import command says only x. The parser hasn't been built yet.
The script printed x: 10 and [x]: 4. The colleague says: “It works.
Keep it and turn it into the parser.” What do you do?
Where must the answer be for a fresh session to build the parser, and what should happen to code written without tests?
Small on purpose
Section titled “Small on purpose”In 1975, Fred Brooks advised teams to plan to throw away the first version of a whole system, because they would anyway. In the 1995 anniversary edition he took that advice back. He wrote that it assumed a system is designed, built and tested in one pass, and that he now preferred to grow a system step by step [3]. A throwaway prototype in this lesson is a different thing from a first version of the system. It is a few lines that answer one question that you wrote down before it existed. The system itself grows one checked component at a time, as Splitting the work into components the agent can build one at a time planned it.
Throw the first version away?
Section titled “Throw the first version away?”A team is about to build an import command for a small to-do program with a coding agent. One design question is open: which done marks the old file uses. The work is planned as three components, each checked before the next.
A teammate quotes “plan to throw one away” and proposes building the whole import twice. What does this lesson do instead?
What did Brooks later say about throwing away a whole first version, and how big is a prototype for one question?
Can a prototype settle it?
Section titled “Can a prototype settle it?”An engineer is specifying an import command for a small to-do program and sorts the open points: some a short throwaway program can settle, and some no program can.
Does a short program print or show something that settles the point?
From open question to spec
Section titled “From open question to spec”The steps of settling one open question in a spec with a throwaway program that a coding agent writes, before the real component is built.
- Write the open question down in one sentence
- Brief the agent for the smallest program that answers it
- Run the program and read what it prints
- Write the answer into the spec and add a case to the test
- Delete the program
What must exist before the agent writes anything, and what has to be in the spec before the code is gone?
Exercise
Take the spec you wrote in the exercise of Let the agent interview you,
and pick one open question from it that a program can answer. Write the
question in one sentence. If your spec has none, use the open question of
sample/SPEC.md in your copy of that lesson’s fixture: whether
archive list shows the date. A program that prints five archived items
both ways shows you the two forms. The answer is then your decision,
which you write into the spec. Start your coding agent in a scratch directory outside
the fixture, so the prototype can’t touch the real code, and brief it for
the smallest program that answers the question, with what to leave out
and the one file it may create. Run the program, write the answer and
your decision into the spec, and delete the program. Fifteen minutes is
enough. You do this so that a design question is settled by what a
program shows, and the code that showed it never reaches the system.
A good result: the question fits in one sentence and was written before the brief. The program is one file with no tests, and it is gone. The spec states the answer, and the question is no longer under the open questions. Reflect: how long would a discussion of the same question have taken, and would it have ended with the same answer?
Stretch: Take a second open question that only a person can decide, and write down why no program answers it.
Recap
- A throwaway prototype is a small program built to learn, and it is thrown away once it has answered its question [1].
- Write the question down in one sentence before you ask for code. A program that answers no named question grows into a first version of the system.
- Brief the agent to leave out tests, error handling and structure, and to create one file. They are effort spent on code that you delete.
- Write the answer and your decision into the spec, and add a case for it to the acceptance test, before the program is deleted. A fresh session reads only the spec.
- Keep the prototype small. Brooks later took back his advice to throw away a whole first version [3], and the system grows one checked component at a time.
You can now
- Settles a design question with a throwaway prototype
References
Section titled “References”- David Thomas, Andrew Hunt. The Pragmatic Programmer: Your Journey to Mastery, 20th Anniversary Edition. Addison-Wesley, 2019. Book.
Thomas 2019 - Bill Venners. Tracer Bullets and Prototypes: A Conversation with Andy Hunt and Dave Thomas, Part VIII. Artima Developer, 2003. Reference.
Artima tracer bullets - Frederick P. Brooks, Jr.. The Mythical Man-Month: Essays on Software Engineering, Anniversary Edition. Addison-Wesley, 1995. Book.
Brooks 1995