While assisting my computer science students on ways to help debug and improve the clarity and runtime of their code, I explained the concept of guard clauses. Guard clauses are true/false expressions (predicates) found at the top of a method or function that determine whether the function should continue to run. Guard clauses test for preconditions and either immediately return from the method or throw an exception, preventing the remaining body of code from executing.
From a defensive programming perspective, a common function of guard clauses is to validate arguments to avoid errors and unintended results that could occur during execution. A common example is to check if an argument is null
and throw an ArgumentNullException
. However, one may be performing other forms of validation on arguments such as if dates fall within a certain date range, integer values are positive, strings are a certain length, etc. Any assumptions about the arguments or state of the object that are being made by the remaining block of code are typically made explicit by the guard clauses.
void Save(Custom customer)
{
// Guard clause - validation
if (customer == null)
throw new ArgumentNullException(nameof(customer));
// rest of the code...
}
Aside from validation, guard clauses can also short circuit a function or method by handling trivial or special cases. For example, if the purpose of a function is to sort a list of strings and there are less than two strings, the list is already sorted. If you are calculating the product of a list of integers and one of the integers is zero, the product is zero. If you need to determine if a certain number of knights can safely be added to an N x M chessboard, it is false if the number of knights to be added is greater than half the number of squares on the chessboard (excluding edge cases).
List<int> Sort(List<int> ages)
{
// Guard clause - validation
if (ages == null)
throw new ArgumentNullException(nameof(ages));
// Guard clause - trivial case
if (ages.Count < 2)
return ages;
// rest of code...
}
Guard clauses are often paired with unit tests to make sure they are operating as expected. For example, using C# and xUnit, one might test to make sure the guard clause mentioned above is throwing an ArgumentNullException
when the argument is indeed null
.
[Fact]
public void Sort_WhenAgesIsNull_ShouldThrowArgumentNullException()
{
Assert.Throws<ArgumentNullException>(() => Utils.Sort(null));
}
Finally, guard clauses used for validation are so common that there are libraries dedicated to validation and most frameworks include validation helpers by default. This is true of most cross-cutting concerns, like validation, logging, caching, etc. Rather than roll your own helper methods for validation, you may want to include a validation library in your project. Regardless of whether you roll your own guard clauses or use a library, the need for guard clauses remains the same.