Make Invalid States Hard To Express

make-invalid-states-hard-to-express

Summary

Repeated validation spreads invariants across callers and lets unchecked values travel too far. Move the rule into a construction boundary or precise type when that reduces downstream reasoning without adding local ceremony.

Problem

Repeated validation asks every caller to remember the same rule before using a value safely. One missed check can let an empty identifier, unparsed URL, invalid state transition, or unsupported mode travel deeper into the system.

Preferred Move

Move the invariant into the boundary where uncertain input becomes a trusted value. Use precise types, constructors, parsers, or enums so downstream functions accept a representation that carries the invariant in its type or construction path.

Tradeoff

Do not wrap values that are constructed and immediately destructured. A precise type should reduce downstream reasoning; it should not add ceremony around a value that stays local to one branch.

Agent Instruction

When the same validation protects the same invariant in multiple places, consider a precise type or
construction boundary. Avoid wrapper types that do not reduce downstream checks.

Examples

Bad: the API accepts raw strings, so every caller must remember that blank names are invalid.

pub fn publish_pattern(name: String) {
    todo!()
}

Good: uncertain input becomes a trusted value before it reaches the publishing API.

pub struct PatternName(String);

impl PatternName {
    pub fn parse(input: &str) -> Result<Self, PatternNameError> {
        todo!()
    }
}

pub fn publish_pattern(name: PatternName) {
    todo!()
}

References

Source Use Note
C-VALIDATE supports Prefer argument types that rule out bad inputs.
M-AVOID-WRAPPERS adapts Avoid wrappers when they add API ceremony without value.