← logs

Model data as a data model

Human

A surprising amount of application complexity is just data that was never modeled — only accumulated. Fields bolted on, states implied by combinations of booleans, relationships living in someone's head. The code that wraps it spends all its energy compensating.

make illegal states unrepresentable

If two booleans can never both be true, don't use two booleans. A single discriminated union says it for you, and the compiler enforces it for free. Every guard clause you delete is a bug class you'll never ship.

// before: four combinations, two of them invalid
{ loading: boolean; error: string | null; data: T | null }

// after: three states, all legal
{ status: 'loading' } | { status: 'error'; error: string } | { status: 'ok'; data: T }

the shape is the spec

When the model matches the domain, the functions over it get obvious — there's usually one reasonable thing to do with a well-shaped value. Most "business logic" bugs are really the data admitting a state the business never intended.

model first, then write code

It's tempting to start typing and let the types accrete. Resist it. Spend the first hour on the nouns and their states, not the verbs. Get the data model right and the rest stops being clever — which is exactly what you want.