The Arrow Anti-pattern

The Arrow Ani-pattern is a name given to the resulting structure produced by using excessive nested conditional operators. The following pseudo-code demonstrates why the name is apt:

if( ... )
{
    if( ... )
    {
        if( ... )
        {
            if( ... )
            {
                if( ... )
                {
                    //--> do something
                }

            }
        }
    }
}

The structure above becomes increasingly problematic as each additional nested condition adds to the cognitive load required to parse the represented logic. According to studies performed by Noam Chomsky and Gerald Weinberg in 1986, few people can easily understand more than three levels of nested conditional statements. It is therefore recommended that techniques for restructuring the code be sought out when this pattern begins to emerge.

Guard Clauses

One approach to refactoring the arrow anti-pattern is to use guard clauses. Guard clauses are a form of assertion which makes a tangible contribution to the logic of the method. By restructuring nested conditional statements to successive conditional exit points, the code becomes easier to understand and eases further refactoring efforts such as method extraction or clause reordering.

void SomeProcess()
{
    if( ... )
        return;

    if( ... )
        return;

    if( ... )
        return;

    if( ... )
        return;

    if( ... )
        return;

    // do something
}

Method Extraction

Another approach especially suited to blocks comprised of nested looping structures is the extraction of segments into separate methods. For each block forming the body of a loop statement, extract the body into a separate method which can then be examined independently of the containing loop statement:

Before

    void SomeProcess()
    {
        while( ... )
        {
            while( ... )
            {
                while( ... )
                {
                    while( ... )
                    {
                    }
                }
            }
        }
    }

After

    void SomeProcess()
    {
        while( ... )
        {
            MethodA();
        }
    }

    void MethodA()
    {
        while( ... )
        {
            MethodB();
        }
    }

    void MethodB()
    {
        while( ... )
        {
            MethodC();
        }
    }

    void MethodC()
    {
        while( ... )
        {
            MethodD();
        }
    }

Logical And/Or

In cases where the nested structure is comprised solely of checks against the state of an object, the conditions can be extracted into a collection of Boolean methods and combined to form a more concise and readable guard clause:

void SomeProcess()
{
    if(ConditionA() &&
          ConditionB() &&
          ConditionC() &&
          (ConditionD1() || ConditionD2()) &&
          ConditionE())
    {
        // do something
    }
}

Composite Specification Chain

As a variant to the previous technique, the Specification pattern can be used in the form of a composite specification chain to render a concise and readable guard clause. Using this technique, specification classes are written to test each case, and the resulting set of specifications are composed into a single composite specification which can evaluate the state of the given object. Due to the encapsulation of the evaluation logic in the form of separate specification classes, this technique has the added benefit of enabling substitution of the specification implementation via the Strategy pattern for test isolation or other variable composition needs.

void SomeProcess()
{
    ISpecification<SomeType> specification = new IsConditionA()
        .And(new IsConditionB())
        .And(new IsConditionC())
        .And(new IsConditionD1().Or(IsConditionD2()))
        .And(new IsConditionE());

    specification.IsSatisfiedBy(this).Then(() => { /* do something */ });
}

Conclusion

The techniques presented here are a few approaches to helping achieve more readable and maintainable code by eliminating the arrow anti-pattern. Through the judicious application of these techniques, developers can in small ways leave their code base cleaner than they found it.

About Derek Greer

Derek Greer is a consultant, aspiring software craftsman and agile enthusiast currently specializing in C# development on the .Net platform.
This entry was posted in Uncategorized and tagged . Bookmark the permalink. Follow any comments here with the RSS feed for this post.
  • http://www.blogger.com/profile/11278436552796934211 Derick Bailey

    Great post! lots of good ideas for when you need to clean up the code. Don't forget about other object oriented patterns like chain of responsibility, iterators, registries, etc. etc. etc, though. There's a lot of ways that OO patterns can help us out of the arrow anti-pattern.