Prompt Engineering for Developers: A Practical Guide
Getting consistent, useful output from LLMs isn't magic — it's a craft. These are the techniques that actually work in production.
Most developers discover prompt engineering the same way: they type something into ChatGPT, get a mediocre result, assume the tool is limited, and move on. Then a colleague shows them a prompt that produces something genuinely impressive — and suddenly the skill gap is obvious.
Prompt engineering is a craft. Here are the techniques that actually work when you're building real things, not just experimenting in a playground.
The Core Mental Model
Think of an LLM as an extremely well-read collaborator who has no memory between sessions unless you provide it, will answer confidently even when uncertain, takes instructions very literally, and performs better with examples than with abstract rules.
Once you internalize this, you write prompts differently.
Technique 1: Role + Task + Format
The simplest structural improvement: tell the model who it is, what to do, and how to respond.
Weak prompt: "Write test cases for a login screen."
Strong prompt: "You are a senior QA engineer writing test cases for a mobile app. Task: Write test cases for the login screen of an iOS app. Include: happy path, error states (wrong password, no internet, empty fields), edge cases. Format: Return a numbered list. Each item: [Test ID] | [Scenario] | [Expected Result]"
The second prompt takes 10 seconds longer to write and returns something you can use directly.
Technique 2: Show, Don't Just Tell
Few-shot prompting — giving examples of input/output pairs — dramatically improves consistency. This is especially useful when generating structured data or code in a specific style.
Example: "Convert these bug descriptions into Jira ticket summaries. Here are two examples: [Input] → [Output]. Now convert this new one: [Input]." The model calibrates its output format to match your examples far more reliably than following abstract instructions.
Technique 3: Chain of Thought for Complex Problems
For reasoning tasks, asking the model to "think step by step" before answering genuinely improves output quality. The model is more accurate when it externalizes its reasoning rather than jumping straight to an answer.
This works especially well for architectural decisions, test strategy planning, and debugging sessions where you want the model to explain its reasoning as it works through a problem.
Technique 4: Constrain the Output Space
Unconstrained outputs lead to bloated, inconsistent results. Be specific about what you don't want:
- "Return only valid JSON. No explanation, no markdown wrapper."
- "Maximum 3 bullet points per section."
- "Do not include test cases for features not mentioned in the spec."
- "If you're uncertain about something, say so explicitly rather than guessing."
Technique 5: Iterative Refinement
The best prompts for production use are never written in one shot. Write a rough prompt, run it 3–5 times, note where the output diverges from what you want, add constraints or examples to address each failure mode, and test again.
For anything running in a pipeline, treat prompt development like code: version control it, test it against a suite of inputs, and review changes before shipping.
Where Developers Usually Go Wrong
Too much context: Dumping an entire codebase into the context window doesn't help. Models perform better with focused, relevant context than with everything you might possibly need.
Ambiguous success criteria: "Write a good summary" gives the model nothing to optimize for. "Write a 2-sentence summary that a non-technical stakeholder could read and immediately understand the impact" is specific enough to evaluate.
Not using system prompts: If you're using an API, the system prompt is where you set persistent constraints and persona. Don't try to do everything in the user turn.
A Template Worth Saving
This structure consistently gets 80% of the way there on the first try:
# Role
You are [role].
# Context
[What they need to know to do this well]
# Task
[Specific thing to do]
# Constraints
- [What to include/exclude]
- [Format requirements]
- [Length/style requirements]
# Examples (optional but powerful)
[Input → Output pairs]I use these techniques daily in my QA and development work. See the projects page for examples of AI-integrated tools I've built.