The key idea
For each decision, name the user need, the owner, the failure behavior, and the cost of your choice.
Building before agreeing on the problem
A news feed might mean reading posts, publishing them, or moderating them. These require different permissions, data flows, and failure handling. Confirm the main user journey and two or three constraints before drawing components. Explicitly exclude features you will not cover, such as recommendation algorithms or video uploads.
Recover with a concrete question
“I assumed a signed-in user reading a personalized feed on mobile. Should we also cover publishing, or concentrate on loading and interacting with posts?” Write down the answer and revise the design.
Drawing boxes without responsibilities
A diagram containing React, a database, and a CDN says little about how the application works. Give each box a responsibility. The server decides visibility and ranking; the data layer fetches and caches records; the feed controls ordering and pagination; individual cards render posts. Trace one action through these boundaries.
- Identify who owns each fact: a draft belongs to the composer; a published post belongs to the server.
- Keep ordered post IDs separate from reusable records when the same post appears in several views.
- Choose technologies after these responsibilities are clear. A library name does not explain a consistency policy.
Defining an API that only works once
“Fetch the posts” omits the decisions that shape the UI: page size, ordering, a continuation cursor, permissions, and errors. Define a sample request and response. Explain whether newly inserted posts can cause duplicate or skipped results, and how the client deduplicates records by stable ID.
For writes, describe validation errors and conflicts separately from outages. A timed-out submission may already have succeeded. Agree on an idempotency contract before automatically replaying it; optimistic UI also needs reconciliation or rollback.
Treating every response as current
In autocomplete, the response for “ca” may arrive after the response for “cat”. Debouncing requests does not solve this race. Cancel superseded work with an AbortController where possible, and check request identity before accepting a result. Include filters, locale, and account scope in the cache identity.
Make state visible
Distinguish initial loading, refreshing existing results, a genuine empty result, and an error. Retaining older results can help, but label them as stale and avoid presenting them as matches for a different query.
Promising speed without a bottleneck
“Use memoization everywhere” is not a performance strategy. Describe the slow path, how to measure it, and the smallest useful intervention. A large hero image, repeated network requests, and expensive list rendering need different fixes. Server rendering can help discoverable content, but it does not remove the cost of client-side interaction.
- Reserve image dimensions to prevent layout movement; serve appropriately sized assets.
- Split optional features from the initial route instead of loading every editor or chart immediately.
- Virtualize a large list only when its rendering cost justifies the complexity; preserve focus, scroll restoration, and access to off-screen items.
Adding accessibility after the design
A clickable suggestion list is incomplete if keyboard users cannot select a result or assistive technology cannot identify the selected option. Start with native controls, then specify roles and keyboard behavior for custom widgets. Plan where focus goes when a panel opens, closes, or disappears.
Also test narrow screens, zoom, long translated labels, and right-to-left layouts. Format dates and currencies for the user's locale. A polished desktop screenshot is only one state of the product.
Confusing UI restrictions with security
Hiding an Edit button does not prevent an unauthorized request. The server must check access to the specific resource on every operation. Keep private service keys on the server. Render user text safely; if rich HTML is required, sanitize it with a maintained sanitizer rather than bypassing framework protections.
Treat cache and telemetry as part of the privacy design. Do not put account-specific responses in shared caches. Clear account-scoped client data on logout, and avoid collecting message bodies, tokens, or private search terms in diagnostics.
Designing only the successful request
A user can lose connectivity halfway through an action. Preserve their draft, show what is pending, and offer a safe retry. Offline writes need an explicit conflict and replay policy; a background queue is not proof of delivery. For real-time updates, discuss disconnects, duplicate events, missed events, and reconnect recovery.
- Test slow and out-of-order responses, expired sessions, duplicate submissions, and authorization failures.
- Measure API failures and action completion by route and release; attach a correlation ID without exposing private content.
- Keep a usable fallback when an optional live connection or third-party service fails.
Losing the thread of the discussion
Explain the main design before spending ten minutes on one widget. When proposing polling, server-sent events, or WebSockets, compare them against the required freshness and interaction direction. Name the extra connection management your choice introduces. Use an unfamiliar term only if you can explain its mechanism and relevance.
A useful closing check
“We covered the primary flow, state ownership, API contracts, and failure recovery. The biggest remaining risk is long-feed performance; I would validate it on a low-end phone with realistic content.” This makes the unfinished work concrete.
Sources & further reading
Original explanations and examples by FineFrontend, informed by the guide and primary references below.
- GreatFrontEnd: Common mistakes (opens in a new tab)
Reference for interview scoping, structure, communication, and explaining tradeoffs. Examples and technical guidance here are original.
- MDN: AbortController (opens in a new tab)
Cancellation of fetch requests and response processing.
- WAI: Combobox pattern (opens in a new tab)
Keyboard interaction, focus, and accessible state for autocomplete interfaces.
- web.dev: Web Vitals (opens in a new tab)
Current Core Web Vitals thresholds, field percentiles, and the limits of laboratory measurements.
- MDN: Cache-Control (opens in a new tab)
The distinction between private caches, revalidation, and no-store.
- OWASP: Authorization (opens in a new tab)
Server-side permission checks and authorization tests.
- OWASP: Cross-site scripting prevention (opens in a new tab)
Safe text rendering, HTML sanitization, and security boundaries in frameworks.
- Chrome for Developers: Retrying offline requests (opens in a new tab)
Background retry mechanisms and browser support constraints; application conflict and delivery policies still need design.