Consolidate Conditional Expression
Intent
Section titled “Intent”Take a run of separate conditionals that each guard the same outcome and fold them into one combined condition, then extract that condition into a named function. Three scattered checks with the same return 0 become a single if (isNotEligible(employee)) return 0, and the reason for the result is captured in the name.
The smell
Section titled “The smell”This is the cure for a sequence of conditionals with identical results. Each check on its own looks innocent, but together they hide a single idea behind three lines of plumbing. The reader has to notice that all three produce the same value before understanding that they are really one question — is this person ineligible? Consolidating makes that one question explicit, and a named helper tells the next reader why without making them reverse-engineer it.
Before → After
Section titled “Before → After”A disability-benefit amount returns zero for several disqualifying conditions. Before, each disqualifier is its own if. After, they are one named check.
// Beforefunction disabilityAmount(employee: Employee): number { if (employee.seniority < 2) return 0; if (employee.monthsDisabled > 12) return 0; if (employee.isPartTime) return 0; // ... compute the real amount return baseAmount(employee);}
// Afterfunction disabilityAmount(employee: Employee): number { if (isNotEligible(employee)) return 0; // ... compute the real amount return baseAmount(employee);}
function isNotEligible(employee: Employee): boolean { return ( employee.seniority < 2 || employee.monthsDisabled > 12 || employee.isPartTime );}# Beforedef disability_amount(employee): if employee.seniority < 2: return 0 if employee.months_disabled > 12: return 0 if employee.is_part_time: return 0 # ... compute the real amount return base_amount(employee)
# Afterdef disability_amount(employee): if is_not_eligible(employee): return 0 # ... compute the real amount return base_amount(employee)
def is_not_eligible(employee): return ( employee.seniority < 2 or employee.months_disabled > 12 or employee.is_part_time )// Beforefunc DisabilityAmount(employee Employee) int { if employee.Seniority < 2 { return 0 } if employee.MonthsDisabled > 12 { return 0 } if employee.IsPartTime { return 0 } // ... compute the real amount return baseAmount(employee)}
// Afterfunc DisabilityAmount(employee Employee) int { if isNotEligible(employee) { return 0 } // ... compute the real amount return baseAmount(employee)}
func isNotEligible(employee Employee) bool { return employee.Seniority < 2 || employee.MonthsDisabled > 12 || employee.IsPartTime}// Beforefn disability_amount(employee: &Employee) -> i64 { if employee.seniority < 2 { return 0; } if employee.months_disabled > 12 { return 0; } if employee.is_part_time { return 0; } // ... compute the real amount base_amount(employee)}
// Afterfn disability_amount(employee: &Employee) -> i64 { if is_not_eligible(employee) { return 0; } // ... compute the real amount base_amount(employee)}
fn is_not_eligible(employee: &Employee) -> bool { employee.seniority < 2 || employee.months_disabled > 12 || employee.is_part_time}flowchart LR
subgraph Before["Before"]
A["if seniority < 2 return 0<br/>if monthsDisabled > 12 return 0<br/>if isPartTime return 0"]
end
subgraph After["After"]
B["if isNotEligible(emp)<br/>return 0"]
end
Before -.->|"Consolidate Conditional Expression"| After Mechanics
Section titled “Mechanics”- Confirm that the conditionals truly share a result and have no side effects between them. If one check mutates state the next relies on, do not merge.
- Combine the tests with
||when they all lead to the same branch (or&&when the structure is nested checks that must all pass). Keep the combined condition next to the shared result. - Run your tests. The behaviour must match the chain of separate
ifs exactly, including short-circuit order. - Apply Extract Function to the combined condition, naming it after the question it answers (
isNotEligible). - Run your tests again.
When to use / trade-offs
Section titled “When to use / trade-offs”Reach for Consolidate Conditional Expression whenever you see consecutive checks that funnel into the same outcome. It is most valuable as a setup move: once the checks are one named function, you can reuse that function, and it often clears the way for Replace Nested Conditional with Guard Clauses.
Do not consolidate when the checks are genuinely independent decisions that happen to share a value today but may diverge tomorrow — merging them would couple unrelated rules. And never merge across a side effect; the combined expression’s short-circuiting could skip work the original chain performed.