Los Techies : Blogs about software and anything tech!

Anti-Patterns and Worst Practices – The Arrowhead Anti-Pattern


arrow

This anti-pattern is named after the shape that most code makes when you have many conditionals, switch statements, or anything that allows the flow to take several paths. You’ll commonly see these nested within each other over and over, thus creating the arrow or triangle shape. This anti-pattern doesn’t always rely this arrow shape to be created by the nested blocks, but can have just as many paths through the code as it would if the arrow shape was replaced using guard clauses where applicable. The main problem we’re trying to solve by eliminating this, is the number of paths (cyclomatic complexity) that the code contains.

Take the following example (from http://c2.com/cgi/wiki?ArrowAntiPattern):

if get_resource
    if get_resource
        if get_resource
            if get_resource
                do something
                free_resource
            else
                error_path
            endif
            free_resource
        else
            error_path
        endif
        free_resource
    else
        error_path
    endif
    free_resource 
else
    error_path
endif

Not the most elegant code in the world kind of a pain to mentally walk through, huh? Oftentimes I’ll put conditionals into guard clauses, this makes for a more readable codebase for starters. The following code is attempting to add a role to a user:

public void AddRole(Role role)
{
    if (role != null)
    {
        if (!string.IsNullOrEmpty(role.Name))
        {
            if (!IsInRole(role))
            {
                roles.Add(role);
            }
            else
            {
                throw new InvalidOperationException("User is already in this role.");
            }
        }
        else
        {
            throw new ArgumentException("role does not have a name", "role");
        }
    }
    else
    {
        throw new ArgumentNullException("role");
    }
}

Likely, you see the path that this is going down. We have all these checks, which aren’t bad by any means, to ensure that the role is appropriate to add for this user. If we refactor to use guard clauses, it’s nicer to read.

public void AddRole(Role role)
{
    if (role == null)
        throw new ArgumentNullException("role");
 
    if (string.IsNullOrEmpty(role.Name))
        throw new ArgumentException("role does not have a name", "role");
 
    if (IsInRole(role))
        throw new InvalidOperationException("User is already in this role.");
 
    roles.Add(role);
}

That’s a lot better, but I think we can do more here. If we have access to something like a UserRoleValidation class, we’ll just use that.

public void AddRole(Role role)
{
    userRoleValidator.Validate(role);
 
    if (IsInRole(role))
        throw new InvalidOperationException("User is already in this role.");
 
    roles.Add(role);
}

I can find countless other ways to improve this sample code, but these simple tasks are good ways to get rid of that arrowhead that forms when several conditions all must be in tune for your code to work the way you expect it to. The real key is breaking your code apart into smaller pieces that do one thing, and do it well. When you see these “arrowheads” form, it’s likely because the code is trying to do too much.

[See more Anti-Patterns and Worst Practices]

Kick It on DotNetKicks.com
Posted May 27 2009, 08:00 AM by Chris Missal

Comments

Matt Youngblut wrote re: Anti-Patterns and Worst Practices – The Arrowhead Anti-Pattern
on 05-27-2009 10:50 AM

I used to be a big fan of single point of entry/exit.  Now I realize how bad arrowhead code can be.

The one thing that I don't like though, is having some return right in the middle of a method (if you have small methods, this isn't a problem).  I am of the belief you either exit early, or exit at the end, but not scattered throughout a method, just because you don't want arrowhead code.

Sound reasonable?

DotNetShoutout wrote Anti-Patterns and Worst Practices – The Arrowhead Anti-Pattern - Chris Missal - Los Techies
on 05-27-2009 11:05 AM

Thank you for submitting this cool story - Trackback from DotNetShoutout

Chris Missal wrote re: Anti-Patterns and Worst Practices – The Arrowhead Anti-Pattern
on 05-27-2009 11:14 AM

@Matt

I agree, that usually makes it easier to understand. Clarity is always good, but so is brevity.Trying to achieve both isn't always easy, but the closer you can get to both, the better off you'll be.

Tom de Koning wrote re: Anti-Patterns and Worst Practices – The Arrowhead Anti-Pattern
on 05-27-2009 5:31 PM

I normally use a validation object that I inject as well; but this post codebetter.com/.../always-valid.aspx by Grey Young made me rethink the concept of validation; why not use an invariant rather that a validator?

Chris Missal wrote re: Anti-Patterns and Worst Practices – The Arrowhead Anti-Pattern
on 05-27-2009 5:53 PM

@Tom

As usual, excellent thoughts from Greg Young. So why not use an invariant rather than a validator? Cause I'm not Greg Young [MVP] ;)

I think if you're debating on the kind of validation I show, and what Jeffery Palermo showed in his post, versus what Greg Young is describing, you're already better off than the guy who wrote the first couple code examples in this post.

It's the thinking outside the scope of what current line you're on is what I'd like people to take away from this post.

Reflective Perspective - Chris Alcock » The Morning Brew #356 wrote Reflective Perspective - Chris Alcock » The Morning Brew #356
on 05-28-2009 3:36 AM

Pingback from  Reflective Perspective - Chris Alcock  » The Morning Brew #356

Jacob Stanley wrote re: Anti-Patterns and Worst Practices – The Arrowhead Anti-Pattern
on 05-28-2009 5:19 AM

@Matt

I used to practice single entry/exit, but now I'm of the opinion that if you're worried about multiple returns then you should be looking at reducing the size of your methods.

Chris Missal wrote Anti-Patterns and Worst Practices – You’re Doing it Wrong!
on 05-28-2009 7:30 PM

When shown ideal code, I think developers understand why it is favorable. When it is regarding Separation

SeanJA wrote re: Anti-Patterns and Worst Practices – The Arrowhead Anti-Pattern
on 05-29-2009 7:35 AM

Ah! Not the arrow! I see that way too often... especially in bad mvc attempts... sigh...

Arrowhead Anti-Pattern « William Bartholomew wrote Arrowhead Anti-Pattern « William Bartholomew
on 05-31-2009 5:54 AM

Pingback from  Arrowhead Anti-Pattern «  William Bartholomew

Jaroslaw Dobrzanski wrote re: Anti-Patterns and Worst Practices – The Arrowhead Anti-Pattern
on 06-02-2009 4:07 PM

You suggestions are correct. You don't have to be a developer to feel the difference :)

However, one needs to be cautious - an exception means sth wrong happened when the application was running. Therefore the number of different exceptions must be balanced. As usual there must be a compromise between nice readable code and sticking to good programming practises.

Anyway, your ideas very good.

Chris Missal wrote re: Anti-Patterns and Worst Practices – The Arrowhead Anti-Pattern
on 06-02-2009 6:16 PM

@Jaraslaw

"You don't have to be a developer to feel the difference"

You're right, I've seen this become a problem with HTML markup as well.

The Technology Post for May 28th | rapid-DEV.net wrote The Technology Post for May 28th | rapid-DEV.net
on 06-14-2009 12:34 PM

Pingback from  The Technology Post for May 28th | rapid-DEV.net

Observations on the ‘if’ statement | Elegant Code wrote Observations on the ‘if’ statement | Elegant Code
on 08-15-2009 12:30 AM

Pingback from  Observations on the ‘if’ statement | Elegant Code

Sean Chambers wrote Refactoring Day 24 : Remove Arrowhead Antipattern
on 08-24-2009 8:00 AM

Today’s refactoring is based on the c2 wiki entry and can be found here . Los Techies own Chris Missal

张荣华 wrote 31天重构指南之二十四:分解复杂判断
on 10-16-2009 4:58 AM

今天要说的重构基于c2 wiki上的条目,你可以在这里查看该条目,在这里还有另一篇文章。 简单的来说,当你的代码中有很深的嵌套条件时,花括号就会在代码中形成一个箭头。我经常在不同的代码中看到这种情况,...

Add a Comment

(required)  
(optional)
(required)  
Remember Me?

Enter the numbers above:
Copyright Los Techies 2008, 2009. All rights reserved.
Powered by Community Server (Commercial Edition), by Telligent Systems