Doing some research, it seems that people generally agree that arguments to public methods should be validated while private functions typically do not. This causes me to have some questions, but I have not been able to find a satisfactory answer so far.
Example:
public void DoSomething(int i)
{
if (i < 0)
throw new ArgumentOutOfRangeException("i");
double d = DoWork(i);
}
private double DoWork(int i)
{
double ret = ...; // some calculation
return ret;
}
Thoughts:
What if the requirement of
i
to be non-negative changes insideDoWork()
? The design risks leaving outdated validation checks in place. The programmer is responsible for adjusting the usage of a function that has changed, I know, but it leaves me wondering if there is a better way to minimize risk of error.What about different calls to
DoWork()
not fromDoSomething()
? Must we validate the arguments redundantly?
public void DoSomething(int i)
{
if (i < 0)
throw new ArgumentOutOfRangeException("i");
double d = DoWork(i);
}
public void DoSomethingElse()
{
int i = 5;
if (i < 0)
throw new ArgumentOutOfRangeException("i");
double d = DoWork(i);
}
private double DoWork(int i)
{
double ret = ...; // some calculation
return ret;
}
This can be cleaned up a little by putting the check into a function of its own. Then there is the risk that a new function making a call to DoWork(int i)
will forget to validate i
.
public void DoSomething(int i)
{
ThrowIfIntegerIsNegative(i);
double d = DoWork(i);
}
public void DoSomethingElse()
{
int i = 5;
ThrowIfIntegerIsNegative(i);
double d = DoWork(i);
}
static void ThrowIfIntegerIsNegative(int i)
{
if (i < 0)
throw new ArgumentOutOfRangeException("i");
}
private double DoWork(int i)
{
double ret = ...; // some calculation
return ret;
}
Is that at all better than this?
public void DoSomething(int i)
{
double d = DoWork(i);
}
public void DoSomethingElse()
{
double d = DoWork(5);
}
private double DoWork(int i)
{
if (i < 0)
throw new ArgumentOutOfRangeException("i");
double ret = ...; // some calculation
return ret;
}
Depending on the situation, these are some goals I am trying to achieve simultaneously:
- Have the argument validation in a single place (and possibly inside the function using the argument)
- Report an error sooner rather than later (might not want to have a bunch of code run for an hour just to fail at the end for some bad user input)
- Avoid validating arguments multiple times
- Avoid performance impact in release code
How do you strike a balance? What methodology has worked best for you? I would greatly appreciate any insight.