Skip to lesson

AnthropicClaude Certified Architect – Foundations2026-103.5 Apply iterative refinement techniques for progressive improvement

Define passing behavior before implementing code

Completed by the knowledge check

Learning objective

Write tests for normal behavior, edge cases, and relevant performance requirements before implementation, then iterate on observed failures.

Core idea

Give Claude Code an executable definition of success before asking it to implement a feature. A test suite turns the next correction from “this looks wrong” into an observed difference between required and actual behavior. Anthropic’s Claude Code best practices recommend checks Claude can run and results it can read: tests, build exit codes, linters, and scripts that compare output with fixtures.

Both the exam guide and Anthropic’s Claude Code best practices describe writing tests before code. The best-practices page recommends having one Claude write tests, then another implement code to pass them; fresh context reduces bias toward code Claude just wrote. The architect’s job is to ensure those checks represent the intended contract. Tests derived uncritically from generated implementation can certify an interpretation the owner never approved.

This Bite owns the overall test-first loop. See 3.5.1 for clarifying the contract with examples and 3.5.3 for the smaller correction packet used when one additional edge case fails.

How it works

Cover three kinds of acceptance evidence

Before implementation, define what an ordinary request does, what boundary inputs require, and which performance requirements matter to the feature. The following acceptance matrix is an illustrative project contract for a customer migration; its quantities are not Anthropic limits.

Coverage classRequired behaviorCheck prepared before implementation
Normal behaviorEvery valid populated contact becomes the approved destination shapeCompare the complete converted record with an owner-approved fixture
Edge casesEmpty and null optional values retain their agreed absence semantics; malformed required IDs are rejectedSeparate assertions for each input category and expected outcome
Relevant performanceConvert a fixed fixture of 100,000 valid records in under 10 seconds on the designated runnerMeasure the converter over that fixture and record elapsed time and output count

A performance requirement needs its workload and measurement conditions. “Make it fast” cannot determine whether a change passed. In this scenario, the owner specifies the runner and fixture before implementation, so a timing result has a meaning. A smaller input, skipped records, or a different machine cannot silently substitute for the agreed measurement.

Normal behavior also needs complete outputs. Checking only that the result has a phone field can miss a dropped customer ID or an extra unwanted field. Edge cases should express separate policy choices: a missing optional phone and an invalid required identifier need not produce the same outcome.

Review the tests before they become the target

Claude Code’s common-workflows page says it can generate tests matching existing project styles, frameworks, and assertion patterns. Ask it to inspect the relevant test files and propose checks for the stated behavior. Review the fixtures, expected outputs, and performance conditions before asking for implementation. Write and review the suite in one session, then start a separate implementation session with the reviewed requirements and tests. You can also use /clear to reset context before supplying those artifacts. This separates test authorship from implementation while keeping the approved expectations available.

Run the checks before implementing. Inspect why they fail. A failure because the implementation is absent is different from a broken fixture loader or an unavailable test dependency. The useful starting signal is that the checks exercise the intended interface and would reject the missing or incorrect behavior. An environment error tells you to repair the test setup, not the converter.

Do not require every test to fail. Existing code may already satisfy part of the contract. The important ordering is that the required behavior exists independently of the proposed solution and that at least the targeted deficiency is observable.

Let observed failures drive the next change

Specify the project’s actual command to run the checks and identify the test files. Ask Claude to implement the approved behavior, run the command, read its output, and repair the observed failures.

A useful result includes the command, the failing test name, the expected and actual values or exception, and the relevant stack trace. Anthropic’s debugging workflow explicitly recommends providing the reproduction command and stack trace. If you run the checks outside Claude Code, paste that evidence into the conversation. If Claude runs them, ask it to show the evidence rather than assert that the suite passes.

Use the failure to locate the violated requirement. If null handling fails, repair that behavior and retain the populated-record checks. If the performance check fails after all outputs match, investigate the measured conversion path rather than weakening the functional assertions. Each round should preserve already satisfied requirements while addressing the observed deficiency.

Preserve general behavior when checks pass

Anthropic’s prompting best-practices page warns that coding can overfocus on passing tests. Its recommended instruction asks for a general-purpose solution for all valid inputs, without hard-coded test values, and states that tests verify correctness rather than define the solution.

Carry that instruction into the implementation request. Ask Claude to report an incorrect or infeasible test instead of working around it. A test expecting the wrong field value should trigger a requirement review, not special-case code for its fixture. Changes to expected outputs need the same owner review as the original suite.

The final evidence should include all three coverage classes that matter here. A passing focused functional check is an intermediate result; it does not establish that the agreed performance workload passed. Conversely, a fast converter that silently drops failing records has not met the functional contract.

Each round runs the checks, repairs the observed failures, and ends only when every coverage class that matters has passed.

Each round repairs the observed failures until every coverage class passesStarts by writing and reviewing the suite, then running the checks before implementing and inspecting why they fail. An environment error means repairing the test setup. An absent implementation leads to implementing the approved behavior, running the command and reading its output. If any coverage class still fails, the observed failures are repaired and the command runs again; when all pass, the result is the final evidence.Environment errorImplementation absentNoYesWrite and reviewthe suiteRun the checksbeforeimplementingWhy do they fail?Repair the testsetupImplement theapproved behaviorRun the command,read its outputAll coverageclasses pass?Repair the observedfailuresFinal evidence

Key distinctions and trade-offs

Tests first versus tests after: Prewritten tests express the intended behavior before a generated implementation influences the expected answers. Tests added afterward can still be valuable, but require particular care to avoid copying the implementation’s mistakes.

Observed failure versus a success claim: “The tests pass” describes an outcome without exposing how it was obtained. A command and its returned output let you assess which checks ran and whether they covered the requirement.

Correctness versus performance: Correct outputs and acceptable execution time are different acceptance conditions. Neither substitutes for the other. Include a performance gate when the feature has a relevant requirement, rather than inventing an arbitrary benchmark for every small change.

Writing the checks first costs effort before the visible implementation appears. That effort buys a stable correction target and reduces repeated manual interpretation. It is particularly useful for transformations whose many small branches otherwise require line-by-line review after every generated change.

Architecture / decision scenario

A developer productivity team asks Claude Code to implement a migration converter. The team prepares normal-record fixtures, independent empty/null cases, rejection cases for malformed required IDs, and the 100,000-record timing check with its designated runner. It reviews those expectations in the test-authoring session, then provides the approved suite and requirements to a separate implementation session.

The initial run exposes the missing converter. Claude implements it and runs the supplied command. Normal behavior passes, but explicit null raises an exception and the timing check exceeds 10 seconds. The developer supplies both observed failures and asks Claude to explain whether the fixes interact; correction grouping is covered in 3.5.5.

The following run must show correct outputs for ordinary and boundary inputs plus the agreed workload within its threshold. The developer rejects a proposal to skip null records or shrink the timing fixture. If the threshold proves infeasible under the approved contract, Claude reports that constraint for a decision rather than changing the test to manufacture success.

Common exam traps

  • Implementing first and accepting tests that reproduce whatever the implementation does.
  • Covering ordinary values while omitting boundary cases or relevant performance requirements.
  • Treating missing dependencies as evidence of incorrect business logic.
  • Sharing “still broken” instead of the command and actual failure output.
  • Allowing hard-coded fixtures, suppressed assertions, or skipped records to produce a green result.
  • Treating one passing check as evidence that every acceptance condition passed.

What to remember

Prepare and review the acceptance suite before implementation. Include normal behavior, distinct edge cases, and measurable performance conditions when they matter. Iterate on actual failure evidence, preserve the contract across rounds, and require a general solution rather than a test-specific workaround.

Knowledge check

References