Techniques for minimising number of function arguments

  softwareengineering

In Clean Code, it is written that “the ideal number of arguments for a function is zero”. The reasons why are explained and make sense. What I’m after is techniques to refactor methods with 4 or more arguments to solve this issue.

One way is to extract the arguments into a new class, but that would surely lead to an explosion of classes? And those classes are likely to end up with names that violate some of the naming rules (ending with “Data” or “Info” etc)?

Another technique is to make variables used by multiple functions a private member variable to avoid passing them, but that expands the scope of the variable, possibly such that it’s open to functions that don’t actually need it.

Just looking for ways to minimise function arguments, having accepted the reasons why it’s a good idea to do so.

19

The most important thing to remember is that those are guidelines, not rules.

There are cases where a method simply must take an argument. Think about the + method for numbers, for example. Or the add method for a collection.

In fact, one might even argue that what it means to add two numbers is dependent on context, e.g. in ℤ 3 + 3 == 6, but in ℤ|5 3 + 3 == 2, so really the addition operator should be a method on a context object that takes two arguments instead of a method on numbers that takes one argument.

Likewise, a method for comparing two objects must either be a method of one object taking the other as an argument, or a method of the context, taking two objects as arguments, so it simply doesn’t make sense to have a comparison method with less than one argument.

That said, there are a couple of things that can be done to reduce the number of arguments for a method:

  • Make the method itself smaller: Maybe, if the method needs that many arguments, it is doing too much?
  • A missing abstraction: If the arguments are closely correlated, maybe they belong together, and there is an abstraction you are missing? (Canonical text book example: instead of two coordinates, pass a Point object, or instead of passing username and email, pass an IdCard object.)
  • Object state: If the argument is needed by multiple methods, maybe it should be part of the object state. If it is needed by only some of the methods but not others, maybe the object is doing too much and should really be two objects.

One way is to extract the arguments into a new class, but that would surely lead to an explosion of classes?

If your domain model has many different kinds of things, then your code will end up with many different kinds of objects. There’s nothing wrong with that.

And those classes are likely to end up with names that violate some of the naming rules (ending with “Data” or “Info” etc)?

If you cannot find a proper name, maybe you either grouped too many arguments together or too few. So, you either have just a fragment of a class or you have more than one class.

Another technique is to make variables used by multiple functions a private member variable to avoid passing them, but that expands the scope of the variable, possibly such that it’s open to functions that don’t actually need it.

If you have a group of methods all of which operate on the same arguments, and another group of methods that don’t, maybe they belong in different classes.

Note how often I used the word “maybe”? That’s why those are guidelines, not rules. Maybe your method with 4 parameters is perfectly fine!

3

Note that zero arguments doesn’t imply side effects, because your object is an implicit argument. Look how many zero-arity methods Scala’s immutable list has, for example.

One useful technique I call the “lens focusing” technique. When you focus a camera lens, it’s easier to see the true focus point if you take it too far, then back it off to the correct point. The same is true of software refactoring.

Especially if you are using distributed version control, software changes are easy to experiment with, see if you like how they look, and back off if you don’t, but for some reason people often seem reluctant to do so.

In the context of your current question, that means writing the zero or one argument versions, with several split off functions first, then it’s relatively easy to see which functions need combining for readability.

Note that the author is also a huge advocate of test driven development, which tends to produce low-arity functions at the beginning because you start with your trivial test cases.

1

An approach that simply (and naively – or should I even say blindly) just aims to reduce the number of arguments to functions ist probably wrong. There’s absolutely nothing wrong with functions having a large number of arguments. If they are required by the logic, well they are required… A long parameter list doesn’t worry me at all – as long as it is properly formatted and commented for readability.

In the case that all or a subset of arguments belong to one unique logical entity and are commonly passed around in groups throughout your program, it maybe makes sense to group them into some container – Typically a struct or other object. Typical examples might be some sort of message or event data type.

You can easily overdo that approach – once you find that packing and unpacking stuff to and from such transport containers generates more overhead than it improves readability, you’ve probably gone too far.

OTOH, large parameter lists can be a sign that your program may be not properly structured – maybe the function that requires such a large number of parameters is just trying to do too much and should be split into several smaller functions. I’d rather start here than worrying about # of parameters.

5

There is no magic way: you must master the problem domain to discover the right architecture. That’s the only way to refactor: mastering the problem domain. More than four parameters is just a sure bet that your current architecture is faulty and wrong.

The only exceptions are compilers (metaprograms) and simulations, where the limit is theoretically 8, but probably only 5.

LEAVE A COMMENT