Skills101

AI Coding Assistants · Lesson 2 of 8 · Updated ·

Prompting for Code — Write Specs, Not Wishes (Context, Constraints, Examples and Acceptance Tests)

"Write a function to validate a phone number" gets you a function. Whether it's the function you need depends on everything you didn't say. Good prompting for code is mostly good requirements writing — a skill that also makes you a better engineer without AI.

1. Weak prompt vs strong prompt

Weak:

write a python function to validate indian phone numbers

The model must guess: Which formats? Return True/False or a cleaned number? Landlines? +91? Spaces? It will pick something plausible — maybe not what your app needs.

Strong:

Write a Python 3.12 function normalise_indian_mobile(raw: str) -> str | None.

  • Accept Indian mobile numbers typed in common ways: 9876543210, 98765 43210, +91 98765 43210, +91-98765-43210, 919876543210, 09876543210.
  • Return the number as +91XXXXXXXXXX, or None if invalid.
  • Valid mobiles have 10 digits starting with 6, 7, 8 or 9. Reject landlines, short numbers and non-Indian numbers.
  • No external libraries. Include a few assert tests covering valid and invalid inputs.

Now there is exactly one right answer, and the tests will prove it.

Prompt anatomy: role and goal, context (language, versions, existing code), the exact task and signature, constraints, examples of input and output, and acceptance tests or a definition of done

2. A reusable spec template

GOAL: what this code is for and who uses it (one or two lines)
CONTEXT: language + version, framework, relevant existing code/schema (paste it)
TASK: exact function/endpoint/component, with signature
INPUTS/OUTPUTS: types, formats, examples
RULES & EDGE CASES: empty input, limits, errors, time zones, money, permissions
CONSTRAINTS: libraries allowed/forbidden, style, performance, security
DONE WHEN: tests that must pass / behaviour to verify
OUTPUT FORMAT: just the code? code + tests? explain trade-offs first?

You won't need every line every time — but each line you skip is a guess you hand to the model.

3. Check the result like a reviewer

Here's what a good implementation of the strong prompt looks like, with the acceptance tests run for real:

import re

def normalise_indian_mobile(raw: str) -> str | None:
    digits = re.sub(r"[\s\-()]", "", raw)
    if digits.startswith("+91"):
        digits = digits[3:]
    elif digits.startswith("91") and len(digits) == 12:
        digits = digits[2:]
    elif digits.startswith("0") and len(digits) == 11:
        digits = digits[1:]
    if re.fullmatch(r"[6-9]\d{9}", digits):
        return "+91" + digits
    return None

valid = ["9876543210", "98765 43210", "+91 98765 43210", "+91-98765-43210", "919876543210", "09876543210"]
invalid = ["12345", "5876543210", "01414937243", "+1 415 555 0100", "", "98765432101"]
for v in valid:
    assert normalise_indian_mobile(v) == "+919876543210", v
for v in invalid:
    assert normalise_indian_mobile(v) is None, v
print("all", len(valid) + len(invalid), "acceptance tests passed")
all 12 acceptance tests passed

The tests came from the prompt. Writing the "DONE WHEN" section first is the single best habit in this lesson.

4. Techniques that consistently help

Ask for a plan first. For anything bigger than one function:

Before writing code, list the steps, the files you'd change, and any questions or assumptions. Wait for my OK.

You catch misunderstandings when they cost one message, not 300 lines.

Show, don't just tell. Paste an existing function written in your project's style and say "follow this pattern". Paste one real input row and the exact expected output.

Give the error and the code together (lesson 5) — never just "it doesn't work".

Split big tasks. "Build a full exam portal" → schema → API for one entity → tests → UI page → next entity. Small steps are easier to review and easier for the model to get right.

State what NOT to do. "Don't add new dependencies." "Don't change the function signature." "Don't touch files outside src/payments/."

Ask it to ask you. "If anything is ambiguous, ask me before assuming." Good assistants will.

Iterate precisely. Instead of "still wrong", say "For input [] it returns None; it should return 0.0. Keep everything else the same."

5. Example: a better prompt for a real task

Goal: Students should get a certificate when they pass every lesson quiz in a subject. Context: Next.js 16 + Prisma. Relevant models pasted below (User, Quiz, QuizAttempt, Certificate). Existing helper awardXp(userId, kind, refId, amount) pasted below. Task: Write checkTutorialCertificate(userId, topicId) that issues a certificate if the user has a passing attempt for every published lesson quiz in the topic. Rules: Only published quizzes count. Issue at most one certificate per user per topic (idempotent). Passing = score ≥ 60%. Constraints: Use the existing Prisma client; no raw SQL; one transaction. Done when: Unit tests cover: no quizzes, some passed, all passed, called twice (still one certificate). Output: Plan first, then code, then tests.

Compare that to "add certificates for tutorials". The second prompt produces something; the first produces your feature.

6. Prompts for learning (not just output)

When you're learning, change the request:

  • "Don't give me the solution. Give me a hint about which data structure to use."
  • "Here's my solution — what's the time complexity, and what edge case breaks it?"
  • "Explain this code line by line as if I'm in second year."
  • "Quiz me with 5 questions on Python dictionaries, one at a time."

You'll learn faster than with either a textbook or copy-pasting answers.

Common mistakes

  • One-line prompts for multi-step features.
  • Not pasting the relevant existing code, schema or error.
  • Accepting the first answer without tests.
  • Saying "make it better" instead of describing exactly what's wrong.
  • Pasting secrets (API keys, customer data) into prompts — lesson 7.

Quick recap

  • Prompt = spec: goal, context, task, inputs/outputs, edge cases, constraints, done when, output format.
  • Write acceptance tests first; check the result against them.
  • Ask for a plan first, show examples, split big tasks, say what not to do, iterate precisely.
  • For learning, ask for hints and explanations instead of full solutions.

Practice what you learned

📝 Quiz: Prompting for Code5 questions · instant answers & explanations · +10 XP · counts towards your free certificateTake the quiz →