Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Possibly incorrect: "Zero arguments is the ideal case" #176

Open
andreobriennz opened this issue May 19, 2020 · 4 comments
Open

Possibly incorrect: "Zero arguments is the ideal case" #176

andreobriennz opened this issue May 19, 2020 · 4 comments

Comments

@andreobriennz
Copy link

In the section "Function arguments (2 or fewer ideally)" it says:
"Zero arguments is the ideal case. One or two arguments is ok, and three should be avoided."
However, I think it's typically best to have at least 1 argument, as most functions with zero arguments aren't pure functions and aren't easily testable

Personally I prefer the wording in Clean Code JavaScript:
"One or two arguments is the ideal case, and three should be avoided if possible" (https://github.com/ryanmcdermott/clean-code-javascript#function-arguments-2-or-fewer-ideally)

@peter-gribanov
Copy link
Contributor

I recommend you read the original book.

Clean Code - Chapter 3: Functions - Function Arguments

The ideal number of arguments for a function is zero (niladic). Next comes one (monadic), followed closely by two (dyadic). Three arguments (triadic) should be avoided where possible. More than three (polyadic) requires very special justification — and then shouldn’t be used anyway.

Arguments are even harder from a testing point of view. Imagine the difficulty of writing all the test cases to ensure that all the various combinations of arguments work properly. If there are no arguments, this is trivial. If there’s one argument, it’s not too hard. With two arguments the problem gets a bit more challenging. With more than two arguments, testing every combination of appropriate values can be daunting.

@andreobriennz
Copy link
Author

andreobriennz commented May 20, 2020

About the testing, normally having different cases are to meet a business requirement and so the different cases will have to exist somewhere in the code. So I would think testing would usually be easier with a parameter as you can test if it returns the expected result when you pass a different parameter to it, for example,

function isOver18(age) {
  return age >= 18;
}

It can be tested by calling the function as isOver18(21) and expecting it to be true. Most tests that I've seen personally work this way. Not sure how this would work without any arguments unless you're just testing a currently logged in user?

It's also surprising to me as in functional programming these would often usually be considered impure functions that should be avoided. But since this is about the original book, feel free to close this issue

@peter-gribanov
Copy link
Contributor

peter-gribanov commented May 20, 2020

It is worth explaining that there are different cases. And i suspect that what interests you in the isOver18() function is not age, but whether the user is adult. If age is one of the user properties, then it’s more correct to encapsulate the user age and check whether he is an adult in the user object as well.

class User {
  // ...

  isAdult() {
    return this.age > 18;
  } 
}

If we are talking about checking the input data, then it is more correct to make a validator and check the input data in the function argument.

class AdultValidator extends Validator {
  validate(age) {
    return age > 18;
  }
}

Both options are easy to test. Getters and setters are also easy to test.

The author of the book said that increasing the number of arguments complicates reading the code and testing if the logic of the function is tied to the arguments.

For example, in this example, the second argument adds logic branching and you need to write 2 tests in order to check all possible return values. This is the complication Robert Martin was talking about.

public function getVideoFrame(string $filename, string $filter = ''): string
{
    $path = $this->frame_locator->locate($filename);

    if ($filter) {
        $path = $this->resolver->getBrowserPath($path, $filter);
    }

    return $path;
}

An increase in the number of arguments can increase the branching of logic in a function and increase exponentially the number of tests needed to cover all cases. This is not always the case, but it is better to adhere to the rule - the fewer the arguments, the better.

@andreobriennz
Copy link
Author

Thaks for explanation and examples. I see what you mean in this case; the age is essentially a property so assuming someone is following OOP it could be the best option

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants