http://www.codinghelmet.com/  

Wear a helmet. Even when coding.

howto > reduce-cyclomatic-complexity-extension-methods

How to Reduce Cyclomatic Complexity: Extension Methods
by Zoran Horvat @zoranh75

Many statements do not deserve to appear in the domain logic. Take this piece of code as an example:

namespace Store.Domain.Implementation
{
    public class DomainServices: IDomainServices
    {
        ...
        public IRegisteredUser RegisterUser(string userName, string referrerName)
        {

            IRegisteredUser user = this.RegisterUser(userName);

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

            return user;

        }
        ...
    }
}

This function registers a user with a referrer. Once the user is created, we search for the referrer. If successful, i.e. if the user with specified user name exists, we just assign that referrer object to the newly created user. This operation has business meaning. Namely, referrer will receive certain discount after new user has registered.

The way in which this operation is implemented is to use TryFind method on the user repository. This method returns Option<User>, which is a collection containing either zero or one user. For more details on Option<T> functional type, please refer to one of the previous articles in this series - How to Reduce Cyclomatic Complexity: Option<T> Functional Type.

Option object returned from the TryFind method is then used to invoke SetReferrer method on all referrer user objects. However, this statement contains one irritating line – call to the ToList method. This method was invoked only because I wanted to call the ForEach method.

Can we do this in some other way? Basically, call to the ToList method has nothing to do with what we wanted and that line is only reducing readability of the code.

The solution lies in the combination of ToList and ForEach methods. We wanted to invoke SetReferrer method on all referrer objects in the collection, but we didn’t have a method which does precisely that. So we reached out for the combination of ToList and ForEach methods. This combination is idiomatic and it is easy to imagine other cases where it is used.

For example, this same DomainServices class has another method which also uses ToList and ForEach methods combined:

namespace Store.Domain.Implementation
{
    public class DomainServices: IDomainServices
    {
        ...
        public void Deposit(string userName, decimal amount)
        {
            this.userRepository
                .TryFind(userName)
                .Select(user => this.accountRepository.FindByUser(user))
                .ToList()
                .ForEach(account => account.Deposit(amount));
        }

    }
}

Deposit method searches for the user, then picks up the user’s account and invokes Deposit method on the Account object. Once again, TryFind method of the user repository returns a collection with zero or one object in it, and once again we use this ToList-ForEach idiom to invoke a method on each of the elements in the collection.

Moving Idiomatic Expressions to Extension Methods

We can simplify our code by identifying expressions that merely complicate the code and appear more than once. Then we move those expressions to an extension method on the class which was used.

For example, ToList method call followed with the ForEach method call can be moved to an extension method on an IEnumerable<T> interface:

namespace Store.Helpers
{
    public static class IEnumerableExtensions
    {
        public static void Each<T>(this IEnumerable<T> collection, Action<T> action)
        {
            collection.ToList().ForEach(action);
        }
    }
}

With this change, we can simplify domain service methods a bit, and also make them more readable:

namespace Store.Domain.Implementation
{
    public class DomainServices: IDomainServices
    {
        ...
        public IRegisteredUser RegisterUser(string userName, string referrerName)
        {

            IRegisteredUser user = this.RegisterUser(userName);

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

            return user;

        }

        public void Deposit(string userName, decimal amount)
        {
            this.userRepository
                .TryFind(userName)
                .Select(user => this.accountRepository.FindByUser(user))
                .Each(account => account.Deposit(amount));
        }

    }
}

With this modification, methods read exactly as they would read in the client requests. For example, user registration request would read like: Create a user with specified user name and, if another user with referrer name exists, set that user as the referrer.

Deposit request would read like: Find the user and, if she exists, deposit money to her account.

Implementation of both methods is exact copy of the request and that is what we can accomplish by moving unrelated processing to utility methods, such as extension methods.

Moving Ugly Code to Extension Methods

Sometimes classes that we use cause us to write plain ugly code. Look at this function:

namespace Store.Infrastructure
{
    public class UserRepository: IUserRepository
    {
        ...
        public Option<User> TryFind(string userName)
        {
            User user = null;
            if (this.userNameToUser.TryGetValue(userName, out user))
                return Option<User>.Create(user);
            return Option<User>.CreateEmpty();
        }
    }
}

This function simulates a repository. It keeps User objects in the internal dictionary and then searches the dictionary by user name when a user object is requested. But the way in which we are querying the dictionary is hard to read and requires some thinking every time we lay our eyes on that line.

One of the problems in programming is when there is a mapping between what we think and what the code looks like. Many times, operations are performed in an obscured way and we have to spend a couple of seconds thinking what this line does.

We can address readability problems by providing extension methods and putting this obscure code there. For example, we could extend the IDictionary interface to support getting an Option object from the key value:

using System.Collections.Generic;

namespace Store.Helpers
{
    public static class IDictionaryExtensions
    {
        public static Option<TValue> TryGetValue<TKey, TValue>(this IDictionary<TKey, TValue> dictionary, TKey key)
        {

            TValue value;
            if (dictionary.TryGetValue(key, out value))
                return Option<TValue>.Create(value);

            return Option<TValue>.CreateEmpty();

        }
    }
}

This is all it takes to enclose the irritating operation on the dictionary. Now we can use the dictionary in much more elegant way:

namespace Store.Infrastructure
{
    public class UserRepository: IUserRepository
    {
        ...
        public Option<User> TryFind(string userName)
        {
            return this.userNameToUser.TryGetValue(userName);
        }
    }
}

When written in this way, it is quite obvious what the TryFind method does. It delegates the call to the internal dictionary and returns the Option<User> object possibly containing the requested element.

Conclusion

It is sometimes difficult to see the forest for the trees. It almost looks like programming languages are forcing us to add cryptic symbols to the code, lines and expressions that we write only to map requirements to actual way in which source code is normally written.

But we can step aside and ask: Is that really the way in which source code is supposed to be written?

When functional extensions were added to the C# language, we could suddenly move query-like code to extension methods. Now we can use that powerful option to remove things that are not part of the domain logic, but take room in the domain-related methods. Such scaffolding or infrastructure code can easily be enclosed in extension methods defined on the class or type which provides input for the operation.

Net result is the domain logic code which is much easier to read and to understand. By providing convenient names to extension methods, we could even get away with never having to look at their actual implementation in order to understand the domain logic implementation.

See also:

Published: May 19, 2015; Modified: Apr 29, 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