skip to content

When a design system team scans product code for component usage, what does the scan count and what does it miss?

level: middleimportance: should knowfreq 30%

answer

  1. references, not what users see
  2. imports and instantiations per repository
  3. which version each consumer runs
  4. local look-alikes stay invisible
  5. pair it with design-file analytics

basics

~20 s

A code usage scan counts where each product imports and instantiates system components, with which options and at which version. It misses local look-alikes, heavily overridden instances, dead code, and how much rendered interface each reference represents.

solid answer

~50 s

A usage scan parses each consuming repository and records every import and instantiation of a system component: which component, which product and file, which system version, and which variants or options are passed. That yields a heat map of component use, the version lag of each product, and a list of components nobody uses. What it cannot see is anything that is not a reference to the system: a hand-built dialog that copies the system's look, a wrapper that restyles a system button beyond recognition, code that is never rendered, and the difference between a button on the main screen and one in a forgotten settings page. So I treat the scan as the **usage** signal and pair it with design-file analytics, which show insertions and detaches before code exists, and with coverage sampling of shipped screens.

code

pseudocode · 9 lines
pseudocode
for repo in consumingRepositories:
    systemVersion = resolvedVersion(repo, SYSTEM_PACKAGE)
    for file in sourceFiles(repo):
        tree = parse(file)
        for ref in importsResolvingTo(tree, SYSTEM_PACKAGE):
            for use in instantiationsOf(tree, ref):
                record(repo, file, ref.componentName, systemVersion,
                       use.optionsPassed, use.hasStyleOverride)
storeSnapshot(today)

go deeper

for a junior

Recall that a code scan counts where system components are imported and used, and that a hand-built copy of a system component is invisible to it.

for a middle

Explain how a scan resolves imports, what it records per instance, including version and options, and which blind spots need another signal to cover.

for a senior

Show how you would turn scan output into decisions: version lag follow-ups, override-heavy components as missing-variant leads, and checks before calling a component unused.

for a principal

Weigh how much to invest in scanning against coverage sampling and surveys, and how to present scan data so it helps consuming teams rather than ranking them.

## What a component usage scan is In a **design system** consumed by several product teams, a **component usage scan** is an automated job that reads the source code of each consuming product and records where the system's components are used. It is the cheapest adoption signal to collect continuously, which is why most system teams build one early. It answers questions such as: which components are used most, which are never used, which products lag behind the current version, and which options people actually pass. ## How a scan works 1. **Enumerate consumers.** List every repository or package that depends on the system, on every platform: web, native mobile and any shared packages. 2. **Parse, do not text-search.** Read each source file into a syntax tree so that aliased imports, re-exports and comments are handled correctly; plain text search can both over-count and under-count. 3. **Resolve references.** Follow each import back to the system's packages, so a local re-export of a system button still counts as the system button. 4. **Record instantiations.** For each place a component is created, record the component, product, file, the system version in use and the options or variants passed. 5. **Aggregate and store over time.** Keep a snapshot per scan so trends, not single readings, can be reported. ## What it records, and why | Field | Why it matters | |---|---| | **Component name** | Shows the most and least used components, and candidates to review | | **Product and file** | Shows who depends on what, and whom a change will affect | | **System version** | Shows **version lag**: products still on superseded releases | | **Options and variants passed** | Shows unused variants, defaults that everyone changes, and heavy use of style overrides | | **Wrapped or re-exported** | Shows where teams put a local layer between themselves and the system | The options field is the most underused. If most instances of a component pass the same override, the default is wrong or a variant is missing. If a variant is never passed, it is carrying maintenance cost for nobody. ## What it misses A scan sees references to the system, so it is blind to everything that is not one: - **Local look-alikes**: a hand-built component that copies the system's appearance never imports it, so it is invisible. - **Overridden instances**: a system component restyled through overrides still counts as one use, even when nothing of the system's look survives. - **Dead code**: components referenced in files that are never rendered still count. - **Weight**: one reference to a button on the most visited screen and one on a forgotten admin page count the same. - **Unscanned consumers**: repositories nobody listed, and platforms the scanner does not parse, drop out silently. This is why a high usage count and a low share of system-built interface can coexist. ## The design-file counterpart Designers work from the system's shared library in a design editor, and such libraries commonly report **inserted instances** and **detached instances** per component and per file. This is the design-side usage signal. It is earlier than code, since it shows what is being designed now, and it records detaches, the moment a designer breaks the link to the shared component. It has its own blind spot: exploratory files and abandoned concepts count alongside designs that ship. ## Using the output - Publish a per-product dashboard of usage and version lag so consuming teams see their own position. - Treat never-used components as questions, not verdicts: check whether they are unused on every platform before proposing their retirement. - Treat components with heavy override use as research leads for missing variants. - Combine the scan with **coverage sampling** of shipped screens, which catches the look-alikes and weights the result by what users actually see. In a customer-support ticketing tool, for example, the scan might show the system's tag chip imported in forty files, while sampling reveals the ticket-priority chips agents look at all day are a local component with a different shape.

  • How would you find local look-alike components that the scan cannot see?
    The scan can flag candidates, such as local components whose names or option shapes mirror system ones, or files full of raw values close to token values, but confirming them usually needs a person. Sampling shipped screens and marking each region as system-built or local catches look-alikes directly, which is why coverage sampling complements the scan.
  • Why record the options each instance passes, not just the component name?
    Options show how the component is really used. A variant nobody passes is a candidate for removal, an option almost everyone sets to the same value suggests a wrong default, and a style override on most instances shows the component does not fit. It turns a usage count into evidence for API decisions.

saying these in an interview costs you the question

  • The number of system imports equals the share of UI built from the system.
  • A component missing from the web code scan is unused on every platform.
  • Plain text search over the code base is as accurate as parsing imports.
  • Design-file analytics make a code scan unnecessary.
  • A single scan at launch is enough; usage does not need tracking over time.