tgvashworth

Avoid lots of arguments

18 Oct 2013

If you’re writing a function that takes lots of arguments, it might be a sign that you need to refactor. One way is to use an options object.

Why are lots of arguments bad?

It’s just a heuristic, but I’d say any more than three is too many.

function doAThing(id, someUrl, isAboutSharks, mightInvolvePonies, callback) {
  // ...
};

That’s not great, becuase the call might look like this:

doAThing(shark.id, "/shark/:id/sightings-with-ponies.json", true, shark.getPonyInvolvement(), function (err, result) { ... });

Remove the middle true and all hell breaks loose.

Switching to an arguments object is easy:

function doAThing(id, opts, callback) {
  // Provide some defaults for things not passed
  if (typeof opts.isAboutSharks === "undefined") {
    opts.isAboutSharks = true;
  }
  // (or use a library's defaults method)
  var opts = _.defaults(opts, {
    url: '/sharks.json',
    isAboutSharks: true,
    mightInvolvePonies: false
  };
  // use opts.isAboutSharks or opts.mightInvolvePonies
});

Now the call could look like:

doAThing(shark.id, {
  mightInvolvePonies: shark.getPonyInvolvement()
}, function (err, result) { ... });

Clean, clear and easy to read. Yum.

This API would be even better with Promises, as it would avoid the last argument:

doAThing(shark.id, {
  mightInvolvePonies: shark.getPonyInvolvement()
}).then(function () { ... });

Very nice.