constraining-primitive-valueslisted
Install: claude install-skill yutna/functional-design-skills
# Constraining Primitive Values
## Overview
A domain value is almost never "a string" or "a number". It is a booking
identifier, a percentage between zero and one hundred, a quantity of at
least one, an email address. When those are represented by primitives,
three things follow: the constraints live in prose, any value can be
passed where any other is expected, and the same check appears wherever
someone remembered it.
Wrapping each domain value in its own type, built only through a function
that can fail, fixes all three at once. This is the cheapest structural
improvement available in most codebases.
## When to use
- A function signature has two or more parameters of the same primitive
- The same format or range check appears in more than one place
- A comment or a schema documents what values are legal
- An identifier is passed as a string across module boundaries
- A number is a quantity, a rate, an amount, or a duration
Not for: values that genuinely are unconstrained free text with no rules.
## Core rules
1. **One type per domain concept**, even when the underlying primitive is
the same. `CustomerId` and `BookingId` are different types.
2. **Constructors can fail; return `Result`.** The constructor is the
only place the rule lives.
3. **No public raw construction.** If the wrapper can be built directly
from a primitive anywhere, the type is decoration.
4. **Unwrap late, at the edge.** Inside the domain, pass the wrapper.
Convert to a primitive only