I've heard that it is recommended to validate arguments of public methods:
- Should one check for null if he does not expect null?
- Should a method validate its parameters?
- MSDN - CA1062: Validate arguments of public methods (I have .NET background but question is not C# specific)
Motivation is understandable. If a module will be used in a wrong way, we want to throw exception immediately instead of any unpredictable behavior.
What bothers me, is that wrong arguments is not the only error which can be made while using a module. Here's some error scenarios where we need to add checking logic if we follow recommendations and don't want error escalation:
- Incoming call - unexpected arguments
- Incoming call - module is in a wrong state
- External call - unexpected results returned
- External call - unexpected side-effects (double-entry to a calling module, breaking other dependencies states)
I've tried to take into account all these conditions and write a simple module with one method (sorry, not-C# guys):
public sealed class Room
{
private readonly IDoorFactory _doorFactory;
private bool _entered;
private IDoor _door;
public Room(IDoorFactory doorFactory)
{
if (doorFactory == null)
throw new ArgumentNullException("doorFactory");
_doorFactory = doorFactory;
}
public void Open()
{
if (_door != null)
throw new InvalidOperationException("Room is already opened");
if (_entered)
throw new InvalidOperationException("Double entry is not allowed");
_entered = true;
_door = _doorFactory.Create();
if (_door == null)
throw new IncompatibleDependencyException("doorFactory");
_door.Open();
_entered = false;
}
}
Now It's safe =)
It's quite creepy. But imagine how creepy it can be in a real module with dozens of methods, complex state and a lot of external calls (hi, dependency injection lovers!). Note that if you're calling a module which behavior can be overridden (non-sealed class in C#) then you're making an external call and consequences are not predictable at the scope of the caller.
Summing up, what is the right way and why? If you can choose from options below, answer additional questions, please.
Check entire module usage. Do we need unit tests? Is there examples of such code? Should dependency injection be limited in usage (since it will cause more checking logic)? Isn't it practical to move those checks to debug-time (do not include in release)?
Check only arguments. From my experience, argument checking - especially null checking - is the least effective check, because argument error rarely lead to complex mistakes and error escalations. Most of the time you'll get a NullReferenceException
at the next line. So why argument checks are so special?
Don't check module usage. It's quite unpopular opinion, can you explain why?