AI Pair Programming: Tips to Get Better Code
Practical habits that turn AI coding assistants from a slot machine into a reliable pair, from context and prompts to verification.
Key takeaways
Practical habits that turn AI coding assistants from a slot machine into a reliable pair, from context and prompts to verification.
On this page
AI Pair Programming: Tips to Get Better Code#
The gap between people who love AI coding assistants and people who think they produce garbage usually comes down to habits, not tools. Same model, same editor, wildly different results. The difference is how you feed the tool, how tightly you check it, and when you take the keyboard back. Here is what actually moves the needle.
Context is everything#
Most bad output traces back to a model guessing at things it could have known. It invents a function that already exists, picks the wrong error type, or ignores your naming conventions because nobody showed it any.
More relevant context beats a longer prompt every time. Before you ask for code, make sure the tool can see the files it needs: the types it will touch, a similar function to mimic, the test file, the config. In editors like Cursor or Claude Code you point the tool at those files or let it search; in a chat window you paste them. Either way, relevant beats verbose. Ten lines of the actual interface are worth more than three paragraphs describing it.
If your project has conventions, put them where the tool reads them. A short rules file or AGENTS.md with your import style, error handling pattern, and testing approach saves you from correcting the same drift on every request.
Be specific about intent and acceptance criteria#
Vague requests get vague code. State what you want, the constraints, and how you will know it is done.
Before:
Tweet this ↗add caching to the user service
After:
Tweet this ↗Add an in-memory cache to
getUserByIdinuser-service.ts. Use the existingLRUCachefromlib/cache.ts(see howproduct-service.tsuses it). TTL 60 seconds, max 1000 entries. Invalidate the entry onupdateUser. Keep the function signature unchanged. Don't add a new dependency.
The second prompt names the file, the pattern to copy, the constraints, and the boundaries. There is very little room to wander.
For anything non-trivial, ask for a plan before code. "Outline the approach and the files you'll change, then wait." A plan is cheap to read and cheap to correct. A 400-line diff built on a wrong assumption is neither. This is the same instinct behind spec-driven development: agree on the shape of the work before generating it.
Work in small steps and verify each one#
The single biggest mistake is accepting a giant diff you have not read or run. AI output looks confident whether it is right or wrong, so confidence is no signal at all.
Keep the loop tight: generate, read, run or test, correct. Ask for one function, not one feature. Run it. Then ask for the next piece. Small steps mean that when something breaks you know exactly which change caused it, and the model has fresh, working code to build on instead of compounding its own earlier mistakes.
Never merge unread code. If you would not sign off on it in a colleague's pull request, do not sign off on it because a model wrote it.
Show the pattern you want#
Models are strong at imitation and weak at guessing house style. Give them an example. "Write this the way handlers/orders.ts is written" or a short snippet of the exact shape you expect will do more than any amount of adjectives. This few-shot nudge is why pointing at existing code works so well: your codebase is the best style guide you have.
Use tests as a spec and a safety net#
Tests are where AI pairing pays off twice. Written first, they pin down the behavior you want, and the model has a concrete target instead of a fuzzy description. Written after, they catch the subtle wrongness that reads fine on the page.
Ask the model to write tests too, but review them like any other code. AI-generated tests have a habit of asserting whatever the code happens to do, including the bug. Check that they test real behavior and edge cases, not just that the function returns something. A test suite you trust lets you accept changes faster because the safety net is real.
Know when to stop prompting#
Sometimes the model gets stuck in a loop. It fixes one error and reintroduces another, or keeps confidently proposing the same broken approach with cosmetic changes. When you have re-prompted three times and you are going backwards, stop. Read the code yourself, find the actual problem, and either write the fix or hand the model a much narrower, better-informed request. Fighting a stuck model costs more time than the ten lines you were trying to avoid writing.
Manage the context window#
A focused session beats a bloated one. Long conversations accumulate stale files, abandoned approaches, and half-finished ideas that quietly pull the model off course. When you switch tasks, clear the context and start fresh. Do not dump the whole repository in and hope; give the tool the slice that matters.
Review for security and correctness#
You own the code, not the AI. Assistants reproduce the insecure patterns they learned from: string-built SQL, missing input validation, secrets in plain sight, dependencies pulled in without a second thought. The model will not feel bad when that ships, and it will not be the one paged at 2am. Treat every generated change as untrusted input until you have read it, and put security-sensitive code through real scrutiny. Our guide to securing AI-generated code covers what to look for.
The habits that matter most#
If you only change three things, change these:
- Feed sharp context. Point the tool at the real files, types, and a pattern to copy. This alone fixes most bad output.
- Verify every step. Small diffs, read and run before moving on. Never merge code you have not read.
- Own the review. Correctness and security are yours. The AI drafts; you are accountable for what ships.
Everything else is a refinement on those three.
The call we'd make#
Treat the assistant like a fast, eager junior who has read a lot and remembers nothing about your project. Give it context, keep the tasks small, check the work, and stay in charge of the decisions that matter. Do that and AI pairing is a genuine multiplier. Skip it and you are just merging plausible-looking code you do not understand.
Pick a tool that fits this loop, then build the habits on top of it. If you are still choosing, start with our roundup of the best AI coding assistants. The tool matters less than what you do with it.
Get the DevOps Troubleshooting Cheat Sheet
Subscribe and get our free one-page reference for the errors that eat an afternoon — CrashLoopBackOff, OOMKilled, Terraform state locks, and more — plus new guides as we publish them.
TCP vs UDP: What's the Difference?
A practical look at how TCP and UDP trade reliability for speed, and how to pick the right one for your service.
REST API Best Practices Every Developer Should Know
A practical guide to designing REST APIs that stay predictable, easy to consume, and safe as your service grows.
More from AI
Explore more articles in this category
AI CLI Agents in CI: Claude Code vs Codex CLI vs Gemini CLI
Running a coding agent on a laptop is a preference. Running one in a pipeline is an architecture decision about credentials, sandboxing, and non-interactive failure.
Best Vector Databases in 2026: Do You Even Need One?
Most teams shipping retrieval do not need a dedicated vector database. Here is where Postgres runs out, and which specialist actually helps when it does.
Three LLM Providers, One Cloud Region: The September 3 Outage
ChatGPT, Claude, and Grok degraded together when Azure East US failed. Gemini stayed up. Multi-provider failover does not help when your providers share a substrate.
You might have missed
Evergreen posts worth revisiting.