Study notes · 7.4% of the exam

Software Engineering Foundations

Apply everyday engineering practice to Claude applications: robust REST and JSON handling, correct async code, disciplined version control, Claude Code in CI, rigorous review of AI-written code, and safe small- and large-scale refactoring.

Key points

  1. 1

    REST retry safety: GET, PUT (full replacement) and DELETE are idempotent. POST is not, so send an idempotency key or deduplicate on the server before retrying automatically after a timeout.

  2. 2

    Status codes decide how to recover. On a 400 invalid_request_error, fix the request and do not retry it unchanged. On a 429 or 5xx/529, retry with exponential backoff that respects retry-after. The official SDKs retry these automatically, twice by default (max_retries).

  3. 3

    Prefer cursor (keyset) pagination over a stable sort key. Offset pagination over a changing dataset produces duplicates and gaps. Claude list endpoints return has_more and last_id, and you pass last_id as after_id; the SDKs can also paginate automatically.

  4. 4

    Treat model output as untrusted input. For JSON, constrain the format with structured outputs or a tool input_schema, then validate against the schema in code. Never eval model output or clean it up with regexes and hope.

  5. 5

    Evolve JSON contracts additively. Add new fields, keep deprecated ones populated during a migration window, version the schema, run consumer contract tests in CI, and have consumers ignore unknown fields.

  6. 6

    Async: in async frameworks use AsyncAnthropic, because a synchronous client blocks the event loop. Stream with async with client.messages.stream(...) and async for text in stream.text_stream.

  7. 7

    Limit concurrency with a semaphore or worker pool sized to your rate limits. An unbounded asyncio.gather over thousands of calls causes 429s and memory spikes, and by default its first exception propagates to the caller.

  8. 8

    Design batch jobs so that one bad item cannot abort the run. Handle errors per item, record permanent failures by ID, and make reruns skip items already completed.

  9. 9

    Streaming: the HTTP 200 arrives before generation finishes, so errors such as overloaded_error can arrive as an error event mid-stream. Never save partial text as a complete answer.

  10. 10

    Version control: keep PRs small with one intent each, and keep behavior-preserving refactors separate from bug fixes. Run parallel Claude Code sessions in separate git worktrees (--worktree) so their edits cannot collide.

  11. 11

    In CI and SDLC, use the Claude Code GitHub Action or headless claude -p with scoped --allowedTools, and optionally --output-format json. Keep the API key in a secret (e.g. ANTHROPIC_API_KEY), never in the workflow file. --bare skips loading local hooks, plugins and CLAUDE.md for scripted runs.

  12. 12

    Code review with Claude: give it explicit criteria (for example in CLAUDE.md) plus the diff and surrounding code, and keep a required human approval. A fresh-context reviewer beats the authoring session. Be suspicious when test assertions change in the same PR as a fix.

  13. 13

    Small refactors: confirm the tests are green, change structure without changing behavior, and commit the refactor separately. Large refactors: add tests where coverage is thin, plan the work (plan mode), migrate incrementally in reviewable PRs, and record conventions in CLAUDE.md.

  14. 14

    Fan out codebase modernization: have Claude generate the task list, loop claude -p per file with --allowedTools, pilot on 2–3 files to refine the prompt, then run the full set. /batch spreads a change across subagents, each in its own worktree.

Test yourself on Software Engineering Foundations

Ten questions, with the answer and explanation after each one.