CodeveilStudio

Engineering digital products with design precision.

Back to Insights

Design

Design Debt: Why Your Product Gets Harder to Use Every Time You Ship

By Muhammad Farhan15 Sept 20266 min read
{ }CODEVEIL STUDIODESIGN

Eight months after launch, a founder shares their screen and walks me through their product. It does more than it did at launch. It is also, unmistakably, harder to use.

Nobody made it worse on purpose. Every individual decision was reasonable at the time. But there are four button styles now. Three different modals, each behaving slightly differently. Six greys where there should be two. The settings page has become the place features go when nobody could decide where else to put them. New users take longer to do the thing the product exists to do, and support answers the same three questions every week.

This is design debt, and it behaves exactly like the technical kind. You borrow against the future to ship faster today, and the interest compounds quietly until one day the interest payment is the entire sprint.

Technical debt slows down the people building the product. Design debt slows down the people using it — which is why it costs more and gets noticed later.

Where it actually comes from

In my experience it almost never comes from bad designers. It comes from four fairly ordinary situations.

  • Designing screens instead of systems. A screen solves today’s problem. A system answers "what does a destructive action look like here?" once, so the next twelve screens do not each answer it differently.
  • Features added by whoever was free. A developer needs a dropdown on a Friday, nothing in the codebase quite fits, so they build one. It is a good dropdown. It is now the fifth good dropdown.
  • Decisions made in the ticket, not in the system. Someone decides this particular warning should be orange. Nobody writes down why, or what orange means. Six months on, orange means four things.
  • Growth with no home for it. The product outgrows its original navigation, and instead of revisiting the structure, new things get appended to whatever menu had room.

Every one of those is a rational local decision. Design debt is what you get when you make forty of them without anyone holding the global view.

How to tell you have it

Design debt is easier to feel than to measure, but it leaves fingerprints. Any of these is worth taking seriously.

  • You cannot answer "what colour is a primary button?" without opening the app to check.
  • Shipping a new screen means copying an old one and editing it, rather than assembling it from pieces.
  • The same action lives in different places depending on which screen you are on.
  • Support keeps answering questions that are really interface problems in disguise.
  • A small visual change touches a surprising number of files, and the review takes longer than the change.
  • New team members ask which of two similar components they should use, and nobody has a confident answer.

That last one is the clearest signal. When the team cannot tell which pattern is correct, users certainly cannot.

Five inconsistent save buttons next to one button with primary, secondary and destructive variants, above a chart showing the cost of rationalising rising with screen count.
The same interface, built two ways — and what it costs to get from the first to the second once you have shipped a hundred screens.

A design system is not a style guide

This is where a lot of teams spend money and get very little back. They commission a beautiful PDF of colours and typefaces, everyone admires it, and the product carries on exactly as before — because a document has no way to enforce anything.

A design system is not the document. It is the set of decisions, made once and made real in code, that the product is assembled from. The useful test is simple: if a developer can ship a screen that violates the system without noticing, you do not have a system yet. You have a suggestion.

In practice that means a small number of things that genuinely exist in the codebase.

  • Tokens, not values. Spacing, colour and type sizes come from a named scale. Nobody types a hex code into a component.
  • One component per job. One button with variants, not five buttons. One modal. One empty state, one error state, one loading state.
  • Decisions recorded where the work happens. Why this colour means danger, when to use a modal versus a drawer — written next to the component, not in a deck.
  • Accessibility built into the component. Focus states, contrast and keyboard behaviour handled once, correctly, so every later use inherits it instead of re-litigating it.

The payoff is not really aesthetic consistency, although you get that. It is speed. Once the primitives exist, new screens stop being design problems and start being assembly, and the team can spend its judgement on the parts that are genuinely new.

Brand and interface are the same problem

There is a version of this that costs even more, and it happens when brand and product are treated as separate projects. An agency delivers an identity — logo, palette, a typeface with real personality. Then the product gets built somewhere else, in a component library that knows nothing about any of it. The marketing site and the app end up looking like two companies with a similar name.

For most software businesses the product is the brand. It is where people spend their time and form their opinion. A brand that only exists on the website is decoration; a brand that reaches into the empty states, the error messages and the onboarding is an actual asset.

That is the main reason we keep identity and interface on one team at Codeveil Studio. Not because it is tidier, but because the handoff between them is exactly where the inconsistency gets in.

What it costs to fix, and when

Design debt is cheapest to pay down before you scale the surface area, and the cost curve is steep. Rationalising four button styles into one at twenty screens is an afternoon. At a hundred and twenty screens it is a project with a name, a budget and a risk register.

If you already have it, you do not need to stop and rebuild everything. What has worked for the teams I have watched do this well is narrower.

  • Inventory first. Screenshot every button, input, modal and empty state in the product. The duplication is usually worse than anyone expects, and seeing it laid out ends the debate about whether this is a real problem.
  • Fix the primitives, not the screens. Colour, type scale, spacing, buttons, form fields. Most of the visible inconsistency disappears once those are settled.
  • Pay it down on the way past. Each time a screen is touched for another reason, move it onto the system. Consistency arrives incrementally instead of needing a freeze.
  • Put a gate on new debt. One person or one review step that answers "does this already exist?" before a new component enters the codebase.

The practical version

If you are early, spend a few days on the primitives before you have twenty screens. It is the cheapest this will ever be, and it is the difference between a product that gets easier to extend and one that gets heavier every release.

If you are further along, do the inventory this week. You do not need a budget or a decision to start — you need to see it. Almost everyone who does that finds the argument makes itself.

And if the product is starting to feel heavier every time you ship, that feeling is data. It is usually the first thing to show up, and it is worth acting on long before it reaches your users.

Muhammad Farhan is co-founder of Codeveil Studio, where he leads design across brand and product. He works mostly on design systems, interface architecture and accessibility — the parts of design that decide how a product ages.