February 9, 2023

Introduce Parameter Object

Long, messy function parameter list often makes your code harder to read and use. One way to clean them up is to look for the parameters that have some relationship, and then group them together to introduce a parameter object.

Look at this example:

function searchEvents(categoryIds, fromDate, toDate, isPremium) {
  // return events matching the above criteria
}

Sometimes it’s harder to find parameters with relationship between them, but for this example I can immediately say fromDate and toDate.

A quick tip for finding parameters with a relationship is to ask yourself if removing one parameter would make the other ones make sense. If they only work together, then they have a relationship between them. For this example, it doesn’t make sense to pass fromDate without toDate; so, they can be combined into an object.

How to combine them

You can simply pass them as an object, like this:

const dateRange = { from: fromDate, to: toDate }
searchEvents(categoryIds, dateRange, isPremium)

But, a better way is to combine them with a class—you will know why later.

class DateRange {
  #data

  constructor(from, to) {
    this.#data = { from: from, to: to }
  }

  get from() {
    return this.#data.from
  }

  get to() {
    return this.#data.to
  }
}

Using them will look like this:

const dateRange = new DateRange(fromDate, toDate)
searchEvents(categoryIds, dateRange, isPremium)

The real power of parameter objects

Parameter objects are not only for grouping parameters that have relationship. They are also great at combining the functions that operate on those parameters.

Having DateRange as a class gives us the opportunity to add a function like contains that will return whether a certain date is between the date range.

class DateRange {
  #data

  constructor(from, to) {
    this.#data = { from: from, to: to }
  }

  get from() {
    return this.#data.from
  }

  get to() {
    return this.#data.to
  }

  contains(date) {
    return date.getTime() >= this.#data.from && date.getTime() <= this.#date.to
  }
}

With this change, you can use dateRange.contains(certainDate) instead of writing this logic inside searchEvents function—or any other place using it; thus reducing duplication.

Adding contains is just an example; I can think of many more things I can add to this class in the future like format for displaying the date range in a specific format, or startsOnWeekend to check if the date range starts on a weekend.

Knowing where to add or change some code is an indication that your code is designed well, which is what we all want to achieve. Not only that, but creating such objects makes it possible and easier to test certain behavior—now it’s easy to test date ranges, which the concept of them didn’t exist before.

Stay up-to-date on the latest projects and articles from me