misuse-resistance
Misuse Resistance
Interfaces must be easy to use correctly and hard to use incorrectly (Scott Meyers; the "pit of success"). A design that relies on developer discipline — remembering to call something, reading a comment, knowing the convention — is a defect, because a competent-but-rushed developer will eventually get it wrong. Hunt for:
-
False affordances: a signature that implies safety it doesn't provide.
function createUser(name, email, role) { return { name, email, role }; }Callers reasonably assume a
createfunction validates or enforces something; this one is an object literal in a trench coat, and its existence discourages callers from validating. Give it a real job (validate, normalize, apply invariants) or delete it and use a literal openly. -
Temporal coupling: correctness depends on call order that nothing enforces.
verifySession(token); // step 1 — easy to forget const ctx = buildContext(req.body); // step 2 — also accepts unverified data!Fix by fusing the sequence (
contextFromToken(token)verifies internally) or by making the later step require unforgeable proof of the earlier one (it accepts only the type that step 1 returns, and nothing else can produce that type). -
Validation separated from construction: "parse, don't validate" (Alexis King). Don't check a string is a valid email and keep passing the string — parse it once into an
EmailAddresstype whose only constructor does the check, then requireEmailAddressdownstream. Possession of the value is proof of validity; unvalidated data becomes unrepresentable ("make illegal states unrepresentable"). Full treatment — branded domain types, deriving types from constants, correlated fields — intype-driven-design.