A defect is closed by rejecting the one input value that produced it. Why does the rest of the defect family stay open?
answer
- One value out, family intact
- Ask what else the change covers
- Would a neighbouring value still fail?
- Fix where the rule belongs, not beside the crash
basics
~20 sRejecting one value removes one occurrence, not the reason that value was dangerous. The weakness stays: the boundary nobody checked, the assumption two components did not share. So a neighbouring value, or the same value by another route, still fails.
solid answer
~40 sA fix aimed at the condition removes this occurrence; a fix aimed at the weakness removes the reason the condition mattered. Rejecting the one value that produced the failure leaves every neighbouring value able to reach the same unguarded code: the one just above the boundary, the same shape arriving by a second route, the identical assumption made about another field. You can tell which layer a change landed at by asking what else it covers. A condition-level fix names the value; a weakness-level fix moves the rule to the boundary every path crosses, or makes the bad state impossible to construct in the first place. Shipping the narrow one is often right when harm is happening now, but say so on the record, or the family silently reads as closed.
code
pseudocode · 7 lines# condition-level: the reported value stops failing
if input == " " then reject
quantity = toNumber(input)
# weakness-level: the rule moves to the boundary every path crosses
quantity = parseQuantity(input) # rejects blank, sign, overflow, width
process(quantity) # can no longer receive an unparsed valuego deeper
Know that making the reported value pass is not the same as fixing the defect. Be ready to say what else you tried after your change: a neighbouring value, or the same input arriving by another route.
Explain the difference between removing one occurrence and removing the reason it was dangerous, and show how you tell which one a change achieved by looking at what else it covers without further edits.
Show the judgement to ship a narrow fix under pressure while being explicit that the family is still open, so the closed record never quietly claims more than the change delivered.
Own how narrow fixes are recorded across the team, so that a closed defect never implies a family is gone. The alternative costs repeat work that nobody ever attributes back to the original defect.
## A fix removes one of two things Every change that closes a defect removes something from the set of things that can go wrong. What it removes is either **one occurrence** (this value, on this path, in this field) or **the reason occurrences of that shape are dangerous at all**. The two look identical on the record, because both end in "fixed and verified", and the verification is the same reproduction that has now stopped failing. Refusing the one input value that produced the failure is the first kind. It is a true fix: the reported reproduction no longer fails and the person who reported it is no longer hurt. It is also complete only for the value you happened to be shown. The code that misbehaved when it received that value is still there, still willing to misbehave, still protected by nothing except a list of values somebody thought of. ## The family a weakness admits A weakness defines a family. If a total is accumulated in a counter narrower than the sums it now receives, the family is every basket large enough to overflow it. If a read path assumes an owner field is always populated, the family is every row that arrived without one: from an old bulk import, from a partial write, from a path that never set it. Members of a family differ in exactly the ways your single occurrence cannot tell you about: - **Neighbouring values.** One above the boundary, one below it, one of the opposite sign. - **Other paths in.** The same code reached by a scheduled job, a bulk import, an automatic retry. - **The same shape in another field.** The identical assumption made about a second attribute nobody looked at. - **The same shape in another component.** Two teams holding the same wrong belief about a shared structure. A fix aimed at the condition covers exactly one member. A fix aimed at the weakness covers all of the first three and points you at the fourth. ## Telling the two apart | Question to ask of the change | Condition-level fix | Weakness-level fix | |---|---|---| | What does it name? | The value, the field, the path from the report | The rule, the boundary, the state that must not exist | | Where does it sit? | Beside the place that failed | Where every path into the code crosses | | Does a neighbouring value still fail? | Usually yes | No, by construction | | What happens when a new path in appears? | The gap reopens silently | Covered without further work | | What is left afterwards? | The family, still open | Nothing for this family | The practical version of that table is one test you can apply in review, before anything merges: **name two more members of the family and check whether the change covers them without another edit.** If you cannot name two, you have not found the weakness yet. If you can name them and the change misses them, you are holding a condition-level fix, which may still be the right thing to ship but is not the right thing to claim. ## The shapes a weakness-level fix takes There are only a few underlying moves, and none of them is heroic: 1. **Move the rule to the boundary.** Check the value where it enters the system rather than where it happened to blow up, so every path in is covered by construction. 2. **Make the invalid state impossible to build.** Convert the value into a structure that cannot hold the bad state, so the code downstream has nothing left to check. 3. **Make the assumption explicit and enforced.** If the code believed a field is always present, either guarantee that where the row is created, or make absence a state every reader is forced to handle. The common case is a small change in a *different place* from where the failure surfaced, and that distance is itself the tell: a fix that lands right beside the crash is usually treating the occurrence. ## When the narrow fix is the right call Often. Users are being hurt now, the deeper change touches an area under active work, or the release is tomorrow. Ship the narrow fix. The mistake is never in taking it; the mistake is taking it and closing the defect as though the family were gone. Six months later the next member arrives as a fresh report with no link to the first, gets its own narrow fix, and the pattern is never seen by anybody. The habit that prevents this costs one sentence on the record: what the change actually covers, what the family still admits, and who owns the deeper change. That sentence is also what lets a later reader recognise three narrow fixes as three sightings of one weakness rather than three unrelated small bugs. ## A note on verification A narrow fix verifies beautifully, which is part of why it is so easy to over-claim: the reported reproduction passes, so the evidence on the record is green. Verifying a weakness-level fix means exercising something you were never shown. If nothing in your confirmation touches a member of the family that was absent from the original report, the evidence is silent on exactly the question the fix was meant to answer.
- Before closing, how do you check that a fix landed at the weakness rather than the condition?Name two more members of the family, such as a neighbouring value and the same shape arriving by another path, and confirm the change covers them with no further edit. If it does not, you have a condition-level fix. Say that on the record and leave the family open, rather than letting the closure imply more than the change delivered.
- When is the narrow fix the right thing to ship anyway?When users are being hurt now and the deeper change is large or risky. Ship the narrow fix to stop the harm, then record explicitly that the family is still open and what the deeper change would be, with an owner. The failure mode is not taking the narrow fix; it is taking it and closing the record as if the family were gone.
Boarding up the one window a thief used does not secure the house; it secures that window.
saying these in an interview costs you the question
- Closes the family because the reported value now passes
- Adds the check beside the crash, not where the rule belongs
- Presents a narrow fix as a permanent one without saying so
- Cannot name a second member of the same defect family
- Believes any change that stops the reproduction is a deep fix