Common Mistakes, Anti-Patterns & Pitfalls
Most bad software is not the result of one giant blunder. It is the slow build-up of small, well-known traps that every builder falls into. This chapter is a catalogue of those traps. For each one you get the problem, why it hurts, and the fix. Read it as a checklist you can run your own work against.
One question ties the whole chapter together. It comes straight from this project's own rulebook: "Would a shopkeeper understand this, or is it for a developer?" Your real users are non-technical print-shop owners. They do not read manuals. They navigate by intuition. Almost every trap below is a way of secretly serving the developer instead of the shopkeeper.
Trap 1 — Designing for yourself (the curse of knowledge)
The deepest trap is invisible: you build for the only user you fully understand, which is you. This is the curse of knowledge — a thinking bias where, once you know how something works, you can no longer imagine not knowing it. So you assume everyone shares your mental model. (A mental model is the picture in someone's head of how a thing works.)
Don Norman, the cognitive scientist who wrote The Design of Everyday Things (1988; revised 2013), gave us the perfect symbol: the Norman door. That is a door where you cannot tell whether to push or pull, because its looks won the fight against its usability. Norman said the design should show you how to use it "without any need for signs."
Two precise Norman terms matter here. An affordance is what an object lets you do (a button affords pushing). A signifier is the visible cue that tells you where and how to act (the word "Push," an underline on a link). Most everyday UX failures are missing or wrong signifiers, not missing affordances. The thing was clickable; nothing told the user so.
Trap 2 — Adding features instead of removing friction
The second trap feels like progress, which is why it is so dangerous. Teams measure themselves by features shipped rather than problems solved. Marty Cagan calls this the feature factory or the build trap: the roadmap is a list of features, and "busy" gets mistaken for "valuable."
The evidence that this wastes work is brutal. Pendo's 2019 Feature Adoption Report — built from real usage across 615 software subscriptions — found that 80% of features in the average product are rarely or never used, while about 12% of features drive 80% of daily usage. The older Standish Group CHAOS data tells the same story: 45% of features are never used and another 19% rarely. So this is not new — it is the norm.
Fix: set goals as outcomes (did the shop owner get their first order out faster?), not as a count of shipped buttons. Discover the real problem before designing a solution. And treat removal as a feature — ask your team, "When did we last delete something?" For a print SaaS, the win is usually fewer steps to publish a product, not one more checkbox in settings.
Trap 3 — Dark patterns (deceiving the user)
Dark patterns — a term coined by UX researcher Harry Brignull in 2010, now often called deceptive design — are interface tricks that push users into things they did not mean to do. Two classic ones:
- Confirmshaming
- Guilt-tripping the user through the "decline" wording, e.g. a decline button that reads "No thanks, I don't want to save money."
- Roach motel
- Easy to get in (one-click signup), deliberately hard to get out (a buried, multi-step cancel flow).
These work in the short term and rot you in the long term. They "create ill will and destroy customer loyalty." They are also now legal risk: the EU's Digital Services Act, US FTC guidance, and California's CPRA all restrict them. The FTC's 2023 action against Amazon over Prime cancellation is a real-world "roach motel" enforcement case.
Trap 4 — Leaking the machine's internals
This is where the shopkeeper test bites hardest. Nielsen Norman Group's usability heuristic #2, Match between system and the real world, says: speak the user's language, not internal jargon. Heuristic #9 says errors must be in plain language with a way to recover.
| The machine says (bad) | The human reads (good) |
|---|---|
200 OK / "System error" | "Saved successfully" / "We couldn't save — check your connection and try again" |
message.exportError (a raw translation key) | "We couldn't create your export. Try again in a moment." |
A row labelled Path bTSxCeDjco or a bare UUID | "Headline text" or "Logo.png" |
message.exportError and "System error," design layers were named Path bTSxCeDjco, and a loading skeleton spun forever. Every one of those is an internal value that escaped onto the shopkeeper's screen. The fix is to finish the "last mile": turn each machine value into finished, human UI — derive a name from the content (a text layer shows its text; an image shows its filename).Trap 5 — No loading, empty, or error states (the blank screen)
NN/g heuristic #1, Visibility of system status, says the system must always tell the user what is happening. A blank or frozen screen breaks this rule — a human reads "blank" as "broken." (Rough timing rules from Nielsen: under 0.1s feels instant; show a spinner past ~1s; show a real progress bar past ~10s.)
Every data-driven view needs all three states, or it is not shippable:
FETCH DATA
|
+---+----+----------+
| | |
LOADING EMPTY ERROR
skeleton "No plain message
(not a products + "Try again"
blank yet — add (never a
page) one →" silent fail)
/login, the reCAPTCHA loaded after the form, leaving "Log In" greyed out with no reason given. Reserve the space, show a "Loading verification…" state in its slot, explain any disabled button, and handle timeouts with a retry.Trap 6 — Inconsistent labels and patterns
Heuristic #4, Consistency and standards, says users should never wonder whether two different words mean the same thing. There are two kinds: internal consistency (within your app) and external consistency — Jakob's Law: users spend most of their time on other apps, so they expect yours to behave like those. Every inconsistency forces re-learning and chips at the user's confidence.
LH, W/H) or give them a tooltip. Before inventing a new list, form, or modal, copy how your existing ones already work.Trap 7 — Destructive actions with no confirmation
Heuristic #5, Error prevention, says the best error message is the error that never happens. Delete, archive, deactivate, and cancel should confirm exactly what is lost, in plain words, and the confirm button should restate the action.
- Bad: "Are you sure?" with a "Yes" button.
- Good: "This will permanently delete 'Premium Business Cards' and remove it from all active orders. This cannot be undone." → button labelled Delete Product.
One nuance: do not over-confirm. For frequent, reversible actions, the gold standard is Undo (heuristic #3, user control and freedom), not a popup on every click. Reserve hard confirmations for the irreversible, high-consequence ones.
Trap 8 — Fake "Saved!" that silently drops data
This is the chapter's signature trap and the most damaging. The form sends a field, the UI cheerfully says "Saved," but that field was never validated or stored — so it vanishes. The user trusts a lie, which is worse than a visible error.
The technical roots are mundane: a field collected in the UI but missing from the server's validation rules; a database column missing from the model's writable list; a snapshot record (an order or quote that freezes data at purchase time) that forgets to copy the new field. Any one of these silently discards real customer data on checkout, sign-up, or address forms.
Trap 9 — Trusting opinions over behaviour
Rob Fitzpatrick's The Mom Test (2013) is named for a simple truth: even your mom will lie to be nice if you ask whether your idea is good. The goal of customer talks is to learn, not to be validated. Its three rules: talk about their life, not your idea; ask about specifics in the past, not hopes about the future; talk less, listen more. "Compliments are the fool's gold of customer learning."
Fix: separate the problem (real and durable) from the solution (a guess), and watch what users do, not only what they say.
Trap 10 — Analysis paralysis vs shipping to learn
The opposite failure is endless research and polishing so you never have to be wrong in front of a real user — so you never learn anything. Eric Ries' Lean Startup (2011) offers the cure: the Build–Measure–Learn loop and the MVP (minimum viable product — the smallest thing that produces real learning). Reid Hoffman put it bluntly: "If you're not embarrassed by the first version of your product, you've launched too late."
Trap 11 — Mistaking pretty for usable
The aesthetic-usability effect (shown by Kurosu & Kashimura's 1995 ATM study, and Tractinsky in 1997) is that people perceive attractive things as more usable — sometimes more strongly than they actually are. The danger: a pretty UI masks real problems, so defects hide during testing and never get fixed. Beauty only buys forgiveness for minor issues; for severe ones, users lose patience anyway.
Key takeaways
- Run every screen through one test: "Would a shopkeeper understand this?" If it shows a code, key, UUID, or jargon label, it fails.
- The curse of knowledge makes you build for yourself — the only cure is watching real, non-team users.
- Roughly 80% of features go unused; default to removing friction, not adding capability.
- Every data view needs loading, empty, and error states; a blank screen reads as broken.
- "Saved!" must be true — validate, save, read back, render, and test it; a silent data drop is worse than a visible error.
- Dark patterns and prettiness both buy short-term wins and cost long-term trust; listen to problems, watch behaviour, and ship small to learn.