Skip to content
aipatterns.dev

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

TypeScript
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

TypeScript
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

  1. Find every assignment to the flag. Confirm what each one means: stop the loop, skip the rest of this iteration, or stop the function.
  2. At the assignment that ends the work, add the matching break, continue or return right after it. Keep the flag for now. Run the tests.
  3. If the flag also held a result, change that exit to return result directly. Run the tests.
  4. Remove the flag from the loop condition, then delete its declaration and remaining assignments. Run the tests.
  5. 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 return is available.

Watch out

  • A break inside a nested loop only exits the inner loop. Extract the loops into a function and return, or use a labeled break if 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 isCancelled on a job. That is data, not control flow.
  • There is no inverse technique.

Agent checklist

  • Every flag assignment has been mapped to break, continue or return.
  • 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

Original writing and examples. Topic coverage follows Refactoring.Guru, which explains this topic with its own illustrations.