skip to content

Which query authoring styles break the build when a mapped field is renamed, and which fail later?

level: middleimportance: must knowfreq 66%

answer

  1. symbol versus text
  2. the compiler skips string literals
  3. regenerate, then compile
  4. startup validation is the middle rung
  5. first execution is the late one

basics

~20 s

Only styles whose field names reach the compiler as symbols break the build: a generated typed DSL, or a builder taking generated field references. Query strings, derived method names and named queries fail at startup or first run.

solid answer

~40 s

Sort the styles by where the field name lives. In a schema-generated typed DSL - and in a builder that takes generated field references rather than quoted strings - the name is a symbol, so regenerating after the schema change makes the compiler fail at every call site. In an object-level query string, or a builder that takes field names as strings, the name is text the compiler cannot see, so it survives the rename and fails when something parses it. Between those extremes sit two startup-time forms: a query derived from a data-access method name, and a query declared by name and validated while the application boots - both stop the deploy rather than the build. The practical ranking is compile error, then failed boot, then a failed request in production weeks later.

go deeper

for a junior

Remember the split: names the compiler sees as symbols break the build, names hidden in quotes do not. That single distinction answers most of the question.

for a middle

Explain each of the five forms and the exact moment its names are resolved, and note that a generated DSL's build error depends on regenerating before compiling.

for a senior

Argue the operational difference between a failed build, a failed boot and a failed request, and describe the cheapest step that moves a given codebase one rung earlier.

for a principal

Judge whether compile-time safety is worth coupling the build to schema state, and what you standardise on when parts of the system cannot pay that cost.

## The question behind the question Every authoring style ends in the same place - a SQL statement sent to the engine - so the interesting difference between them is **how early a wrong name is noticed**. Renaming a mapped field is the cheapest test of that, because a rename is exactly the change that a text-based query cannot follow. ## The five common forms - **An object-level query string.** Text naming mapped classes and fields, parsed by the layer. The compiler sees a string literal and nothing more. - **A fluent or criteria builder.** The query is assembled by calling methods in code. Whether a rename breaks the build depends entirely on **how the field is named in that call**: a quoted string is invisible to the compiler, a generated field reference is not. - **A typed DSL generated from the schema.** A build step reads the schema (or the mapping) and emits code in which every table and column is a typed symbol. Queries reference those symbols, so a query is ordinary code that the compiler type-checks. - **A query derived from a method name.** The layer parses the name of a data-access method into a predicate at wiring time. The name is code, but the *field tokens inside it* are matched against the mapping at startup, not by the compiler. - **A named query declared once and validated at startup.** The text is still text, but it lives somewhere the layer can enumerate, so every declared query is parsed while the application boots. ## Earliest possible check, by form | Authoring form | Earliest check | Symptom of a stale field name | |---|---|---| | Object-level query string | Parse: startup or first execution | A failing request, or a failing boot if declared | | Builder with string field names | Parse or execution | Same as above - the string hides the name | | Builder with generated field references | **Compile** | Build error at the call site | | Schema-generated typed DSL | **Compile** (after regeneration) | Build error at every call site that used it | | Method-name-derived query | Startup, when the name is parsed | The application refuses to start | | Named query validated at startup | Startup | The boot fails; the deploy stops | Two rows break the build, and both do it for the same reason: **the field name reached the compiler as a symbol rather than as text**. Everything else fails later, and the useful distinction among the late ones is *startup* versus *first execution* - the difference between a deploy that stops and a page that breaks for a user next month. ## Why the typed DSL's compile error is conditional A generated DSL only breaks the build if the generator ran against the *new* schema before compiling. That is a real workflow requirement, not a footnote: 1. the schema change lands (a migration, applied to a build-time database or read from a schema definition); 2. the generator regenerates the typed symbols; 3. compilation fails everywhere the old symbol was used. Skip step 2 and the build is green against a stale picture of the schema. Teams that rely on this property wire generation into the build so it cannot be skipped, and treat generated sources as build output rather than as code to edit. ## Startup validation is the cheap 80% Not every codebase can afford a code-generation step, and startup validation gets most of the benefit for almost no infrastructure: if every query is declared where the layer can enumerate it, a bad one stops the boot. Push it one step earlier by running that boot in the test suite - then a stale query name fails the build after all, without generating anything. What startup validation cannot do is check a query that is **assembled at runtime**: text that only exists once a request supplies its parts is parsed only when that request happens. ## What this means in review - Treat a field name that appears as a **quoted string** anywhere in the data-access layer as a name nothing will check for you. - Ask where each query is **declared**: if the layer cannot enumerate it, startup validation is not covering it, whatever the docs say. - Do not read "compile-checked" as "correct". The compiler checks that the names exist and the types line up. It says nothing about whether the predicate expresses the rule you meant, whether the join multiplies rows, or whether the plan is acceptable. - Remember the asymmetry of blast radius: a compile error stops one change; a startup failure stops one deploy; a first-execution failure stops one user, quietly, later.

  • Why is a typed DSL's compile error conditional?
    Because it only appears if the symbols were regenerated from the changed schema before compiling. The chain is migrate, regenerate, compile; skip the middle step and the build is green against a stale picture. Teams that depend on this wire generation into the build and treat the generated sources as build output rather than editable code.
  • How do you get an early failure without a code-generation step?
    Declare every query somewhere the layer can enumerate, so all of them are parsed at boot, then boot the application in the test suite. A stale name then fails the build without generating anything. It misses only queries whose text is assembled at request time, since that text does not exist at boot.
  • Does a compile-checked query mean a correct query?
    No. The compiler confirms that the names exist and the types line up. It says nothing about whether the predicate encodes the rule you meant, whether a join multiplies rows, whether the emitted statement uses an index, or whether the result shape is what the caller needs. Compile safety removes one class of defect, not the interesting ones.

A compiler proofreads the sentences you write in its own language and skips anything you hand it in quotation marks. Field names in quotes are quotations: correct or not, they pass through untouched.

saying these in an interview costs you the question

  • Says a builder is compile-safe even when field names are quoted strings
  • Claims a generated DSL fails the build without regenerating first
  • Treats startup validation and compile checking as the same guarantee
  • Believes compile-checked queries cannot be logically wrong
  • Assumes startup validation covers text assembled during a request
  • Thinks a rename refactoring rewrites query text along with the code