#Field Notes

Unions Over Enums, Mostly

A small preference with a surprisingly large effect on the bundle.
author
Odette Lang
category
"Field Notes"
reading
"3 min"
unions-over-enums-mostly.md

What surprised me was how much of the cost was in the waiting. The work itself was quick. The build took nine minutes, the review sat for a day and the deploy window was on Thursdays. Shaving a second off the code path would have been easy and would not have changed a thing.

Do the rename in its own commit. It feels like extra ceremony right up until someone tries to find out when the behavior changed and the history shows a single enormous diff. Separating the mechanical change from the interesting one costs thirty seconds and saves a very long afternoon.

A good default is one that nobody has to think about. We spent a long time making this configurable and then discovered that every single environment used the same value. So we deleted the setting, wrote the value down in one place and removed an entire class of support questions.

The actual fix

type Result<T> = { ok: true; value: T } | { ok: false; error: string };

export function parse(input: unknown): Result<number> {
  if (typeof input !== 'number') {
    return { ok: false, error: 'not a number' };
  }

  return { ok: true, value: input };
}
plain preformatted text with no code element

Write the failing case down before you change anything. It can be a test, a curl command or a sentence in the ticket. The point is that you have something outside your own head that says what wrong looks like, because your memory of the bug starts drifting the moment you begin working on it.

Nobody reads the documentation until something is on fire, so write it for that reader. Put the command they need at the top. Say what it changes and how to undo it. Leave the history of how we got here for a later section, where it can be appreciated at leisure.

Test it with the keyboard before you call it finished. Tab through the page, press Enter on things and see where focus lands afterwards. It takes less than a minute, it needs no tooling at all, and it finds a remarkable number of problems that an automated checker will never report.

Trying it yourself

After that, the only thing left was to delete the workaround. This is the step that tends to get skipped, which is how a codebase ends up with fixes for bugs that stopped existing years ago. Put the removal in the same ticket, or accept that it will outlive everyone on the team.

The fix itself took four lines. Finding out where those four lines belonged took most of a week, including one afternoon spent proving that the bug was not where everyone, including me, had been absolutely certain it was. That is a normal ratio, and it is worth telling new people about.

Naming turned out to matter more than the structure did. Once the function stopped being called process and started saying what it did, two of the three bugs in the surrounding code became obvious to everybody reading it, including the person who had written them, who was me.

1 comment on “Unions Over Enums, Mostly”

Leave a Reply

Your email address will not be published. Required fields are marked *