A value object rejecting an invalid input with a message that named the type rather than the problem.
// before
if ($cents < 0 || $currency === '' || ! $this->known($currency)) {
throw new InvalidArgumentException('invalid money');
}
// after
if ($cents < 0) {
throw InvalidMoney::negativeAmount($cents);
}
if (! $this->known($currency)) {
throw InvalidMoney::unknownCurrency($currency);
}
One check per condition and a named constructor per failure costs six lines and turns a support conversation into a log line. The message that says “invalid money” appears in a log with no context about which of three things was wrong, and the person reading it is you, in a year, with the input no longer available.