Craft · May 22, 2026
Design is the specification
Most teams apply design to software. We treat it as the thing the software is built to obey.
There are two ways to build an app, and the difference shows up in the parts nobody is supposed to notice.
The common way is code-first. You build the screens, wire up the data, get it working, and then — late, under time pressure — you make it look nice. Design arrives as a skin stretched over a structure that was decided without it. It mostly fits. But the empty states feel forgotten, the error messages sound like a different person wrote them, the spacing is almost-but-not-quite consistent, and the whole thing has a faint air of having been assembled rather than made. Nobody can point to what's wrong. It just doesn't feel considered, because it wasn't.
We build the other way. The design is not applied to the software. The design is the specification, and the code's only job is to keep the promise it makes.
What "on paper" actually means
Before a line of code gets written, the whole app exists as a document. Not a mood board and not a Figma file full of happy-path screens — a specification precise enough that the build has nothing left to invent. For us that means writing down, and arguing about:
- The data model — every entity, every field, what's required, what's nullable, what's derived. The shape of the truth the app is built around.
- Every screen, in every state. Not just the screen full of perfect data — the empty state, the loading state, the error, the success, the offline case, the first-run version and the thousandth-run version. A screen isn't designed until all of its states are.
- The motion. What animates, how far, how long, on what curve, and — more importantly — what doesn't. Timing is a design decision, not a default.
- The exact words. Every label, every button, every error, written out. Copy is interface. "We couldn't save that" and "Error 500" are the same event and a completely different product.
- The failure cases. What happens when the network drops mid-action, when the input is garbage, when the subscription lapses, when the thing the user wanted simply isn't possible. The unhappy paths are where care is visible.
By the time code starts, the interesting decisions are already made. The build is execution, not discovery.
Why it's faster, not slower
This sounds slower. It feels slower — you spend the first stretch of a project arguing about things that don't exist yet, with nothing running to show for it. But it is the faster way to finish, for a reason that has nothing to do with discipline and everything to do with where decisions are cheap.
A decision made in a specification costs a sentence. The same decision made in code costs a branch, a refactor, a round of review, and a regression somewhere you didn't expect. When you design as you build, you make every decision in the most expensive medium available, and you make a lot of them twice. When the design is settled first, each decision is made once, in words, and the code just carries it out.
The build is just keeping a promise you already made.
The drift that makes code-first apps feel assembled comes from a thousand tiny decisions made at build time by whoever happened to be writing that file that day. A real spec removes those decisions from the build. Consistency stops being something you police in review and becomes something that was never in question.
The handoff test
Here's how you know whether you actually have a specification or just a nice-looking sketch: hand it to two people and have them build the same screen separately. If they produce the same thing, you have a spec. If they produce two different things, the document left the real decisions to "judgment at build time" — which is a polite way of saying the design wasn't finished, and the gaps got filled by whoever got there first.
Most "design handoffs" fail this test badly, and everyone has quietly agreed not to mention it. The spec covers the three screens in the deck and goes silent on the forty states that make up the actual app. The silence is where slop comes from.
What it costs
We won't pretend this is free. Specifying an app before you build it is slow to start and genuinely uncomfortable. You have to make decisions while they still feel abstract, defend them before anything is real enough to feel, and resist the pull to "just start coding and figure it out as we go." That pull is strong, and it is almost always wrong. Figuring it out as you go is how you end up with software that feels like it was figured out as it went.
The payoff is coherence, and coherence is the one quality you cannot bolt on at the end. When you use an app that was specified before it was built, the details hold together because they were decided together — by the same people, at the same time, against the same idea of what the thing was for. That agreement is not something a final design pass can manufacture. It is the difference between software that works and software you'd actually keep.
It's also, not coincidentally, how Subside was built — every screen state, every line of copy, the timing of the one animation that matters, all settled before the first commit. And it's the same reason this website behaves the way it does, which is a story for another post.
Written by BD Media — a small iOS app studio. We make a few things, exceptionally well. Say hello: hello@bdmedia.app.
← All writing