Refactoring techniqueSimplifying Conditional Expressions
Remove Control Flag
Replace a boolean variable that steers a loop or function with break, continue or return so control flow is explicit.
- Also known as
- Replace Control Flag with Break
Problem
A loop or function uses a boolean such as found, done or keepGoing to decide whether to continue. The flag is set in one place and tested in another, so you have to trace every assignment to know when the code actually stops.
Solution
Delete the flag and exit at the point where it would have been set, using break, continue or return. If the flag also carried a result, return that result directly.
Before
function firstConflict(slot: TimeSlot, bookings: Booking[]): Booking | null {
let conflict: Booking | null = null;
let searching = true;
for (let i = 0; i < bookings.length && searching; i++) {
const b = bookings[i];
if (b.status === "cancelled") {
continue;
}
if (b.start < slot.end && slot.start < b.end) {
conflict = b;
searching = false;
}
}
return conflict;
}After
function firstConflict(slot: TimeSlot, bookings: Booking[]): Booking | null {
for (const b of bookings) {
if (b.status === "cancelled") continue;
if (b.start < slot.end && slot.start < b.end) return b;
}
return null;
}Why
- The exit point is where the decision is made, so a reader sees it at once.
- The loop header goes back to a plain iteration with no hidden second condition.
- Fewer mutable variables means fewer states to reason about and test.
Steps
- Find every assignment to the flag. Confirm what each one means: stop the loop, skip the rest of this iteration, or stop the function.
- At the assignment that ends the work, add the matching
break,continueorreturnright after it. Keep the flag for now. Run the tests. - If the flag also held a result, change that exit to
return resultdirectly. Run the tests. - Remove the flag from the loop condition, then delete its declaration and remaining assignments. Run the tests.
- If code after the loop only ran when the flag was set, move it to the exit point or extract the loop into a function so
returnis available.
Watch out
- A
breakinside a nested loop only exits the inner loop. Extract the loops into a function andreturn, or use a labeledbreakif your team accepts labels. - If the code after the flag assignment did meaningful work in the same iteration (logging, counting), an early exit skips it. Move that work above the exit.
- In languages or style guides that require a single exit point, extract the search into its own small function so early returns stay local.
- Do not remove a flag that is part of an object's real state, such as
isCancelledon a job. That is data, not control flow. - There is no inverse technique.
Related
- Shortens Long Method.
- Usually followed by Replace Nested Conditional with Guard Clauses.
- Use Extract Method first when the loop sits in the middle of a larger function.
Agent checklist
- Every flag assignment has been mapped to
break,continueorreturn. - Work that ran after the flag assignment in the same iteration still runs.
- Nested-loop exits leave the correct loop.
- The flag variable no longer exists, and tests pass.
Treats these smells
See also
- Replace Nested Conditional with Guard ClausesHandle special and invalid cases first with early returns so the normal path runs flat at the end of the function.
- Extract MethodMove a coherent fragment of a long function into its own well-named function and call it from the original place.
- Decompose ConditionalMove a complex condition and each of its branches into well-named functions so the decision reads as intent instead of arithmetic.
Original writing and examples. Topic coverage follows Refactoring.Guru, which explains this topic with its own illustrations.