Writing · essay

Name the system before you build it

When one word does several jobs, nobody can own it. How I split an estate into named subsystems, test each one, and enforce the names with a check that runs daily.

I once found a single word doing several jobs at the same time. It was the name of a set of scheduled work, and of what that work produced, and of the whole idea behind it, depending on who was talking. When something went wrong, people said that word was broken. Which part? Nobody could say. And because nobody could say, nobody could own it.

That's when I started treating naming as part of the build, and an early part. Before I write much code for something new, I want to know what it's called, what it's for, and where its edges are. A name forces those questions. A vague name lets you skip them until it's expensive.

Split the estate into systems

Most businesses that have been running software for a while have an estate, a sprawl of scripts, jobs, databases, forms and dashboards that grew one need at a time. You can't reason about it as one thing. You have to break it into systems you can point at.

I do this on paper first. I list everything I can find, then group it by what it's actually for. A group that exists to take in requests is one system. A group that exists to publish content is another. Some pieces will obviously belong somewhere. Others won't fit anywhere, and those are the interesting ones.

The test for a real subsystem

A group of things isn't a subsystem just because it sits in the same folder. I use a test. To count as a subsystem, it needs all of these:

  • A job you can say in one sentence.
  • A record it owns. Some data, file or state that is its responsibility and nobody else's.
  • A failure mode of its own. A way it breaks that you could recognize and name.
  • A named owner. A person, not a team, and definitely not "everyone."
  • The ability to be held or rolled back without stopping the others.

The last one is the one that catches people out. If you can't pause a piece without taking three other things down with it, it isn't separate yet. It's tangled, and the name is hiding the tangle.

When something fails the test, I don't force it through. If it has no owner, no record, or nothing watching it, it isn't a subsystem yet. It's a gap. I write it down as a gap, on purpose, with that word. Gaps are fine to have. Gaps you've mistaken for systems are how things go quietly wrong, because everyone assumes someone else is watching.

One thing, one name

Once the systems are clear, each gets exactly one name. People will still use other words for it, and that's human. So I list the aliases once, in one place, next to the real name. Anyone reading a chat message or an old document can look up what a word meant. What I don't allow is a second official name drifting into code, folders or reports.

The reverse matters just as much. One name should never point at two things. If a word already means something in your business, don't reuse it for a new component, even if it sounds right. Ambiguity costs nothing on the day you create it and a lot on the day something breaks.

Don't name it after the first project that needed it

This is the mistake I see most often, and I've made it myself. A component gets built for a specific project, so it gets that project's name. Then a second project needs it. Then a third. Now you have a shared piece of infrastructure named after one customer or campaign, and every new person has to learn that the name means something different from what it says.

Name components for what they do. If you build something that sends reminders, call it after reminders, not after the launch it was built for. It feels less exciting. It ages much better.

A naming rule only works if something enforces it

Here's the lesson that took me longest. A naming rule that lives only in a document can't be enforced. People are busy. They'll create a folder with the old name, or a job with a new abbreviation, and nobody will catch it for months.

So a daily check enforces the names. It reads what actually exists, the folders, scheduled jobs and database tables, and compares their names against the approved list and the aliases. Anything that doesn't match gets flagged. Anything new that no system claims gets flagged too, because an unclaimed thing is exactly the kind of gap I described above.

It doesn't need to be clever. Mine is mostly string matching against a list. The value comes from it running every day without anyone remembering to run it.

Steps you can take this week

If your own setup has names that mean too many things, here's how I'd start.

  1. List every script, job, database, form and dashboard you can find. Don't organize yet.
  2. Group them by purpose. Write a one-sentence job for each group.
  3. Run each group through the test. Record, failure mode, owner, and whether it can be paused alone.
  4. Anything that fails, mark as a gap. Write down what's missing for it to become a real system.
  5. Give each real system one name. Write its aliases next to it in a single shared list.
  6. Rename anything that's called after the first project that used it.
  7. Write a small daily check that compares what exists against your list and flags mismatches and unclaimed pieces.
  8. When you build something new, name it and run it through the test before you start.

This work pairs well with keeping an accurate record of what you've got. I wrote about that in writing the owner's manual from the running system. The names are what make the manual readable, and the manual is what keeps the names honest.

It's tempting to think naming is cosmetic, something to tidy up after the real work. In my experience it's the first real decision. When everything has one name, one owner and one job, a failure has an address. You know who to call and what to roll back. When it doesn't, every problem starts with an argument about what the problem even is.