http://www.codinghelmet.com/  

Wear a helmet. Even when coding.

howto > reduce-cyclomatic-complexity-guard-clause

How to Reduce Cyclomatic Complexity: Guard Clause
by Zoran Horvat @zoranh75

Guard clauses are important part of design. All public methods of all publicly available classes must be protected from invalid input. Otherwise, method execution could be erratic and lead to inconsistent system state.

Guard Clauses in Use

Take a look at the implementation of domain services in the e-commerce application:

namespace Store.Domain.Implementation
{
    public class DomainServices: IDomainServices
    {

        private readonly IUserRepository userRepository;
        private readonly IProductRepository productRepository;
        private readonly IAccountRepository accountRepository;

        public DomainServices(IUserRepository userRepository,
                              IProductRepository productRepository,
                              IAccountRepository accountRepository)
        {
            this.userRepository = userRepository;
            this.productRepository = productRepository;
            this.accountRepository = accountRepository;
        }

        public IRegisteredUser RegisterUser(string userName)
        {

            if (string.IsNullOrEmpty(userName))
                throw new ArgumentException("User name must be non-empty.", "userName");

            User user = new User(userName);

            this.userRepository.Add(user);

            Account account = new Account(user);
            this.accountRepository.Add(account);

            return user;

        }

        public IRegisteredUser RegisterUser(string userName, string referrerName)
        {

            if (string.IsNullOrEmpty(userName))
                throw new ArgumentException("User name must be non-empty.", "userName");

            if (string.IsNullOrEmpty(referrerName))
                throw new ArgumentException("Referrer name must be non-empty.", "referrerName");

            IRegisteredUser user = this.RegisterUser(userName);

            this.userRepository
                .TryFind(referrerName)
                .Each(referrer => user.SetReferrer(referrer));

            return user;

        }

        public bool VerifyCredentials(string userName)
        {

            if (userName == null)
                throw new ArgumentNullException("usernName");

            return this.userRepository.TryFind(userName).Any();

        }

        public IReceiptViewModel Purchase(string userName, string itemName)
        {

            if (string.IsNullOrEmpty(userName))
                throw new ArgumentException("User name must be non-empty.", "userName");

            if (string.IsNullOrEmpty(itemName))
                throw new ArgumentException("Item name must be non-empty.", "itemName");

            return  this.userRepository
                .TryFind(userName)
                .Select(user => this.Purchase(user, itemName))
                .DefaultIfEmpty(new InvalidUser(userName))
                .Single();

        }

        public IReceiptViewModel AnonymousPurchase(string itemName)
        {

            if (string.IsNullOrEmpty(itemName))
                throw new ArgumentException("Item name must be non-empty.", "itemName");

            return this.Purchase(new AnonymousBuyer(), new InfiniteCash(), itemName);

        }

        public void Deposit(string userName, decimal amount)
        {

            if (string.IsNullOrEmpty(userName))
                throw new ArgumentException("User name must be non-empty.");

            if (amount <= 0)
                throw new ArgumentException("Deposit must be positive.", "deposit");

            this.userRepository
                .TryFind(userName)
                .Select(user => this.accountRepository.FindByUser(user))
                .Each(account => account.Deposit(amount));

        }

        ...

    }
}

There are six public methods in this class. And if we slowly walk down the code we can see that nearly half of the code is devoted to defending from invalid input.

In all cases, user name must be non-null and non-empty string. Should the caller pass null string or empty string, ArgumentException would be thrown.

The same constraint is on the item name - whenever a user wants to purchase an item, but supplies null or empty string, ArgumentException is thrown again.

Deposit method is interesting as well. If user attempts to deposit non-positive amount, there comes the ArgumentException again.

Comment on Guard Clauses

These guard clauses are there on purpose. No doubt the application would be vulnerable without them, because faulty data could easily get to the lower layers of the application. Every step of the way, such data could cause harm. That is why we must always place guard clauses to stop them as early as possible.

But is there any other way to implement them? Any other implementation which is less invasive than this series of if statements is certainly welcome. That is the question we will address in this article.

Moving Guard Clauses to Extension Methods

One convenient way of dealing with guard clauses is to enclose them in extension methods. These methods would actually extend the type on which the test is performed.

Take string as an example. We want to test whether the string variable is non-null and non-empty. We do that using static method defined on the System.String type:

if (string.IsNullOrEmpty(userName))
    throw new ArgumentException("User name must be non-empty.", "userName");

The goal of this exercise is to move this entire if statement to the extension method defined on the string type. Something like this:

namespace Store.Helpers
{
    public static class StringExtensions
    {
        public static void AssertNonEmpty(this string value, string paramName)
        {
            if (string.IsNullOrEmpty(value))
                throw new ArgumentException("Value must be a non-empty string.", paramName);
        }
    }
}

This extension method does everything the if statement did before. But it has one advantage - extension method needs not be called directly. It behaves like a method defined on a type.

Replacing Guard Clauses With Extension Methods

Now that we have the extension method defined on the System.String type, we can put it in motion in our custom code:

namespace Store.Domain.Implementation
{
    public class DomainServices: IDomainServices
    {

        ...

        public IRegisteredUser RegisterUser(string userName, string referrerName)
        {

            userName.AssertNonEmpty("userName");
            referrerName.AssertNonEmpty("referrerName");

            IRegisteredUser user = this.RegisterUser(userName);

            this.userRepository
                .TryFind(referrerName)
                .Each(referrer => user.SetReferrer(referrer));

            return user;

        }

        ...

    }
}

See how this method has suddenly become easier to read? That is because long and cumbersome if-then-throw constructs have been removed and replaced with simple calls to the Assert method on string variables. This method clearly depicts benefits from using extension methods compared to explicit if-then-throw implementation.

Extension Methods and Null

In the previous implementation of the AssertNonEmpty extension method, we have implicitly allowed one slightly unusual operation. Having that extension method in place, try to tell what will happen when statement like this is executed:

((string)null).AssertNonEmpty("null");

Will the AssertNonEmpty method throw its ArgumentException, or will the whole statement fail with NullReferenceException even before execution gets into the method?

The answer lies in the extension method itself:

public static void AssertNonEmpty(this string value, string paramName)
{
    if (string.IsNullOrEmpty(value))
        throw new ArgumentException("Value must be a non-empty string.", paramName);
}

The object on which the method is invoked is actually an argument to the method. This means that we are safe to call the extension method directly on a null reference! There will be no NullReferenceException if we try to do that.

This detail has profound effects on the guard clause design. It ensures that we are perfectly safe to move all guard clauses to the extension methods. They will always be executed, even when reference to the object which is tested is null.

More Examples

Strings are not the only type which can be tested using extension methods. Any other type can also be subdued to the same technique. Observe the Deposit method of the domain services class:

namespace Store.Domain.Implementation
{
    public class DomainServices: IDomainServices
    {

        ...

        public void Deposit(string userName, decimal amount)
        {

            if (string.IsNullOrEmpty(userName))
                throw new ArgumentException("User name must be non-empty.");

            if (amount <= 0)
                throw new ArgumentException("Deposit must be positive.", "deposit");

            this.userRepository
                .TryFind(userName)
                .Select(user => this.accountRepository.FindByUser(user))
                .Each(account => account.Deposit(amount));

        }

    }
}

This method is used to deposit specified amount of money to the specified user's account. The method has two guard clauses - one ensuring that user name is non-empty string, and the other one ensuring that the amount to deposit is positive.

We can fix the user name test easily by using the AssertNonEmpty extension method on the string variable. To do the same with the second test, we would have to extend the System.Decimal type:

namespace Store.Helpers
{
    public static class DecimalExtensions
    {
        public static void AssertPositive(this decimal value, string paramName)
        {
            if (value <= 0)
                throw new ArgumentException("Value must be positive.", paramName);
        }
    }
}

With this extension method in place, we can simplify the Deposit method:

namespace Store.Domain.Implementation
{
    public class DomainServices: IDomainServices
    {

        ...

        public void Deposit(string userName, decimal amount)
        {

            userName.AssertNonEmpty("userName");
            amount.AssertPositive("amount");

            this.userRepository
                .TryFind(userName)
                .Select(user => this.accountRepository.FindByUser(user))
                .Each(account => account.Deposit(amount));

        }

    }
}

With this modification in place, Deposit method can finally focus on its primary responsibility - depositing money to the user.

Conclusion

If-then-throw is a well known design principle used to protect operations from receiving invalid input. The problem with if-then-throw is that it quickly clogs the code with many cryptic and complicated throw statements, preceded by if statements which nearly all look the same.

In this article we have seen one powerful technique which helps us keep the code clean and tidy, while still protecting it from invalid input. This repetitive if-then-throw code can all be moved into a small number of extension methods. Each extension method is defined on the type which is actually tested by the if statement.

Net result of this approach is simplified and less complex custom code.

See also:

Published: Jul 14, 2015; Modified: Jul 21, 2015

ZORAN HORVAT

Zoran is software architect dedicated to clean design and CTO in a growing software company. Since 2014 Zoran is an author at Pluralsight where he is preparing a series of courses on object-oriented and functional design, design patterns, writing unit and integration tests and applying methods to improve code design and long-term maintainability.

Follow him on Twitter @zoranh75 to receive updates and links to new articles.

Watch Zoran's video courses at pluralsight.com (requires registration):

Making Your C# Code More Object-Oriented

This course will help leverage your conceptual understanding to produce proper object-oriented code, where objects will completely replace procedural code for the sake of flexibility and maintainability. More...

Advanced Defensive Programming Techniques

This course will lead you step by step through the process of developing defensive design practices, which can substitute common defensive coding, for the better of software design and implementation. More...

Tactical Design Patterns in .NET: Creating Objects

This course sheds light on issues that arise when implementing creational design patterns and then provides practical solutions that will make our code easier to write and more stable when running. More...

Tactical Design Patterns in .NET: Managing Responsibilities

Applying a design pattern to a real-world problem is not as straight-forward as literature implicitly tells us. It is a more engaged process. This course gives an insight to tactical decisions we need to make when applying design patterns that have to do with separating and implementing class responsibilities. More...

Tactical Design Patterns in .NET: Control Flow

Improve your skills in writing simpler and safer code by applying coding practices and design patterns that are affecting control flow. More...

Writing Highly Maintainable Unit Tests

This course will teach you how to develop maintainable and sustainable tests as your production code grows and develops. More...

Improving Testability Through Design

This course tackles the issues of designing a complex application so that it can be covered with high quality tests. More...

Share this article

webmasters