You own a codebase of tangled legacy routines — what standard would you set for when an unstructured jump may remain, and how would you enforce it?
answer
- rule about the defect, not the keyword
- direction and target are decidable
- the flag substitute must be named
- characterisation tests before shape changes
- measure follow-up fixes, not jump counts
basics
~20 sWrite the rule about the defect, not the keyword: permit forward-only jumps to a single top-level label inside one routine, refuse backward and inward ones, and rewrite on touch behind characterisation tests rather than in one sweep.
solid answer
~50 sA blanket ban is the tempting rule and the wrong one, because it scores the wrong thing: a routine whose jump becomes a failure flag threaded through every later step passes the ban while getting harder to change. Set the rule on **direction and target** instead. Permit a jump that goes forward only, targets one label at the routine's top level, never lands inside a block, and has its target visible on the same screen — that admits the cleanup exit and little else. Refuse backward jumps and jumps into blocks outright, since those are the shapes whose removal changes code rather than rearranging it. Enforce the refusals with an automated check, because direction and target are mechanically detectable, and leave the judgment calls to review. Then migrate **on touch**, with characterisation tests captured first, rather than scheduling a sweep through routines nobody currently needs to change.
go deeper
Recall that a rule about code shape is only useful if it targets the actual cost, and that the cost here is a reader unable to tell what happened before a given point.
Be able to state the permitted shape precisely — forward only, one top-level label, never into a block, target on the same screen — rather than repeating a blanket prohibition.
Show how you would migrate: characterisation tests captured first, shape and behaviour changed in separate commits, and only routines already under change touched at all.
Own the tradeoff between enforceability and effect. Automate the decidable rules, put the flag substitution in the standard by name, and pick a success measure that a keyword ban cannot move on its own.
## Start by naming what you are actually protecting The cost of an unstructured jump is that a target collects predecessors the text does not enumerate, so a reader cannot say what holds at that point without scanning the routine. Every rule you write should be checkable against that sentence. If a rule permits something that leaves a point with an unknown history, it is too loose; if it forbids something whose history is obvious, it is theatre. This matters because the obvious rule fails the test. A ban on the keyword is trivially enforceable and does not measure the defect, so the refactor it rewards — a failure flag set once and tested by every later step — passes review while spreading one decision across the whole routine. Any standard that would approve that change is scoring the wrong property. ## The rule worth writing 1. **Permit** a jump that is forward only, targets a single label at the routine's top level, never enters a block partway, and whose target is visible without scrolling. In practice this admits the cleanup exit that unwinds partially acquired resources, and very little else. 2. **Refuse** backward jumps and any jump landing inside a block. These are the shapes whose removal changes code rather than rearranging it, so allowing them accumulates work that can only be paid down with a real restructuring slot. 3. **Refuse the substitutes too.** Name explicitly that replacing a jump with a variable whose only readers are the statements that follow the decision is not compliance. Without this clause the standard reliably produces exactly that. 4. **Require the label to be named for its postcondition** — what has been released or established when control arrives — so the predecessor set is documented where a reader will look. ## Enforcement, split by what is mechanical | Rule | Enforced by | Why there | |---|---|---| | No backward jumps | Automated check | Direction is decidable from the text | | No jump into a block | Automated check | Target position is decidable too | | Forward jump within a screen | Automated check with a line budget | Crude, but it fails in the safe direction | | Not a flag standing in for a jump | Review | Requires knowing what reads the variable | | Label named for its postcondition | Review | A naming judgment, not a shape | Automate what is decidable and leave the rest to people, then say so in the standard. A rule you cannot check will be obeyed for a quarter and quietly abandoned, and a rule a machine checks badly is worse than one a human checks well. ## Migration: on touch, behind tests A sweep through every tangled routine is the plan that gets proposed and the one that hurts. These routines are old because they are rarely changed, which means they are also rarely exercised, which means a behaviour change lands far from the commit that caused it. Three commitments keep this survivable: - **Capture behaviour before changing shape.** Record the routine's outputs for representative inputs as tests first, so the rewrite has something to be wrong against. Without them a control-flow rewrite is an unverifiable edit. - **Change shape and behaviour in separate steps.** A commit that both restructures control flow and fixes a defect cannot be bisected or reverted cleanly. - **Rewrite only routines you were already touching.** The ones nobody touches cost nothing to leave; the ones under active change pay the cleanup back immediately. ## How you know it worked Do not measure the count of jumps, because that number goes to zero on the day the flags arrive. Measure things that track the defect: how often a change to one of these routines needs a follow-up fix, how long a reviewer spends on them, whether new work inside the flagged regions inherits its guard automatically. If the jump count fell and the follow-up-fix rate did not, the standard is being satisfied rather than served. ## The judgment this question is really testing Two failures are visible at this level. One is the leader who bans the keyword and declares the problem solved, mistaking an enforceable rule for an effective one. The other is the leader who treats the whole subject as settled history and lets each routine be argued individually, which produces a codebase with no shared vocabulary for why a given jump is or is not acceptable. The useful position is narrower than either: a small set of permitted shapes, machine-checked where the shape is decidable, migrated on touch, and measured by whether the code got easier to change.
- Why not simply schedule a cleanup sweep across all the tangled routines at once?Because these routines are old precisely because they are rarely changed, so they are also rarely exercised and a behaviour change surfaces long after the commit. A sweep concentrates that risk into one window with no offsetting benefit, since routines nobody touches cost nothing to leave alone. On touch, the cleanup is paid for by the change that needed it.
- What metric would tell you the standard is being satisfied rather than served?A falling count of jumps with no improvement in the rate of follow-up fixes to the same routines. That combination is the signature of the flag substitution: the banned shape disappeared, the distributed decision replaced it, and the code is no easier to change than before.
- How do you write the rule so the flag substitution is not compliant?State it as a property of the variable, not an intent: a value whose only readers are the statements immediately following the decision that sets it, and whose removal in favour of one guarded region would be behaviour-preserving, counts as control flow and is held to the same rule. That is checkable in review even though it is not decidable by a tool.
saying these in an interview costs you the question
- Bans the keyword and treats the problem as solved
- Schedules a full rewrite of rarely-changed routines with no tests
- Counts jumps as the measure of whether the standard worked
- Combines a control-flow rewrite and a behaviour fix in one commit
- Leaves every case to individual argument with no shared rule