37  AI: Let it draft

The assistant as Drafter, kept safe by the smallness of the piece and a test.

This is the first time this course lets the assistant write code you did not type yourself, and it is safe for exactly two reasons: the piece is small enough to read in full, and a test stands behind it before you are allowed to believe it. Every round below follows the same order, and the order is the whole point: specify first, draft second, read every line third, test fourth. Never let the assistant race ahead of a step you have not done yet.

TipThe order, every time
  1. Specify. Write the function’s name, its inputs and outputs, and one worked example, before prompting anything.
  2. Draft. Ask for exactly that one function, giving it the specification, nothing more.
  3. Read. Go through what it returns line by line. If there is a line you cannot explain, stop here.
  4. Test. Write one gentle test and one nasty test, seeded from your own worked example and from a case designed to break it. Only a passing nasty test earns your belief.

Warm-up, done together

As a class, specify gc_content(dna): fraction of bases that are G or C, with the worked example gc_content('GGCC') == 1.0. Draft it with the assistant. Read it aloud, line by line. Write assert gc_content('GGCC') == 1.0 as the gentle test and assert gc_content('') == 0 or a documented decision not to allow it as the nasty one. Run both. This models the full order once before anyone works alone.

Three small functions

For each function below, follow the full order: specify with a worked example first, draft, read every line, write one gentle and one nasty test, run both. Do not move to the next function until the current one’s tests pass.

Exercise 37-1

AI: Drafter

is_palindrome(dna): True if the DNA string reads the same as its own reverse complement. Worked example: is_palindrome('GAATTC') == True. Nasty case to consider: an odd-length string, and a string containing a base outside A, T, G, C.

Exercise 37-2

AI: Drafter

count_codon(dna, codon): how many times a given three-letter codon appears, including overlaps. Worked example: count_codon('ATGATGC', 'ATG') == 2. Nasty case to consider: a codon that does not appear at all, and a codon longer or shorter than three letters.

Exercise 37-3

AI: Drafter

most_common_base(dna): the single most frequent base in a DNA string. Worked example: most_common_base('GGGATC') == 'G'. Nasty case to consider: a tie between two bases, so decide, in writing, before you draft, what you want to happen, since last term’s cohort found the assistant will pick silently and inconsistently if you do not.

Part 3, Catch the silent bug

Not every draft that passes a gentle test deserves your belief, which is the entire reason the nasty test exists. This round is curated so the gentle test passes and the nasty one does not, on purpose.

Exercise 37-4

AI: Drafter

Specify gc_content(dna) again, but this time specify it to be case-insensitive: it should count lowercase g/c the same as uppercase. Worked example: gc_content('ggcc') == 1.0. Draft it, read it, and write two tests: assert gc_content('GGCC') == 1.0 and assert gc_content('ggcc') == 1.0. Many drafts pass the first and silently fail the second because they only check the uppercase letters. If yours does, do not just accept a patched version, reread the fixed line until you can say in one sentence why the first draft missed lowercase input.

Drafting a method, not just a function

Classes entered this week, and a method is drafted the same way a function is, specified first, read in full, tested before belief.

Exercise 37-5

AI: Drafter

Specify a small Codon class with an attribute bases and a method translate(self) that returns the corresponding amino acid letter for a short, fixed table of codons you provide (four or five entries is enough). Worked example: Codon('ATG').translate() == 'M'. Draft the class, read __init__ and translate line by line, and write one gentle test plus one nasty test using a codon not in your table, decide, before drafting, what should happen then, and check the draft actually does what you decided rather than whatever it happened to do.

Logbook

For your logbook this week, name the one function or method from today where reading it line by line, before testing, made you suspicious enough to write a nastier test than you otherwise would have. Say what specifically in the code raised your suspicion, and whether the nasty test confirmed it or turned out to be unfounded.