RSPEC-107: Long Parameter List

Welcome to the series "Clean Code"; brought to you by "Coding Mantis"!

As three is the number of minutes it usually takes to read one of my posts, so is the amount of parameters a method should accept. The general rule suggests it could go up to four but I believe it's one too many.

Why is it a bad practice?

A long parameter list makes our code more complex than it should be to use and read, and although in some cases it seems that it would increase reusability and decrease the coupling between methods, as the flow can be altered depending on the values that are passed to it, it actually does the opposite.

// Bad practice example
public void doSomething(int a, int b, int c, String d, long e) {
    // ...
}

It's worth noting that the "RSPEC-107" code smell does not only affect the signature of a method but also its body. This is the case where we're extracting all steps into variables which are then passed as parameters into the method that will perform the logic.

// Snippet by Refactoring Guru
// Bad practice example
public void doSomething(int quantity, int itemPrice) {
    int basePrice = quantity * itemPrice;
    double seasonDiscount = getSeasonalDiscount();
    double fees = getFees();
    double finalPrice = getDiscountedPrice(basePrice, seasonDiscount, fees);
    // ...
}

These "symptoms" in our code could suggest violations of the SOLID Principles, bad design whether it originates from unclear requirements, lack of experience, or even laziness from its author.

How do we fix it?

As in most cases, it also applies to this that prevention is better than cure; meaning that it's much easier to stop it from happening in the first place by following a few guidelines than to refactor/repair it later after the damage has happened. Based on the examples provided above, let's see what we can do to make our code compliant and treat the smell.

In the first case, we have two ways depending on the context:

  • If the values of the parameters originate from another object, we could preserve and pass the object holding them directly and let the method take what it needs to function.
  • If the values passed as arguments originate from calculations or different objects, we could combine them under a new object and pass it as a single parameter, commonly known as a "Value Object (VO)".
public void doSomething(MyClass myClass) {
    int a = myClass.getA();
    int b = myClass.getB();
    // etc, ...
}

In the second case, we can address the issue by replacing the variables with method calls, effectively reducing the steps leading up to the method invocation and letting the method call what it needs to function within its responsibilities.

// Snippet by Refactoring Guru
public void doSomething(int quantity, int itemPrice) {
    int basePrice = quantity * itemPrice;
    double finalPrice = getDiscountedPrice(basePrice);
    // ...
}

public double getDiscountedPrice(int basePrice) {
    return basePrice * getSeasonalDiscount() + getFees();
}

Conclusion

By preventing or treating the Long Parameter List code smell, we end up with shorter, more readable and more meaningful code that allows us to detect previously unnoticed duplicated code. As with all things, this is also not a panacea to be blindly followed and must be used with caution so as not to introduce unwanted/unneeded dependencies between classes.

What do you think about the subject?