skip to content

How would you decide whether an app's route table is declared explicitly in code or derived from the project's file layout?

level: principalimportance: nice to knowfreq 38%

answer

  1. same table, different birthplace
  2. one inventory versus URL equals location
  3. can a pattern be computed at runtime
  4. who asks where a URL is handled
  5. insist the effective table is printable

basics

~20 s

Decide by how regular the URL surface is and who reads it. Derivation removes registration and makes URLs findable by file; an explicit table makes the whole surface readable and programmable. Either way the effective table must be printable.

solid answer

~50 s

Both forms produce the same thing — patterns paired with screens — and differ in where the pattern lives. **Derived**: a file's location is its URL, so nothing is registered, there is no table file to conflict over, and a newcomer finds the handler for a URL by walking the tree. The cost is that no single place lists the effective patterns, unusual shapes need escape hatches, and paths cannot be data. **Explicit**: one readable inventory you can order, compose, parameterise, generate links from and diff between releases — at the cost of a registration step everyone must remember and a file that collects merge conflicts. I decide on route count and regularity, whether patterns must vary by locale or deployment, and how often someone asks where a URL is handled. Hybrids are normal; the non-negotiables are an inspectable effective table and generated links.

go deeper

for a junior

Know that both arrangements exist and that your job is to find where a URL is handled: either the inventory file or the folder whose location matches the path.

for a middle

Explain the tradeoff concretely — registration and conflicts against an unreadable effective surface — and name the escape hatch an unusual URL needs under a convention.

for a senior

Judge from the surface you actually have: count the irregular routes, check whether patterns must be data, and insist on a printable effective table plus generated links either way.

for a principal

Own it as policy: the URL surface is public, so decide what may be expressed by convention, where exceptions live, how a rename is reviewed, and how long retired patterns are honoured.

## Two ways the same table comes to exist A route table is patterns paired with screens plus the work attached to each entry. Nothing about routing requires the patterns to be typed out. They can be **declared** — written as data in code — or **derived** by a build step from where files sit, with the location of a file naming the URL it serves. Matching, nesting, parameter conversion and not-found all work either way. The choice is about the humans and the tooling, not about the router. ## What each form costs | Concern | Explicit in code | Derived from layout | |---|---|---| | Finding the handler for a URL | read one inventory | follow the path down the tree | | Seeing the whole URL surface | it is the file you already have | needs a tool to print it | | Adding a route | a registration step to remember | create the file; nothing else | | Merge conflicts | one hot file | spread across the tree | | Unusual shapes (aliases, localised paths, several patterns for one screen) | ordinary data | an escape hatch | | Paths as runtime data | possible | not possible; names are fixed at build | | Link generation | read the table back | read a generated artifact | | Discoverability for newcomers | one file to read | strong: URL and folder agree | | Drift between structure and URLs | possible | impossible by construction | Neither column is a verdict. A regular app with a hundred conventional URLs pays almost nothing for derivation and gets real value from URL-equals-location. An app with a handful of screens but an irregular surface — localised paths, several URLs resolving to the same screen, paths configured per deployment — pays a lot for it, in escape hatches that each reader has to learn. ## The questions I actually ask 1. **How regular is the surface?** If nearly every URL is a section plus an identifier, a convention expresses that well. If a meaningful minority is special, the convention is going to be fought. 2. **Must a pattern be data?** Localised paths, patterns that differ per tenant or per deployment, or a marketing slug that changes without a release all argue for declaration, because a filename cannot be computed. 3. **Who reads this, and how often?** If the question 'where is this URL handled?' is asked weekly by people new to the codebase, URL-equals-location is worth a lot. If the question is more often 'what URLs do we expose?', an inventory is worth more. 4. **Can tooling print the effective table?** If derivation comes with a command that lists every pattern, the main cost is bought back. If it cannot, the surface is unknowable and diffing it across releases is guesswork. 5. **What does a rename cost?** Under derivation a rename is a move, which is easy to do and easy to do by accident; declaration makes the same change a visible edit in a reviewed file. 6. **What happens at the edges?** Not-found, redirects for old paths, and the pattern that is generated rather than written — check each one has an ordinary home before committing. ## The hybrid, and why it is usually right The practical answer is rarely pure. Derive the regular majority, and keep a small, explicit list for the exceptions: aliases, redirects from retired patterns, localised variants, anything computed. Then the convention carries the volume and the odd cases are *visible as odd* instead of hidden in a naming trick. The failure mode to avoid is a third mechanism appearing later because neither of the first two was allowed to hold the exceptions. ## The invariants that survive either choice - **The effective table must be inspectable.** A command or test that prints every pattern with its parameters. Without it you cannot diff the URL surface between releases and cannot reason about what you have promised. - **Links are generated from the table**, never concatenated, so a pattern lives in exactly one place whichever way it was born. - **Parameter conversion belongs to the entry**, so a URL's values become typed data at one boundary regardless of how the entry was declared. - **Not-found is an entry**, so the table stays total over paths. - **Retired patterns get redirect entries** for as long as saved links matter. ## Traps - Choosing derivation for a surface that is mostly exceptions, then reinventing declaration in comments and conventions. - Choosing declaration and letting the table become a file nobody reads and everybody conflicts in. - Accepting derivation with no way to print the effective patterns, so no one can say what URLs exist. - Migrating between the two for tidiness alone; the URL surface is public, and churn there costs users their saved links.

  • Which single capability makes a derived table acceptable at scale?
    A way to print the effective table — every pattern, its parameters and the screen it resolves to. That restores the inventory the convention removed, lets the URL surface be diffed between releases, and gives link generation something authoritative to read. Without it, nobody can answer what URLs the app exposes.
  • How would you sequence a move from an explicit table to a derived one without breaking saved links?
    Freeze the current pattern list as a test fixture, move the regular routes so the derived patterns match that list exactly, keep an explicit list for aliases and retired paths as redirect entries, and keep link generation reading whichever source is authoritative during the transition. Compare printed tables before and after every step.
  • What is the strongest argument against deriving patterns from file locations?
    Patterns that must be data: localised paths, per-deployment or per-tenant differences, or several URLs resolving to one screen. A filename is fixed at build time, so each of those needs an escape hatch, and a surface made mostly of escape hatches is harder to read than the explicit table it replaced.

saying these in an interview costs you the question

  • Treats the choice as a style preference with no cost either way
  • Accepts a derived table with no way to print the effective patterns
  • Assumes localised or per-deployment paths can be expressed as filenames
  • Keeps an explicit table nobody reads and everybody conflicts in
  • Migrates the URL surface for tidiness, breaking saved links
  • Adds a third mechanism because neither form was allowed to hold the exceptions