skip to content

In a design system for a travel-expense tool, how would you use a codemod to retire an old button component across many consuming codebases?

level: seniorimportance: must knowfreq 36%

answer

  1. automation for the mechanical part
  2. map every old option first
  3. syntax tree, not text replace
  4. flag what it cannot decide
  5. dry run, review, track the rest

basics

~20 s

Map the old button's options to the new one, write a syntax-aware codemod that rewrites mechanical cases and flags the rest, test it on real usages, then have teams dry-run it and track what remains.

solid answer

~50 s

A **codemod** is a program that rewrites source code automatically, working on the parsed syntax tree rather than raw text, so it can change component references and options reliably. I would first map each option of the old button to the new button: direct equivalents, values that need translating, and options with no equivalent. The codemod handles the mechanical cases, such as the renamed component and changed variant names, and leaves a clear marker wherever it cannot decide, such as a custom style override. I would test it on a corpus of real usages collected from consumers, make it safe to run twice, and ship it with the migration guide. Teams run it as a dry run, review the diff, fix the flagged cases by hand and check their screens, while remaining usages are tracked until they reach zero.

code

pseudocode · 15 lines
pseudocode
for each source file in codebase:
  tree = parse(file)
  for each usage of OldButton in tree:
    if usage already refers to NewButton: continue
    replace component reference OldButton -> NewButton
    if usage.kind in [primary, secondary]: set usage.variant = usage.kind
    if usage.kind == danger: set usage.variant = critical
    if usage.small is true: set usage.size = small
    remove usage.kind and usage.small
    if usage has customStyle:
      add marker comment 'DS-MIGRATE: review custom style on button'
      flagged += 1
    rewritten += 1
  if tree changed: write file preserving formatting
report rewritten, flagged

go deeper

for a junior

Recall that a codemod rewrites code automatically so teams can migrate from a deprecated component quickly, and that its output still needs review.

for a middle

Explain why codemods work on the syntax tree, why they must be idempotent, and why unsafe cases are flagged instead of guessed.

for a senior

Show the full rollout: the option mapping, testing on real usages, dry runs, manual resolution of flagged cases, visual checks and per-team usage tracking.

for a principal

Weigh the cost of building and supporting codemods for each platform against the migration effort they save across all consuming teams, and decide when a change warrants one.

## What a codemod is, and why use one A **codemod** (code modification) is a program that rewrites source code automatically. Good codemods parse each file into a **syntax tree**, the structured representation a compiler uses, find the constructs to change, rewrite them and print the code back. Working on the tree rather than on text means the codemod can tell a real use of the old button from a comment or a string that happens to contain the same word. On a travel-expense tool, the old button appears in hundreds of places: submit-expense forms, approval queues, receipt screens, admin settings. Migrating each by hand is slow and error-prone, and many teams would put it off. A codemod turns most of the migration into a reviewable, automatic change, which is why deprecating a widely used component usually comes with one. ## Step 1: map old to new Before writing any code, list every option of the old button and decide what it becomes: | Old button option | New button equivalent | Codemod handles it? | |---|---|---| | Kind primary or secondary | Variant with the same name | Yes, direct rename | | Kind danger | Variant critical | Yes, value translation | | Small flag | Size option set to small | Yes, shape change | | Icon-only with no label | Icon button with a required accessible label | Partly: adds a marker when no label text can be found | | Custom style override | No equivalent | No: flagged for manual review | The mapping becomes both the codemod's specification and the core of the **migration guide**. ## Step 2: write and test the codemod - **Operate on the syntax tree**, rewriting component references and options, and preserving the surrounding formatting so diffs stay small. - **Make it idempotent**: running it twice must change nothing the first run already migrated, because teams will rerun it after merging new code. - **Flag, do not guess.** Where the mapping has no safe answer, leave a clearly searchable marker comment for a person to resolve. - **Test on real usages.** Collect a corpus of how consumers actually use the old button, including awkward cases like wrappers and dynamic option values, and make each a test case. - **Report counts**: files changed, usages rewritten, usages flagged. ## Step 3: roll it out 1. Publish the codemod with the release that deprecates the old button, and link it from the migration guide. 2. Each team runs it as a **dry run** first to see the proposed changes without writing them. 3. The team applies it, reviews the diff like any other change, and resolves every flagged case by hand. 4. The team checks affected screens, since the new button may differ in size, spacing or focus style. 5. The system team re-counts remaining usages across codebases and follows up with teams whose counts are not falling. ## Limits of a codemod - **Dynamic usage** (a component chosen at runtime from a variable) is often invisible to static analysis. - **Wrappers** that teams built around the old button may need a change in one place, or may hide usages from the codemod. - **Visual differences** are not caught by rewriting code; screens still need a check. - **Design files** are untouched: designers swap the old button for the new one in the design library and in existing files separately. - **Multiple platforms** need their own tooling. Web and native mobile codebases each need a codemod written for their language and parser, but they can share the same mapping and guide. ## Measuring completion A codemod is also worth versioning and maintaining like any other system artifact during the support window. Teams will report patterns it mishandles, and each fix should be released quickly with a note, because a codemod that fails on a team's common pattern pushes that team back to manual migration and delay. The goal is zero remaining usages by the removal release. Publishing the per-team count with each release keeps progress visible, and a falling curve is the best evidence that the codemod and guide are doing their job; a flat one means the flagged cases are harder than expected and need hands-on help.

  • Why test a codemod on a corpus of real consumer usages rather than only on hand-written examples?
    Hand-written examples reflect how the system team expects the button to be used; real code contains wrappers, dynamic values, unusual option combinations and formatting the team never imagined. Those are exactly the cases where a codemod crashes, produces wrong output or silently skips a usage. A real corpus finds them before thirty teams do.
  • What should happen to the marker comments a codemod leaves behind?
    They should be searchable and counted. Each marks a usage the codemod could not migrate safely, so the team resolves it by hand and removes the marker. The system team tracks the number of open markers alongside remaining usages, because a codebase with no old buttons but many unresolved markers is not finished.

saying these in an interview costs you the question

  • A text search-and-replace is as reliable as a syntax-aware codemod.
  • A codemod should guess the closest match rather than leave anything for people.
  • Once the codemod has run, no screen needs checking.
  • A codemod also updates the design files, so designers need do nothing.
  • A codemod only needs testing on the system team's own examples.