Defensive Programming: Using Guard Clauses

Defensive programming is a technique used to make software more reliable, robust, and less prone to errors. It involves anticipating and guarding against potential issues that could occur during runtime, such as unexpected input, invalid user behavior, or hardware failures. By incorporating defensive programming practices into software development, programmers can ensure that their code is more resilient and can handle unexpected situations gracefully.

The Guard Shield – Image courtesy of Midjourney BOT

One common technique used in defensive programming is guard clauses. Guard clauses are statements used at the beginning of a function or method to check for any preconditions that need to be met before the function can execute. This technique helps to prevent errors from occurring by catching any invalid inputs or conditions early on in the code execution process.

By using guard clauses, developers can improve the reliability of their code and reduce the likelihood of errors and bugs. Additionally, guard clauses can make code easier to read and maintain by clearly defining the assumptions and preconditions for a given function or method. Overall, incorporating defensive programming techniques like guard clauses into software development can result in more robust and reliable software.

Here are a few examples of how to use two different GuardAgainst methods from the GuardClauses package and the FluentGuard package in C# .NET, a couple of scripting examples, and finally a Swift 5 example using the Guard function:

C# .NET

GuardClauses

In this example, the Guard.Against.NullOrEmpty method from the GuardClauses package is used to guard against null or empty string values for the value parameter. If the value is null or empty, an ArgumentNullException or an ArgumentException is thrown with a message indicating the name of the parameter. The Guard.Against.OutOfRange method is also used to guard against the length of the value parameter being outside of the range of 1 to 10 characters.

using GuardClauses;

public class MyClass
{
    public void DoSomething(string value)
    {
        Guard.Against.NullOrEmpty(value, nameof(value));
        Guard.Against.OutOfRange(value.Length, nameof(value.Length), 1, 10);

        // rest of the method logic
    }
}

FluentGuard

In this example, the NotNull and NotEmpty extension methods from the FluentGuard package are used to guard against null and empty string values for the value parameter. If the value is null or empty, an ArgumentNullException or an ArgumentException is thrown with a message indicating the name of the parameter.

using FluentGuard;

public class MyClass
{
    public void DoSomething(string value)
    {
        value.NotNull(nameof(value));
        value.NotEmpty(nameof(value));

        // rest of the method logic
    }
}

Script

JavaScript

In this example, a guard clause is used to check if the value parameter is null, undefined, or not a string. If any of these conditions are met, an error message is logged to the console and the function returns early, preventing the rest of the function logic from executing.

function doSomething(value) {
  if (!value || typeof value !== 'string') {
    console.log('Error: value is null, undefined, or not a string');
    return;
  }

  // rest of the function logic
}

jQuery

In this example, a guard clause is used to check if the button element ($button) exists. If it does not exist, an error message is logged to the console and the function returns early, preventing the rest of the function logic from executing. The $ function is used to create a jQuery object from the event.currentTarget parameter, which represents the element that triggered the event (in this case, a button element). The $button.length property is then checked to see if the button element exists.

function handleClick(event) {
  event.preventDefault();

  const $button = $(event.currentTarget);

  if (!$button.length) {
    console.log('Error: button element not found');
    return;
  }

  // rest of the function logic
}

iOS and Mac

Swift 5

In this example, the guard statement with optional binding and isEmpty check is used to guard against nil or empty string values for the value parameter. If the value is nil or empty, a custom MyError error is thrown. Another guard statement is used to guard against the length of the value parameter being outside of the range of 1 to 10 characters. If the length is outside of the range, a custom MyError error is thrown.

enum MyError: Error {
    case valueIsNilOrEmpty
    case valueLengthOutOfRange
}

func doSomething(_ value: String?) throws {
    guard let value = value, !value.isEmpty else {
        throw MyError.valueIsNilOrEmpty
    }
    guard value.count >= 1 && value.count <= 10 else {
        throw MyError.valueLengthOutOfRange
    }

    // rest of the function logic
}

The above are but a few examples on implementing guard clauses across a few different languages using native syntax and libraries for convenience.

Here are the NuGet package URLs for GuardClauses and FluentGuard:

These packages are available on the official NuGet package repository and can be installed using Visual Studio or the .NET CLI.

Thanks for reading…

~ghost

Ghost Writer