Two markers sit on the same declaration, one pure description and one causing behaviour, so how do you tell them apart?
answer
- metadata means whatever reads it
- describes, or causes
- the name proves nothing
- delete it and watch
- report changed, or the run changed
basics
~20 sNot from the marker's name, shape or members — attached metadata carries no intrinsic meaning. Classify by what changes when it is absent: remove it, and see whether only a report changes or the program's behaviour changes.
solid answer
~50 sA marker attached to a declaration is inert; its meaning comes entirely from whatever acts on it. So the marker's name, its members and where it sits tell you nothing reliable about which of the two kinds it is. The usable test is **delete-and-observe**: remove the marker and ask what changed. If only a report, an index or a piece of documentation changed, it was **description**. If the build now fails, or the payroll run is no longer re-attempted after a failure, it was **instruction** — and you should also say at which stage the change showed up, because a marker that fails a build and one that wraps a call are both instructions with very different blast radii. The line is not permanent: a description-only marker becomes an instruction the moment someone writes something that acts on it, and that addition is a behaviour change.
code
pseudocode · 10 lines<<owner "payroll-team">>
<<retried max 3>>
function runPayroll(batch)
postAll(batch)
end
// remove <<owner "payroll-team">>
// -> the ownership report lists one fewer method; the run is identical
// remove <<retried max 3>>
// -> a failed run is no longer re-attempted; no report mentions itgo deeper
Recall that metadata attached to a declaration does nothing on its own — something has to read it. So never assume from a marker's name that it makes anything happen.
Explain the delete-and-observe test and name the stage at which the difference appeared: a report, the build outcome, or what the program does when it runs. That staging is the part most candidates leave out.
Show the operational consequence: adding a consumer for an existing marker changes behaviour everywhere it is already attached, and losing one silently reverts every marked declaration while the markers still read like promises.
Own the convention. Decide how a codebase keeps descriptive and behaviour-causing markers separable, who may introduce a new one, and how the currently-consumed set is published rather than remembered.
## Metadata means whatever reads it Attaching a marker to a declaration adds a fact *about* the declaration. On its own the fact does nothing: it sits there, carried along with the code. Everything interesting — a report, a failed build, a boundary opened around a call — happens because something else read the fact and chose to act. This is the single idea the whole distinction rests on, and it is why the intuitive tests people reach for do not work: - **The name does not tell you.** A marker named for an intent reads exactly the same whether anything implements that intent or not. - **Members do not tell you.** A marker carrying a retry count looks purposeful, but a purely descriptive marker can carry members too, and a bare marker with no members can cause a great deal to happen. - **Placement does not tell you.** Markers of both kinds sit in the same position above the same declarations. ## The delete-and-observe test The reliable classification is behavioural, not syntactic. Remove the marker — in a scratch branch, not in the payroll service — and ask a precise question: **what observable thing is different now?** Then name the stage at which it differed. | What changed when you removed it | Classification | Example of the change | |---|---|---| | A report, an index, a generated document | **Description** | The ownership report lists one fewer method | | An editor hint or a warning, with the program unchanged | **Description** (tooling-facing) | A hint stops appearing for callers | | The build outcome | **Instruction, at build stage** | A rule stops being enforced and the build now passes | | What the program does when it runs | **Instruction, at run stage** | The payroll run is no longer re-attempted | Naming the stage matters because it is what a reviewer needs. "Instruction" alone does not distinguish a marker whose loss fails loudly at build time from one whose loss is invisible until a production failure that would have been absorbed. ## The line is not a property of the marker; it is a property of the system A marker that is description today becomes an instruction the day somebody writes something that acts on it. Nothing about the marker changes — no line above the payroll method is edited — and yet every declaration carrying it changes behaviour at once. Two consequences follow: 1. **Introducing a consumer for an existing marker is a behaviour change**, and it is one of the widest-blast-radius changes a codebase can take, because it applies to every declaration already marked. It deserves review as such, not as "wiring a new component". 2. **A marker nobody acts on is a liability in waiting.** It reads to a newcomer as if it does something. Either remove it or make the system report that nothing acts on it. The reverse direction is the same story: if the thing that acted on a marker is removed or stops matching, every marked declaration silently reverts to plain behaviour while the markers remain on screen, still reading like a promise. ## Why the distinction is worth making out loud Declarative configuration kept next to the code is genuinely valuable — the intent is visible at the declaration rather than buried far away — but only if the reader can tell which attached facts are promises about behaviour and which are notes. A codebase that mixes the two freely, with no convention distinguishing them, teaches its readers to ignore markers entirely, which is the worst outcome available: the instruction markers stop being read too. Practical conventions that hold the line: - Keep the two kinds **visually or lexically separable** — a naming convention, a separate namespace, a documented list — so a reader can classify without running an experiment. - **Publish which markers currently have a consumer.** This is the durable form of the delete-and-observe test, computed rather than remembered. - When a marker's classification changes, **treat it as a release-worthy event** and say so in the change description. - Resist adding a description-only marker that reads like an instruction; if it only documents something, a name that sounds like documentation costs nothing and prevents a wrong assumption. ## What an interviewer is listening for The weak answer classifies by vibe: "this one sounds like it does something". The strong answer says that attached metadata has no intrinsic meaning, gives the delete-and-observe test, names the stage at which the difference appeared, and adds the uncomfortable part — that the classification can change under you without any edit to the marked code at all.
- Can the same marker be description in one release and instruction in the next?Yes, and nothing above the marked declaration has to change for it to happen. The meaning lives in whatever acts on the marker, so adding that consumer converts every already-marked declaration at once. Review the addition as a behaviour change with a wide blast radius rather than as new plumbing.
- A marker makes the build fail when a rule is broken. Is that description or instruction?Instruction, but at build stage rather than run stage. Its removal changes an observable outcome — the build stops rejecting the violation — while the running program behaves the same. Naming the stage is the useful part of the answer, because a loss that fails the build is far cheaper than one that surfaces only in production.
- What should a codebase do with a marker that nothing acts on?Remove it, or make the system say so. An unconsumed marker reads to a newcomer as a promise about behaviour, so it misleads exactly the people least able to check. If it must stay for a future consumer, publish it in the list of markers currently without one.
saying these in an interview costs you the question
- Says a marker carrying members must be behaviour-causing.
- Says a marker is inert unless a compiler enforces it.
- Believes the marker's name reliably reveals what it does.
- Thinks a marker read by a reporting script changes program behaviour.
- Assumes a description-only marker can never become an instruction.