Design and review checklist
Project overview and reading path
Use this as a review reference after reading the relevant lessons. Apply only items that fit the change. Each link explains the rationale, costs, and examples.
Choose the contract
- Name a concrete mistake the design prevents; use the simplest representation that preserves the contract. Purpose
- Give shared records precise fields. Keep required fields required; parse dates and timestamps at the boundary. Data modeling
- Preserve relationships between arguments and results, and encode structural preconditions where useful. State, generics
Handle outcomes and alternatives
- Declare supported recovery decisions as typed outcomes. Document why any
remaining exceptions must unwind the operation; a
Raises:section is not a checked failure contract. Failure contracts - Narrow outcomes before consuming payloads and check closed unions with
assert_never. Avoid unchecked unwraps and discarded failures. Result handling - Distinguish unavailable values from valid zero or emptiness with typed outcomes. Undefined metrics
- Retain the diagnostic details callers need without turning programming defects into routine failures. Result handling
Validate at boundaries
- Validate external data with explicit coercion, missing-field, and extra-field policies; expose precise types afterward. Keep unknown library values inside adapters. Boundary validation
- Use declared fields and typed interfaces in application logic. Keep necessary reflection local to documented adapters or tests. Dynamic access
- Keep configuration and CLI constraints consistent, and side effects at the application edge. Settings, CLIs
- Define behavior for malformed input at the typed boundary. SDK adapter
Keep components and state understandable
- Use small protocols where substitution is needed. Implementations and wrappers must preserve error and mutation contracts. Composition
- Model state-dependent operations explicitly and account for shallow immutability and aliases. State, immutability
- In numerical code, keep native arrays and tensors. Check numerical behavior separately from static contracts. Limits
Verify the promises
- Check passing code and the intended static rejections. Keep workarounds narrow and supported by evidence. Static evidence, checker limitations
- Test observable behavior and the promised checker rejection. Reading examples
- Distinguish static guarantees, runtime validation, and conventions. Do not infer exception freedom, ownership, or scientific correctness from passing types. Benefits and limits