Turn a vague idea into inputs, outputs, functions, pseudocode and test cases before writing code.
Why it matters
The most common reason a beginner project stalls is not a hard bug. It is starting to type before knowing what the program should do. Ten minutes of planning on paper saves hours of rewriting, and the plan doubles as a checklist that tells you when you are finished. Professional developers plan too; they just call it requirements, design and test cases.
Step 1: write the problem in one or two sentences
Be specific about who uses it and what they get:
A lab technician has a CSV of sample masses from three balances. The program should report the mean and range for each balance and flag any sample more than 0.5 g from its balance's mean.
If you cannot write this sentence, you are not ready to code. Vague goals ("analyse the data") lead to programs that never feel done.
Step 2: pin down inputs and outputs
Write out a tiny, concrete example of each, by hand:
Input (masses.csv):
balance,sample,mass_g
B1,S-01,12.40
B1,S-02,11.80
B2,S-03,12.10
B1,S-04,13.10
Output:
B1: n=3 mean=12.43 range=11.80-13.10
B2: n=1 mean=12.10 range=12.10-12.10
FLAG B1 S-02 11.80 (0.63 from mean)
FLAG B1 S-04 13.10 (0.67 from mean)
Working out the expected output by hand is the single most valuable planning step. It forces you to decide the details (how many decimals? sorted how? what counts as "more than 0.5 g"?), and it becomes your first test.
Step 3: list the edge cases
Ask "what could be weird about the input?":
- An empty file, or a file with only a header.
- A mass that is blank or
n/a. - A balance with only one sample (range is zero; can a sample be flagged?).
- Extra spaces or different capitalisation (
b1vsB1).
Decide what the program should do for each. "Skip and count it" or "stop with a clear message" are both fine; pick one deliberately.
Step 4: break it into functions
Each function should do one job you can describe in a sentence, with clear inputs and outputs. Write the signatures before any bodies:
def read_rows(path): # -> list of dicts from the CSV
def parse_mass(text): # -> float, or None if unusable
def group_by_balance(rows): # -> {balance: [(sample, mass), ...]}
def summarise(groups): # -> {balance: {"n", "mean", "min", "max"}}
def find_flags(groups, summary, limit=0.5): # -> list of (balance, sample, mass, diff)
def format_report(summary, flags): # -> str
Notice the pattern from the previous lesson: read, parse, group, summarise, report. Most small data programs fit it.
Step 5: write pseudocode
Pseudocode is the plan written in plain language, structured like code but without worrying about syntax:
for each row in the file:
mass = parse the mass text
if mass is unusable:
add 1 to the skipped count
skip to the next row
add (sample, mass) to that balance's list
for each balance:
mean = average of its masses
for each sample in the balance:
if the distance from mean is more than 0.5:
add it to the flags list
If a step in your pseudocode is fuzzy ("work out the flags somehow"), that is where you will get stuck while coding. Break it down further now.
Step 6: write the tests first
Turn your hand-worked example into checks before writing the functions:
assert parse_mass("12.40") == 12.4
assert parse_mass("n/a") is None
assert parse_mass("") is None
groups = {"B1": [("S-01", 12.4), ("S-02", 11.8), ("S-04", 13.1)]}
summary = summarise(groups)
assert round(summary["B1"]["mean"], 2) == 12.43
These fail at first, because the functions do not exist yet. That is the point: each one you make pass is visible progress, and when they all pass, you are done. This habit is the core of test-driven development, and it is exactly how the Do tab in this course works.
Step 7: build one function at a time
Implement the smallest function first (parse_mass), run its tests, then move to the next. Resist writing everything and running it once at the end; when that fails, you will not know which part is wrong. Commit or save a copy each time a function works.
Scope: what is in version 1?
Write down what you are not doing yet: no charts, no command-line options, no Excel files. A small program that works and is shared beats a big one that is half finished. Put extra ideas in a "later" list in your README.
Common mistakes
- Coding before you can state the problem. Write the sentence first.
- Skipping the hand-worked example. Without it you have nothing to test against.
- Giant functions. If you cannot describe a function in one sentence, split it.
- Ignoring edge cases until they crash the program. List them in the plan.
- Scope creep. Finish version 1 before adding features.
Quick recap
- State the problem in one or two specific sentences.
- Work out a small input and its expected output by hand.
- List the edge cases and decide how to handle each.
- Break the work into small functions with clear signatures, then write pseudocode.
- Write tests from your example first, then build and test one function at a time.
Try it
In the Do tab you will plan a small program of your own (or the grades analyser) on paper or in a text file, following these steps.