The 200 Small Decisions That Make Software Feel Good
Great software isn't made by one big idea. It's made by a few hundred tiny decisions nobody mentions in case studies — and each of them is individually unglamorous.
There are essays about design philosophy, essays about color theory, essays about typographic systems. This isn't one of them. This is an essay about the unglamorous work that sits between theory and shipped product — the dozens of micro-decisions you have to get right for an interface to feel considered, and the reason nobody talks about them is that each one is so individually minor it sounds silly to mention.
The difference between a screen that feels cheap and a screen that feels premium is almost never a single design choice. It is the cumulative result of getting roughly two hundred small things right in a row.
Here are some of them.
Spacing rhythm
The gaps between elements tell the reader how to parse the page. Inconsistent gaps read as chaos even if every individual gap is "technically fine." Strong interfaces have a small number of spacing values (often four to six), chosen to relate to each other proportionally, and every gap on the page is drawn from that set.
Related: the gap between sections should be meaningfully larger than the gap between items within a section. If a section break and a line break look the same, the reader has to work to understand the structure. Their brain does that work, they just resent it.
Optical vs. geometric centering
Centering a shape is not the same as centering what the eye sees as the shape. A play icon is geometrically a triangle, but its visual center is offset left of its bounding box. Center it geometrically and it looks off. Center it optically — nudge it a few pixels to the right — and it looks right without anyone noticing.
This applies everywhere. Circles inside squares. Asymmetric icons. Text inside buttons with non-uniform padding. Lean on your eye, not the math.
Text weight hierarchy
A page with three text weights — regular, medium, bold — usually reads well. A page with five or six weights reads like a ransom note. Hierarchies of weight need to be compressed, not expanded. The difference between medium and semibold is often enough; you rarely need both.
Also: bold does not mean "important." It means "different from the thing next to it." A whole page of bold is no longer bold. A single bold phrase on a page of regular has the weight the designer intended.
Line height
Most default line heights are too tight. A line-height of 1.5 or 1.6 is usually better than 1.3. Read any body of text at both, on a real device, in a real context. The looser one is almost always more comfortable. Designers who come from print occasionally over-tighten because print typography runs tighter, but screens are not print.
Heading line heights go the opposite direction. Large type with 1.5 line height feels loose and unanchored. Headings want closer to 1.1 or 1.2.
Border radius
Consistency matters more than magnitude. A card with rounded-lg next to a button with rounded-md next to an input with rounded-sm looks mismatched even when no individual radius is wrong. Pick a radius system. Stick to it. Two values for most systems is enough: one for primary surfaces (cards, panels) and one for interactive elements (buttons, inputs). Three at most.
Border radii also interact with padding. A rounded corner on an element with too little internal padding looks cramped. The rounder the corner, the more breathing room the content needs inside it.
Focus states
Focus states are the difference between an interface a keyboard user can navigate and one they cannot. They are also, far too often, the first thing a developer strips because the default looks ugly.
The answer is not to strip focus states. The answer is to design better ones. A custom ring with a color from your palette, with an offset, with enough contrast — that's a focus state you'll actually leave in.
Loading states that don't shift
When content arrives from a network request, the page should not reflow. Skeletons should occupy the real dimensions of the thing they're standing in for. Images should have intrinsic dimensions. Fonts should not cause layout shift when they finally load. None of this is glamorous; all of it is the difference between an app that feels stable and one that feels jittery.
Error states with actual copy
"An error occurred" is not an error state. It is an admission of defeat. A good error state tells the user what happened, in specific terms, and what they can do next. Usually one sentence is enough. Usually the sentence has been hiding in a pattern somewhere.
"We couldn't load your list. Try refreshing in a moment." That is six seconds of copywriting and a measurable increase in perceived product quality.
Input affordances
Inputs need to look clickable without looking loud. A subtle border, a tiny shadow, an interior padding that matches the body text line height — and you get an input that reads as interactive at a glance. Inputs that try too hard (heavy borders, gradient fills, animation on focus) read as decorative rather than functional.
Disabled inputs need to look disabled in a specific way: dimmer, lower-contrast, but not so washed out that the user can't read what's in them. Disabling is a communication, not a punishment.
Icon weight matched to text weight
An icon next to a line of text should visually weigh the same as the text. A thick icon next to light text reads as shouty. A hairline icon next to bold text reads as timid. Match the weights and the combined element feels unified.
Button label verbosity
"OK" is a bad button label. "Save changes" is a good button label. The user is not reading the dialog carefully; they are scanning the buttons. The buttons should be self-explanatory out of context. This principle sounds fussy and pays off constantly.
The list continues
These eleven are representative. The actual list is longer. A partial inventory, without commentary:
- Modal overlays tinted with a subtle color rather than plain black.
- Scroll shadows at the top and bottom of scrollable containers.
- Hover states that change something, never nothing.
- Transitions that are fast enough to feel responsive (150–200ms) but not so fast they feel mechanical.
- Empty states with an illustration or a concrete suggestion, not just "No results."
- Date formats that match the user's locale.
- Tables that right-align numbers and left-align text.
- Icons used consistently to mean the same thing across a product.
- Link underlines that appear on hover if they aren't permanent.
- Dividers that are subtle enough to separate without dominating.
- Truncation that happens with tooltips, so users can still see the full value.
- Keyboard shortcuts for the power actions.
- Default input focus on the first meaningful field when a form loads.
- Touch targets that are at least 44 pixels even when the visual element is smaller.
And on.
Why this matters
The reason none of these decisions is glamorous is that none of them is individually difficult. Each is either a known principle or a matter of taste. The difficulty is getting all of them right, in the same product, at the same time. That is craft. That is what separates an AI-generated first draft from shipped software that someone cared about.
The good news is that these decisions are not proprietary and not mystical. They can be learned, they can be checked for, they can be fixed. The bad news is that doing the fixing takes time, and the time has to be spent on what feels like trivial adjustments, none of which is individually impressive.
Most of the work of making software feel good is this work. If you are building a product right now and something about the output feels not quite right, don't look for one big idea. Look for twenty small ones. The difference is cumulative, not singular.