DEV Community

Cover image for Refactoring 034 - Reify Parameters
Maxi Contieri
Maxi Contieri

Posted on

Refactoring 034 - Reify Parameters

Transform scattered inputs into one clear object

TL;DR: Wrap messy parameters into a single meaningful entity.

Problems Addressed ๐Ÿ˜”

Related Code Smells ๐Ÿ’จ

Steps ๐Ÿ‘ฃ

  1. Identify multiple parameters of the same type
  2. Create a meaningful entity to group them
  3. Add missing validation rules to fail fast
  4. Replace function signatures with the new entity
  5. Adjust all callers to pass the entity
  6. Add context-specific names to improve clarity

Sample Code ๐Ÿ’ป

Before ๐Ÿšจ

function findHolidays(
 maxPrice: Currency, 
 startDate: Date,
 endDate: Date, 
 minPrice: Currency) {
  // Notice that maxPrice and minPrice are swapped by mistake
  // Also, dates are mixed
}
Enter fullscreen mode Exit fullscreen mode

After ๐Ÿ‘‰

// 2. Create a meaningful entity to group them  

class PriceRange {
  constructor(public min: Currency, public max: Currency) {
    if (min > max) {
      throw new Error(
        `Invalid price range: min (${min}) `+
        `cannot be greater than max (${max})`
      );
    }
    if (min < 0) {
      throw new Error(
        `Invalid price range: min (${min}) cannot be negative`);
    }
  }
}

class Interval {
  // 3. Add missing validation rules to fail-fast
  constructor(public start: Date, public end: Date) {
    if (start > end) {
      throw new Error(
        `Invalid date range: start (${start.toISOString()})  ` + 
        `cannot be after end (${end.toISOString()})`
      );
    }
  }
}

class HolidaySearchCriteria {
  constructor(
    public priceRange: PriceRange,
    public dateRange: Interval
  ) {}
}

function findHolidays(criteria: HolidaySearchCriteria): Holiday[] {
  // 1. Identify multiple parameters of the same type  
  // No need to call validate() - already validated in constructors
  // 4. Replace function signatures with the new entity  
  const { priceRange, dateRange } = criteria;
  // 5. Adjust all callers to pass the entity  
  // 6. Add context-specific names to improve clarity 

  return database.query({
    price: { $gte: priceRange.min, $lte: priceRange.max },
    startDate: { $gte: dateRange.start },
    endDate: { $lte: dateRange.end }
  });
}

try {
  const criteria = new HolidaySearchCriteria(
    new PriceRange(500, 1000),  // โœ… Valid
    new Inteval(
      new Date('2025-06-01'), 
      new Date('2025-06-15')
    )
  );

  findHolidays(criteria);

  // โŒ This will throw immediately
  // Great for UI and API validation
  new PriceRange(1000, 500);

} catch (error) {
  console.error(error.message);
}
Enter fullscreen mode Exit fullscreen mode

Type ๐Ÿ“

[X] Semi-Automatic

Safety ๐Ÿ›ก๏ธ

Many IDEs support this pattern.

Why is the Code Better? โœจ

You avoid order confusion and increase readability.

You make functions easy to extend with new parameters.

You bring semantic meaning to the input data.

You eliminate the risk of passing arguments in the wrong order since the object properties have explicit names.

You make function calls self-documenting because each value clearly indicates its purpose.

You simplify adding new optional parameters without breaking existing code.

You enable better IDE support with autocomplete showing parameter names.

You create opportunities to reuse the parameter object type across related functions.

You fail fast, asserting on the relations among parameters.

How Does it Improve the Bijection? ๐Ÿ—บ๏ธ

You move closer to a one-to-one map between the business concept of a "search request" and your code model.

You stop treating the data as loose numbers and give them an explicit identity that matches the domain.

In the real world, you describe searches using named criteria rather than ordered lists.

When you ask someone to "search for products with a minimum price of 50 and a maximum price of 100," you use named concepts.

This refactoring mirrors that natural language structure in your code.

The SearchCriteria becomes a first-class concept that maps directly to how searching works in the real world.

Refactor with AI ๐Ÿค–

Ask AI to scan your codebase for functions that use two or more parameters of the same type.

Instruct it to propose an entity name, generate the type or class, and rewrite both the function and its callers to use the new entity.

Suggested Prompt: 1. Identify multiple parameters of the same type 2. Create a meaningful entity to group them 3. Add missing validation rules to fail fast 4. Replace function signatures with the new entity 5. Adjust all callers to pass the entity 6. Add context-specific names to improve clarity

Tags ๐Ÿท๏ธ

  • Primitive Obsession

Level ๐Ÿ”‹

[X] Intermediate

Related Refactorings ๐Ÿ”„

Introduce Parameter Object

Also known as

Introduce Parameter Object

Credits ๐Ÿ™

Image by Gerd Altmann on Pixabay


This article is part of the Refactoring Series.

Top comments (0)