Posted on

A flag argument is a boolean which causes the method to behave differently. It’s an indicator that the code is exercising multiple scenarios based on an external factor. A piece of code on a higher level decides with path to take through a lower level method.

Consider this brief example:

def create_task(description, priority, preview: true, email: true)
  task = Task.new
  task.status = "open"
  task.description = description
  task.priority = priority

  unless preview
    task.save!
    index_in_search_engine(task)
    send_task_created_email_notification(task) if email
  end

  task
end

preview and email are the flag arguments in this method. It’s called in various ways depending on what is required. The flag arguments also cause the method calls to be somewhat confusing:

# Create a task and send an email notification
create_task("Read the newspaper", "low", preview: false)

# Create a task but don't send a notification
create_task("Read the newspaper", "low", preview: false, email: false)

# Build a task for preview purposes
create_task("Read the newspaper", "low", preview: true)

The logic for different scenarios is tangled together in the create_task method. The method is a little hard to read as a result. If you want to understand one scenario, you have to filter out the others. This requires unnecessary attention and thinking. With multiple flag arguments the complexity gets out of hand very quickly.

Methods are usually not born this way. A small change to the logic may have been required at some point, and adding the flag argument was the fastest way to get there.

To fix the code smell, the method can be split up into multiple, smaller methods:

def create_task_and_send_notification(description, priority)
  create_task(description, priority).tap do |task|
    send_task_created_email_notification(task)
  end
end

def create_task(description, priority)
  build_task(description, priority).tap do |task|
    task.save!
    index_in_search_engine(task)
  end
end

def build_task(description, priority)
  Task.new.tap do |task|
    task.status = "open"
    task.description = description
    task.priority = priority
  end
end

Each of these methods is executing a different scenario. It hardly requires any effort to understand them. The calling code can now decide which scenario is exercised by calling a different method rather than supplying a flag argument:

# Create a task and send an email notification
create_task_and_send_notification("Read the newspaper", "low")

# Create a task but don't send a notification
create_task("Read the newspaper", "low")

# Build a task for preview purposes
build_task("Read the newspaper", "low")

If you like this post, follow me:


Or share this post: