Getting better code.
8 MIN READ · UPDATED 2026-08Six habits that separate 'wrote some code' from 'wrote correct, idiomatic, testable code' — for engineers who use LADLE daily.
Claude Sonnet writes competent code by default. Getting genuinely-good code — the kind you'd merge without a rewrite — takes six specific habits. Each one is small; together they change the shape of what you get.
State the constraint that matters.
Every codebase has invariants that generic-good code violates. "Don't add new dependencies without discussion", "no server components can import from client-only modules", "our lint config requires trailing commas". If you don't state these, the model doesn't know them. If you state one specific constraint per prompt, you get code that respects it.
Paste the surrounding context, not just the target.
If you're asking for a refactor of one function, paste the function AND the two most-related callers. If you're asking for a new component, paste the two most-similar existing components. Style-matching is meaningfully better when the model can see what your codebase looks like already.
Ask for the small change first.
The instinct is to describe the end state and ask for the code. Better pattern: describe the change you're trying to make, and ask "what's the smallest diff that accomplishes this". You'll get 15 lines of change instead of a well-intentioned 200-line rewrite that includes unrelated cleanup.
Ask for tests explicitly.
Left to itself, the model writes the code and skips the tests. Adding "and write the two most important tests for this — the happy path and the one edge case that would catch the most likely regression" doubles the useful output. The 'two most important' framing is deliberate — asking for "tests" produces a mediocre suite of five; asking for two specific ones produces sharper tests.
When it's wrong, say what's wrong specifically.
"This doesn't work" produces a defensive rewrite that changes random things. "This runs, but it returns null when the input array is empty — should return an empty array to match the caller's contract" produces a targeted fix in the right place. Specificity in critique is proportional to specificity in fix.
Read the code before you run it.
The output is a first draft, not a finished artifact. The 30 seconds you spend reading through the returned code catches most subtle bugs — misused APIs, wrong types, off-by-one errors — before you burn 5 minutes running and debugging. If you routinely ship code you haven't read, the ratio of net-productivity from AI tools inverts.
What Sonnet is genuinely good at.
Long-context reading of a whole file or module. Refactors that preserve public APIs. Explaining stack traces. Writing tests once you've written the implementation. Migrating between framework versions with clear diffs. Translating between languages (TypeScript to Python, Bash to Node, etc.).
What it's genuinely bad at.
Anything requiring genuine architectural taste on greenfield code (it will make competent choices that a strong senior would disagree with). Novel algorithm design where correctness matters and the pattern isn't in training data. Anything involving very recent library versions where its knowledge is stale — always specify version numbers if they matter.
- State the specific constraint that matters — style rules, invariants, forbidden dependencies.
- Paste surrounding context so style-matching works.
- Ask for the smallest diff, not the end state.
- Request the two most important tests, not 'tests'.
- Be specific when critiquing bad output — specificity in is specificity out.
- Read the code before running it. Every time.