January 19, 2026

Stop building utility layers that hide decisions

Abstraction without opinion delays the decisions that make software correct.

January 15, 2025·1 min read·Caleb Cannon

Judgment: Utilities should encode a decision, not avoid one.

A utility layer that avoids decisions does not reduce complexity. It relocates it. The complexity returns later, when the system needs a judgment and the utility has none.

Mechanism

Utilities are a way to enforce a policy. If they are only a collection of helpers, they are not a layer, they are just a junk drawer. The real mechanism is constraint: the utility chooses one path and makes other paths harder.

export function toMoney(value, currency = 'USD') {
  return new Intl.NumberFormat('en-US', {
    style: 'currency',
    currency,
  }).format(value)
}

This is a decision. It defines locale and format. It is not pretending to be universal.

Tradeoffs

Opinionated utilities can be wrong. That is fine. The cost of a wrong opinion is lower than the cost of no opinion. You can change a decision. You cannot debug a vacuum.

Signal

If your utility API reads like a wrapper around every possible option, you have not built a layer. You have built an escape hatch.