Skip to content
aipatterns.dev

Refactoring techniqueSimplifying Method Calls

Replace Parameter with Explicit Methods

Split a method that branches on a flag or enum argument into one clearly named method per value.

Also known as
Remove Flag Argument

Problem

A method takes a parameter whose only job is to choose which branch runs. Call sites read like setStatus(account, true, false), and the reader must open the method to learn what true means. Each branch has little in common with the others.

Solution

Create a separate method for each value of the parameter, move the matching branch into it, and have callers call the explicit method.

Before

TypeScript
function exportReport(report: Report, format: "csv" | "pdf"): Buffer {
  if (format === "csv") {
    const header = report.columns.join(",");
    const rows = report.rows.map((r) => r.map(csvEscape).join(","));
    return Buffer.from([header, ...rows].join("\n"));
  } else {
    const doc = new PdfDocument({ size: "A4" });
    doc.table(report.columns, report.rows);
    return doc.render();
  }
}

const file = exportReport(monthly, "pdf");

After

TypeScript
function exportCsv(report: Report): Buffer {
  const header = report.columns.join(",");
  const rows = report.rows.map((r) => r.map(csvEscape).join(","));
  return Buffer.from([header, ...rows].join("\n"));
}

function exportPdf(report: Report): Buffer {
  const doc = new PdfDocument({ size: "A4" });
  doc.table(report.columns, report.rows);
  return doc.render();
}

const file = exportPdf(monthly);

Why

  • Each call states what it does without a flag to decode.
  • Each method has one job and only the dependencies that job needs.
  • The type checker catches a missing case at compile time, rather than a runtime else.

Steps

  1. Confirm callers pass the parameter as a literal. If the value comes from data at runtime, stop; you would only move the branch to every caller.
  2. Create one explicit method per value, with the body of its branch. Run the tests.
  3. Make the original method delegate to the explicit methods. Run the tests.
  4. Replace each call that passes a literal with a call to the matching explicit method. Run the tests.
  5. Delete the original method when no callers remain.

Watch out

  • Do not split when the value is decided at runtime (from a user setting, request header or database). Keep the dispatching method, or move the choice to a lookup map. That map is often the boundary where callers need a single entry point.
  • Do not split when the branches share most of their code and differ by a value. That is the case for Parameterize Method, the inverse technique.
  • Many values (ten export formats) make many methods. Consider Replace Conditional with Polymorphism with one exporter object per format.

Agent checklist

  • Most callers pass the parameter as a literal.
  • The branches do different work, not the same work with different values.
  • Any caller with a runtime value still has a single dispatch point.
  • Boolean flag arguments were the first candidates.

Treats these smells

See also

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