Skip to content

    Frontend System Design

    Frontend Requirements: Users, Devices and Networks

    Turn wishes like 'make it fast' into testable front-end requirements: budgets, browser support, accessibility and states, and see how each shapes the design.

    By Published 25 min read

    • frontend-system-design
    • requirements
    • accessibility
    • performance-budget
    • browser-support
    Share

    This lesson is part of Frontend System Design Foundations: How the Web Runs. Enroll for free, then sign in, to read it in full.

    What you'll learn: By the end of this lesson you will be able to explain how front-end requirements differ from back-end ones, write the states of a user interface as requirements, and turn vague wishes into measurable, testable sentences. You will also be able to write a browser-support policy, treat accessibility as a requirement with a named target, choose between progressive enhancement and graceful degradation, and map each requirement to a design consequence you can defend to product and design.

    A restaurant kitchen is a controlled place. You choose the stove, the staff and the hours. A shopfront is not. You do not choose whether a customer arrives by car, by bus, in a wheelchair, in the rain, or while carrying three bags and a crying child. If the door is heavy, some customers leave, and none of them tell you why.

    A front-end system is the shopfront. The back end is the kitchen. This lesson is about writing down what the shopfront must handle before anyone draws a component.

    The running example is an online store with three journeys: a product page, search, and checkout. Every number in the examples is an illustrative assumption, not data from a real store.

    The core idea

    A front-end requirement describes what a person experiences in a browser, on a device and network you do not own. The back-end requirements lesson covers latency percentiles, availability nines, durability and SLOs for servers you run. Read it for those ideas. Here we use them, but four things change.

    1. The code runs on someone else's machine. The same page may run on a recent laptop, an older phone with little memory, or a browser with extensions that block scripts. You must measure it from the user's browser: field data (data collected from real visits), as opposed to lab data (data from a test you run yourself).
    2. "Fast" is perceived, not computed. A server response of 50 ms means little if the page then spends seconds downloading and running JavaScript. The requirement must describe what the user sees and can do.
    3. The design space is a matrix. Device power, screen size, input method (touch, keyboard, mouse, screen reader), browser, network quality and user preferences all combine.
    4. More people own the result. Designers, product managers, legal, marketing (who add tags and scripts) and several engineering teams all change the page. Requirements also say who may change what.

    A useful rule: a front-end requirement is complete when it names a journey, a condition (device, network, browser, user need), a measurable outcome and a way to check it.

    Functional requirements of a UI: journeys and states

    A user journey is a path through the product that a person takes to reach a goal: find a product, compare two, pay. List the journeys first, in order of business importance. For the store:

    • Product page: see the product, choose a size, add it to the basket.
    • Search: type a query, filter results, open a product.
    • Checkout: confirm the basket, enter an address, pay, see a confirmation.

    A back-end feature list usually stops there. A front-end specification must go further, because the screen is never in just one condition. Each piece of data on screen has several states, and each one is a requirement.

    State What the user sees Requirement question
    Loading Something is on the way What appears first? Is there a placeholder that holds the layout still?
    Empty A valid request with no results What does search say when nothing matches? What can the user do next?
    Error The request failed What is said, in plain words? Can the user retry without losing input?
    Partial Some data arrived, some did not If reviews fail, does the product page still let me buy?
    Offline or slow The network is gone or poor What still works? Is the data shown possibly stale, and does it say so?
    Success The normal case What exact content and actions appear?

    The "partial" row is the one teams skip, and it drives real architecture: a page built from five independent data sources can show four of them. A page that treats the five as all-or-nothing turns a failed reviews service into a blank product page.

    Figure 1. The states of the search results area

    stateDiagram-v2 accTitle: States of the search results area accDescr: The results area moves from idle to loading, then to results, empty, partial or error, and can show stale results when offline. [*] --> Idle Idle --> Loading: user submits query Loading --> Results: all data arrives Loading --> Empty: valid query, zero matches Loading --> Partial: some data fails Loading --> Error: request fails Error --> Loading: user retries Partial --> Loading: user retries Results --> Stale: network lost Stale --> Loading: network returns

    How to read this: every arrow out of Loading is an outcome the design must handle. "Stale" means showing results already on screen while saying they may be out of date. If a state has no design, it will still happen, and the user will see whatever the code does by accident.

    Non-functional requirements, written as testable sentences

    A non-functional requirement (NFR) says how well the product must work. The weak form is an adjective ("accessible", "fast", "secure"). The strong form is a sentence a person or a tool can check. A good template:

    For [journey], on [condition], [measurable outcome], checked by [method].

    The table gives one illustrative sentence per quality. The numbers are assumptions you would replace after measuring.

    Quality Weak wording Testable sentence (illustrative) Checked by
    Performance "The product page is fast" On the product page, the largest content element appears within 2.5 s for 75% of real visits on each of mobile and desktop Field data, per device class
    Responsiveness "Search feels snappy" Typing in the search box, filtering and adding to the basket respond visibly within 200 ms for 75% of real visits Field data
    Accessibility "It is accessible" Product page, search and checkout conform to WCAG 2.2 Level AA, and a keyboard-only user can complete checkout Automated checks plus manual review
    Browser support "Works everywhere" The browsers in the support policy get full function; others get the basic purchase path Test matrix, browserslist
    Network "Works on bad Wi-Fi" On a throttled slow connection, the product page shows a price and an add-to-basket button before images load Lab test with throttling
    SEO and previews "Good for search" Product pages return their title, price and description in the first HTML response and carry preview metadata HTML check of the raw response
    Internationalisation "Supports other languages" The store shows prices, dates and text in the shopper's chosen language and currency, and layouts survive text 40% longer (illustrative) Pseudo-localisation test
    Privacy "We respect privacy" No analytics or advertising script runs before the shopper's consent choice Automated network check
    Security "It is secure" A Content Security Policy blocks inline and unknown scripts on checkout Header check in CI
    Reliability "Never fails" If the reviews service fails, the product page still sells; if payment is slow, an order is never placed twice Fault-injection test
    Maintainability "Clean code" A team can change checkout without a release of the product page Repository and deploy boundaries

    Two terms from the table need a definition. Pseudo-localisation replaces text with accented and lengthened fake text to expose layouts that break when translations are longer. A Content Security Policy (CSP) is a rule set, sent as the Content-Security-Policy HTTP response header, that tells the browser which sources of scripts and other resources are allowed. MDN describes it mainly as a defence against cross-site scripting. See security for the server side.

    Device and network diversity

    You do not need statistics to design for diversity. You need to name the dimensions and decide which ones your product will promise to support. This lesson deliberately does not quote any figure for how many people use which device. Your own field data, from real visits, is the only number that matters for your product.

    Figure 2. What a front-end design does and does not control

    What a front-end design does and does not controlShopper device to Browser; Browser to Network; Network to CDN edge (HTML, JS, CSS); Network to Product and search APIs (data)NOT UNDER OUR CONTROLUNDER OUR CONTROLShopper device: CPU, memory, screenShopper deviceCPU, memory,screenBrowser: engine and versionBrowserengine andversionNetwork: speed, loss, offlineNetworkspeed, loss,offlineCDN edge: static files, HTMLCDN edgestatic files,HTMLProduct and search APIsProduct andsearch APIsHTML, JS, CSSdata

    How to read this: everything on the left is a condition you must design for and cannot fix. Everything on the right is where you can act. Requirements describe the left side; architecture is your response on the right.

    Device dimensions: processor speed and memory (which decide how much JavaScript a device can run before it feels stuck); screen size and pixel density; input (touch, mouse, keyboard, voice, switch devices); assistive technology such as screen readers; and user preferences such as larger text, a dark colour scheme, or reduced motion.

    Network dimensions: bandwidth, latency (the delay per round trip), packet loss, connection changes mid-session (walking from Wi-Fi to mobile data), metered or capped data, captive portals (a hotel Wi-Fi page that blocks everything until you sign in), and no connection at all.

    Browser dimensions: the engine (Chromium-based, Gecko, WebKit), the version, and which platform features exist. Support differs between engines and versions. MDN's compatibility tables for each feature are the reference.

    Some APIs let a page ask about the network. The Network Information API exposes navigator.connection, with an effectiveType estimate. At the time of writing, MDN marks it "Limited availability", meaning it is not Baseline (see below), so treat it as an optional enhancement and never as a requirement.

    The pattern matters more than the API: ask for the hint if it exists, and make the page correct when it does not.

    From a vague wish to a measurable requirement

    "Make it fast" is the front-end version of "make it reliable". It cannot be tested, so it cannot be traded off or defended. Use a short procedure.

    Figure 3. Turning a wish into a requirement and a budget

    flowchart TD accTitle: Turning a vague wish into a measurable requirement accDescr: A vague wish is made specific by choosing a journey, a user condition, a metric and a percentile, then a threshold, a budget and a place to enforce it. W["Wish: make it fast"] --> J["Pick the journey
    product page, search, checkout"] J --> C["Pick the condition
    device class and network"] C --> M["Pick the metric
    what the user sees or feels"] M --> T["Set threshold and percentile
    for example 75th percentile"] T --> B["Derive a budget
    script size, request count"] B --> E["Enforce it
    CI check plus field monitoring"]

    How to read this: each step removes a degree of vagueness. The wish becomes a requirement after the threshold step, and a budget and an enforcement point make it stay true as the code changes.

    Pick user-centred metrics

    web.dev defines three Core Web Vitals, with "good" targets assessed at the 75th percentile of page loads, segmented across mobile and desktop:

    • Largest Contentful Paint (LCP): loading. Good is 2.5 seconds or less.
    • Interaction to Next Paint (INP): responsiveness. Good is 200 milliseconds or less.
    • Cumulative Layout Shift (CLS): visual stability, meaning how much content jumps around. Good is 0.1 or less.

    These are thresholds published at the time of writing (see the web.dev link below, which is where changes would appear). The Loading Performance and Core Web Vitals lesson explains how each is measured and improved. Here the point is narrower: they give you shared vocabulary for a requirement sentence. You can also add your own metrics, such as the time until the add-to-basket button works.

    Note the percentile. A 75th percentile target means one visit in four may be worse. A stricter requirement for checkout, such as the 90th, is a legitimate product decision with a cost.

    Turn the metric into a budget

    A performance budget, in web.dev's words, is a set of limits imposed on metrics that affect site performance. web.dev describes three kinds: quantity-based (page weight, number of requests, script size, number of fonts), milestone timings (loading and interaction milestones) and rule-based (scores from tools such as Lighthouse). Quantity limits are easy to explain and to check in a build. Timing limits are closer to the user experience. Combine both.

    A budget is derived from a requirement. If the product page must show its main image in 2.5 seconds on a slow connection, there is only so much you can download before then. Work backwards from the target, divide it among HTML, CSS, JavaScript, images and fonts, and write the result down. Illustrative budget for the product page:

    Resource Limit (illustrative) Why
    JavaScript needed before first interaction 150 KB compressed Parse and run cost on weaker phones
    Images above the fold 1 hero image, at most 3 requests Main image decides the loading time
    Web fonts 2 files Each is a request and can shift text
    Third-party scripts 0 before consent Privacy and loading requirement

    Enforce the budget where it is cheapest to catch a break. A check in continuous integration (CI) fails the build when a limit is passed, the way a test fails. Field monitoring then catches what a lab test cannot. web.dev names Lighthouse CI among the tools for CI checks.

    A browser-support policy

    "Support all browsers" is not a policy, because support has a cost and the list must be finite. A browser-support policy states which browsers get the full experience, which get a working basic experience, and which are not tested. Write it as sentences and as a machine-readable query.

    For the second part, Browserslist is a shared configuration read by front-end build tools, such as Babel and Autoprefixer, so they know which browsers to target. Its queries are described in its README. A few examples from the README: > 0.5% (browsers above that share of global usage), last 2 versions, not dead (excludes browsers without official support or updates for 24 months), and defaults, which expands to > 0.5%, last 2 versions, Firefox ESR, not dead. Put it in package.json:

    {
      "browserslist": [
        "> 0.5%",
        "last 2 versions",
        "Firefox ESR",
        "not dead"
      ]
    }

    That is a usage-based policy. It depends on the Can I Use data bundled with the tool, which you must update from time to time.

    A second option is Baseline. web.dev describes Baseline as an indicator of which web platform features are safe to use based on browser support, now defined by the WebDX Community Group. A feature is Baseline Newly available when it works in all browsers of the core set: Chrome (desktop and Android), Edge, Firefox (desktop and Android) and Safari (macOS and iOS). It becomes Baseline Widely available 30 months after that date. Browserslist's README lists queries such as baseline widely available and baseline newly available, so the same idea can drive tooling. Check your installed Browserslist version supports them.

    {
      "browserslist": ["baseline widely available"]
    }

    A readable policy for the store, in plain sentences (illustrative):

    1. Full experience: the current and previous major versions of the Baseline core browsers on desktop and mobile.
    2. Basic purchase path: older browsers that still run our basic HTML and CSS. They can search, view a product and check out without enhancements.
    3. Not tested: anything else. We do not block it, we do not promise it.
    4. Review: the policy is checked against field data (which browsers real shoppers use) every quarter, and any change is recorded.

    The third point is honest and cheap. The fourth stops the list from freezing while your audience moves.

    Accessibility as a requirement

    Accessibility means people with a wide range of abilities and circumstances can use the product: low vision, colour blindness, deafness, motor or cognitive differences, a broken arm, bright sunlight, a noisy room. Treating it as a requirement means naming a target and a method, the way you name a performance budget.

    The standard to name is the Web Content Accessibility Guidelines (WCAG), published by the W3C. At the time of writing, WCAG 2.2 is the newest version (a W3C Recommendation, first published on 5 October 2023; the current edition is dated 12 December 2024), and the W3C encourages use of the latest version. It does not supersede WCAG 2.0 or 2.1, but content that meets 2.2 also meets those earlier versions, with one exception: 2.2 removes the criterion on parsing (4.1.1), so people required to report on 2.0 or 2.1 may still need to test it. WCAG 3 is an early draft and not something to cite as a target.

    WCAG is organised under four principles: perceivable, operable, understandable and robust. Each success criterion (a testable statement) is assigned to one of three conformance levels: A (the minimum), AA and AAA (the highest). The levels are cumulative: AA means all A and AA criteria are met. The W3C's own guidance says Level AAA is not recommended as a general policy for entire sites, because some content cannot meet every AAA criterion.

    So a common requirement is "WCAG 2.2 Level AA for the three journeys". Two criteria you can turn into specific tests:

    • 1.4.3 Contrast (Minimum), AA: text needs a contrast ratio of at least 4.5:1, or 3:1 for large text (at least 18 point, or 14 point bold).
    • 2.5.8 Target Size (Minimum), AA: pointer targets need to be at least 24 by 24 CSS pixels unless an exception applies, such as sufficient spacing. This affects buttons on the checkout page.

    Automated tools find a limited part of the problems. Keyboard-only checkout, screen-reader labels and focus order need a person to test them. Put both methods in the requirement.

    WARNING

    Do not turn a WCAG level into a statement about legal compliance. Whether a rule applies to you, and which version or level it expects, depends on your country, your sector and the wording of the regulation. Ask your legal team. This lesson gives engineering requirements, not legal advice.

    Progressive enhancement and graceful degradation

    Both approaches answer the question "what happens when something is missing?" MDN defines progressive enhancement and graceful degradation as related but pointing in opposite directions.

    • Progressive enhancement starts with a baseline of essential content and function for as many users as possible, then adds richer experiences for browsers that can run them.
    • Graceful degradation starts from the full experience and falls back to something less capable, still delivering essential content and function, where features are unavailable.

    MDN says both are valid and often complement one another. For a front-end design the practical difference is where you begin. The first suits the primary purchase path, where failure costs money. The second suits an extra, such as an animated product viewer.

    Here is progressive enhancement in a search form. Without JavaScript it is an ordinary form that loads a results page. With JavaScript, a script can take over and update the page in place.

    <form action="/search" method="get" id="search-form">
      <label for="q">Search products</label>
      <input id="q" name="q" type="search" required>
      <button type="submit">Search</button>
    </form>
    <div id="results"></div>
    <script type="module">
      const form = document.getElementById("search-form");
      form.addEventListener("submit", async (event) => {
        event.preventDefault();
        const query = new FormData(form).get("q");
        const response = await fetch(`/search?q=${encodeURIComponent(query)}&partial=1`);
        if (!response.ok) { form.submit(); return; } // fall back to the full page load
        document.getElementById("results").innerHTML = await response.text();
      });
    </script>

    If the script fails to load or the fetch fails, the form still works. The sample assumes the server has a results page at /search and can return a fragment for partial=1; both are part of the design, not given by the browser. Injecting server text with innerHTML is only safe when the server escapes it, a point the security lesson covers.

    The same idea applies in CSS. Use a feature query so a browser that lacks a feature keeps working with the plain layout.

    .product-grid { display: block; }
    
    @supports (display: grid) {
      .product-grid {
        display: grid;
        grid-template-columns: repeat(auto-fill, minmax(12rem, 1fr));
        gap: 1rem;
      }
    }

    A browser that understands display: grid gets the grid; one that does not shows the products in a plain column.

    The requirements people forget

    Four qualities appear late, and then they are expensive.

    • SEO and link previews. Search engines differ in how they handle JavaScript. Google says it renders pages with a headless Chromium when resources allow, and still describes server-side or pre-rendering as a great idea, because not all bots can run JavaScript. A link preview (the card shown when a link is pasted into a chat app) is usually built from tags in the <head> of the first HTML response; the Open Graph protocol defines og:title, og:type, og:image and og:url as the required properties. If a requirement says "product pages show a title and image when shared", client-only rendering of those tags will not meet it for crawlers that do not run scripts.
    • Internationalisation (i18n). Beyond translated text: currency, dates, number formats, text that grows, and right-to-left layouts. The browser's Intl API formats numbers by locale, as in the example below. Retrofitting after the layout is written is far harder than planning for it. WCAG 3.1.1 (level A) also expects the page language to be set with lang on the html element.
    • Privacy and consent. Requirements such as "no tracking script before consent" shape how third-party scripts load. The rules depend on your jurisdiction, so involve legal early and turn the decision into a testable sentence.
    • Security. Beyond a CSP, third-party scripts run with the full power of your page. A requirement should say which third parties may run on which pages.
    const price = 123456.789;
    console.log(new Intl.NumberFormat("en-US", { style: "currency", currency: "USD" }).format(price));
    // $123,456.79
    console.log(new Intl.NumberFormat("de-DE", { style: "currency", currency: "EUR" }).format(price));
    // 123.456,79 € (MDN's example; a no-break space separates the number and the sign)

    Both lines format the same number; only the locale changes.

    How requirements drive architecture

    A requirement is useful when you can say what it changes. These are the questions the later lessons answer; this table links each requirement to the design choice it pushes toward, using the store's examples.

    Requirement (illustrative) Design consequence Trade-off
    Product page content visible within 2.5 s on mobile for 75% of visits Rendering strategy that delivers HTML with content, not an empty shell; small critical script budget Server or build-time work and cache rules to maintain
    Product pages indexable and shareable HTML includes title, price, description and preview tags in the first response Less personalisation in cached HTML
    Price and stock must not be stale at payment Cache product description aggressively, never cache the final price check More API calls on checkout
    Basic purchase path works without enhancements Progressive enhancement: forms that submit by themselves, enhanced by script Two code paths to test
    One team ships checkout independently Separate route bundles and deploy boundary; shared design system Duplicated dependencies; versioning of shared parts
    Search stays usable on a flaky connection Show last results with a "may be out of date" label; cancel stale requests State handling grows more complex
    No third-party script before consent Load analytics after the consent choice; a tag-loading rule in CI Less marketing data from the first visit
    WCAG 2.2 AA for checkout Semantic HTML first, a tested component library, focus management in the router Slower custom widgets
    Order never placed twice Unique request key and a "check status" step after a timeout Needs server support

    The Frontend System Design lessons Rendering Strategies and HTTP Caching for the Front End take the rendering and caching consequences in turn. For the server-side view of caching, see caching basics.

    Figure 4. A checkout request on an unreliable network

    sequenceDiagram accTitle: Placing an order when the response is lost accDescr: The shopper presses pay, the page sends one request with a unique key, the response is lost, so the page asks for the order status using the same key and shows the confirmation. participant S as Shopper participant P as Checkout page participant A as Order API S->>P: press Pay P->>P: disable button, show progress P->>A: place order with key K A-->>A: order created for key K Note over P,A: response is lost, page times out P->>S: "Still working, checking your order" P->>A: status of key K A-->>P: order exists P-->>S: confirmation screen

    How to read this: the requirement "an order is never placed twice, and the shopper is never left guessing" is met by two choices, one unique key per attempt and a status check instead of a blind second submit.

    If the key is meant to prevent duplicates, the server must honour it. That is why front-end requirements often become API requirements; see API design.

    Negotiating trade-offs with product and design

    Requirements conflict. A marketing carousel wants large images and scripts; the budget wants few. A designer wants a custom date picker; the accessibility target wants native behaviour or a lot of testing. Negotiation goes better with a repeatable approach than with opinions.

    1. State the conflict in user terms. Not "the carousel is heavy" but "with the carousel, the main product image appears later than the target for slower connections".
    2. Show the data. A lab trace, a field metric, or a budget table makes the discussion concrete without personal criticism.
    3. Offer options with costs. For the carousel: show one hero image and load the others on interaction; keep the carousel and raise the budget by dropping another feature; or move it below the fold.
    4. Ask for a decision, record it, set a revisit trigger. The back-end lesson's decision record works here: context, decision, consequences, revisit when.
    5. Protect the non-negotiables. Agree early which requirements are fixed (checkout works on the basic path, AA contrast) and which are budgets that can move.

    A budget is a negotiation tool. Because adding something means paying for it with something else, the conversation changes from "can we add this?" to "what do we trade for it?"

    In practice: an online store fixes its product page, search and checkout

    NOTE

    A realistic scenario, not a case history. This is a composite example built from common production patterns. It does not describe any specific company, and every number in it is an illustrative assumption.

    The situation

    A mid-sized online store sells home goods. A team of five front-end engineers maintains one application that is rendered entirely in the browser: the server returns an almost empty HTML page and a large JavaScript bundle, which then calls product, search and payment APIs. Customer support reports three complaints: the site feels slow on phones, shared product links show a blank preview card, and some mobile shoppers say the Pay button "does nothing". Nobody has written down what the site must do, so each complaint turns into an argument.

    Starting architecture

    Figure 5. Starting architecture: everything renders in the browser

    Starting architecture: everything renders in the browserShopper to CDN; CDN to Browser app (bundle); Browser app to Product API; Browser app to Search API; Browser app to Payment providerShopper: phone or laptopShopperphone or laptopCDN: empty HTML, big bundleCDNempty HTML, bigbundleBrowser app: renders everythingBrowser apprenderseverythingProduct APIProduct APISearch APISearch APIPayment provider: script in pagePaymentproviderscript in pagebundle

    How to read this: the shopper's phone has to download and run the whole bundle before anything useful appears, and the Pay button depends on a script from a third party loading in time.

    Options considered

    Option What it fixes What it costs Risk
    Optimise inside the current design (split bundles, compress images) Some loading time Low Preview cards and indexing stay broken; no written target
    Write requirements first, then change the rendering of product pages only Loading, previews, indexing for the pages that earn the money A rendering change and cache rules for product pages Cached pages can show stale price if rules are wrong
    Rewrite everything on a new framework Possibly everything Months of work, a long freeze No agreed target to prove the rewrite helped

    The decision

    Field Decision record
    Context Complaints about speed, link previews and a dead Pay button, with no shared definition of "good".
    Decision Write ten requirements (journey, condition, measure, method). Serve product pages as HTML with content and preview tags; keep search in the browser with a server-rendered fallback; keep checkout as a small separate bundle with its own budget and an error state for a failed payment script.
    Consequences, good A written target; previews and indexing work; the purchase path no longer depends on one script.
    Consequences, bad Cache rules for product pages to own; two code paths for search; some marketing scripts must wait for consent.
    Revisit when Field data shows the product-page target missed for two consecutive months, or the support policy for browsers changes.

    Rollout and verification

    First collect field data for four weeks with no change, so the targets are based on what real visits show rather than a guess. Then add the budget as a CI check that reports but does not block, then blocks. Ship the new product-page rendering to a small share of visits with a feature flag, and compare field metrics and the share of visits that reach checkout. Check the raw HTML response (not the page after scripts run) for title, price and preview tags. Add a fault test that blocks the payment script and confirms the checkout shows the error state with a way forward.

    Figure 6. After the change: product pages arrive as HTML, checkout has its own path

    After the change: product pages arrive as HTML, checkout has its own pathShopper to CDN (browse); Shopper to Checkout bundle (buy); CDN to Product API (on cache miss); Checkout bundle to Order API; Order API to Payment provider; Shopper to Field monitoring (field data)ShopperShopperCDN: cached product HTMLCDNcached productHTMLCheckout bundle: own budgetCheckoutbundleown budgetProduct APIProduct APIOrder APIOrder APIPayment provider: load with timeoutPaymentproviderload with timeoutField monitoring: real visitsFieldmonitoringreal visitsbrowsebuyon cache missfield data

    How to read this: browsing and buying now take different paths with different budgets. Monitoring watches the real shopper visits so a missed target is seen quickly.

    The 2 a.m. failure

    The payment provider has an outage in one region. The script that draws the card form never loads, and the Pay button stays disabled. Orders from phones fall sharply. A synthetic check that opens checkout every minute raises an alert: "checkout form not shown within 10 seconds".

    First three checks: the payment script request in the browser's network panel (blocked, timing out or returning an error), the checkout funnel in field data (visits that see the form versus visits that submit it), and the provider's status page. Mitigation: switch on the flag that redirects payment to the provider's hosted page, which does not need the script in your page. Follow-up fixes: load the script with a timeout, show an error state with a retry and the hosted-page alternative, and add the "payment script fails" case to the fault tests. The requirement that would have caught it was already in the table: reliability under a failed dependency.

    Architect's notes

    • Write requirements before choosing a framework. A framework choice is an answer. Know the question first.
    • Decide per journey, not per site. Checkout deserves a tighter budget and a simpler stack than a marketing page. The product page earns the strictest loading target.
    • Measure in the field. Lab tests catch regressions; field data tells you what users get. Collect it early.
    • Define the support policy and the baseline path early. The cost of supporting a browser is paid for every feature. A written policy lets you say no calmly.
    • Treat accessibility as a design input. Retrofitting is slower than starting with semantic HTML and a tested component library.
    • Defer what you cannot yet measure, such as offline support, until a requirement justifies it. Name an owner for each budget you do set.

    Common mistakes

    • Writing adjectives instead of sentences. "Fast" and "accessible" cannot be tested. Fix: journey, condition, measure, method.
    • Using the developer's laptop as the reference. It is a fast device on a good network. Fix: pick a device and network class to test, and check field data. Quote a percentile, not an average, as the Core Web Vitals do.
    • Designing only the success state. Loading, empty, error and partial states are where users get stuck. Fix: list them as requirements.
    • Promising every browser. It is untestable and costly. Fix: write a support policy and review it.
    • Treating accessibility as a late audit. Fixes cost more at the end. Fix: name the WCAG version and level at the start.
    • Letting third-party scripts in unmanaged. Marketing tags can break privacy, security and speed at once. Fix: a budget and an owner for third parties.

    Key takeaways

    • Front-end requirements describe a person on an unknown device and network. You cannot see the conditions from your server, so measure field data.
    • States are requirements. Loading, empty, error, partial and offline need an explicit design, and partial failure drives architecture.
    • Write a testable sentence. Journey, condition, measurable outcome, method of checking.
    • Use user-centred metrics and percentiles. Core Web Vitals give a shared vocabulary, with good targets at the 75th percentile.
    • A budget turns a target into limits. Quantity, timing and rule-based limits are enforced in CI and watched in the field.
    • Write a browser-support policy. Use Browserslist and Baseline to express it, and review it against field data.
    • Name a WCAG version and level. WCAG 2.2 Level AA is a common target, tested by tools and by people. It is not a legal statement.
    • Start from a working baseline. Progressive enhancement for the purchase path; graceful degradation for extras.
    • Map each requirement to a design consequence and a trade-off. Then negotiate with product and design using data and options, and record the decision.

    Practice exercises

    Exercise 1 - Starter (30 min): Take the wishes "the product page should be fast", "checkout should be reliable" and "search should work on bad Wi-Fi". Rewrite each as a sentence using the template (journey, condition, measurable outcome, method). Label every number as illustrative.

    Exercise 2 - Intermediate (2 hours): For the store's search results, write a state table with the six states from this lesson: what the user sees and what they can do next in each.

    Exercise 3 - Intermediate (2 hours): Write a browser-support policy for a product you know: three tiers in plain sentences and a Browserslist query. Run your query with Browserslist's command-line tool on your machine and list the browsers it selects. Say which entries you would remove and why.

    Exercise 4 - Advanced (half day): Choose one page of a site you maintain. Measure its main load metric and its script size, set a requirement and a budget for it, and write a CI step that fails when the script size passes your limit. Then write a one-page note for product and design that proposes one trade-off (for example removing a third-party script) using the negotiation steps.

    In this course:

    Elsewhere on the site:

    Official documentation

    Enroll to keep reading

    Lesson 2 of 8 · Frontend System Design Foundations: How the Web Runs

    Turn wishes like 'make it fast' into testable front-end requirements: budgets, browser support, accessibility and states, and see how each shapes the design.

    In the rest of this lesson

    • A browser-support policy
    • Accessibility as a requirement
    • Progressive enhancement and graceful degradation
    • The requirements people forget
    • How requirements drive architecture
    • Negotiating trade-offs with product and design

    Enrolling is free. It unlocks every lesson in Frontend System Design Foundations: How the Web Runs, tracks your progress across devices and keeps your quiz scores. The newsletter is optional.

    Ask about this article

    Get answers grounded in this post. AI-generated — based on this article, and may be imperfect.

    Scaled AI Weekly

    Enjoyed this? Get more like it every Monday.

    Real architecture decisions, LLMOps patterns that survive production, and engineering leadership advice — from 12+ years of building at enterprise scale. Free. No spam. Unsubscribe anytime.

    Get new articles by email

    Free. We email a confirmation link first, and you can unsubscribe from any email.

    Join engineers building production AI systems

    Comments