Andy Hunt's Agile Carolinas Talk

§ April 28, 2009 14:11 by beefarino |

I just got back from hearing Andy Hunt discuss his new book, Pragmatic Thinking and Learning.  I hadn't heard him speak before, and I have to admit I was not sure what to expect.

On the one hand, I hold many of this books in very high regard.  In particular, the following books were career-altering reads for me:

And his keystone role in the Agile movement has earned my utmost respect.  However, when I saw the title of this latest book I was a bit worried.  I have a master's degree in cognitive psychology, and I know a lot about learning, memory, and perception.  Most learning books outside of the field are crap, so honestly my first instinct was that this was going to be a cash-grab treatise of self-help porch psychology fuzzy-feel-goods for software developers.

After listening to Andy's presentation, I am happy to say my instincts were way off the mark.

First of all, the book (and Andy's presentation) remains true to the pragmatic banner.  His recommendations are both practical and effective.  For example, a recurring theme during this talk was to write things down.  Carry around a small notebook and jot down every idea that pops into your head.  Maintain a personal wiki.  Mindmap as you read or think.  Solidify your thoughts into something concrete.  The point is not to be able to refer back to them later, but instead to force your brain to keep working, keep producing, keep processing.  To summarize one of his points, that's the first step to an accomplishment.

Second, a lot of what he was saying is supported by academic research.  Granted, Andy takes some license with his metaphors but his points hold water.   E.g., what Andy refers to as the "memory bus" being shared between "dual cores" of the brain is probably more of an attention effect; however, the behavioral effect cannot be denied - the serial and holistic parts of your mind compete when trying to solve a problem.

Based on the presentation tonight, I wouldn't recommend the book to my former psychology colleges - it's too macro to be useful to them.  However, for my fellow geeks, this is actually a useful introduction to becoming a more effective learner.

It was a great talk, a fun evening, and I plan to pick up the book next time I'm at the bookstore.  Oh, and I had a short chat with Andy just before the talk, and I have to say how awesome it is to meet someone you hold as a guru and detect no ego.  Awesome.



Automation Framework pt 5: Hiding Complexty in a Fluent Interface

§ March 2, 2009 11:12 by beefarino |

In my last Automation Framework post I asked for some advice on managing state between commands.  I didn't get any public feedback on the blog, but an old college of mine named Jon Lester tinkered with the blogged examples and sent me some of his code.  The nut of his idea was to use extension methods on an accumulator object to separate the domain logic from the testing apparatus.  I liked his approach, it wasn't something that would have popped into my head; it also put a spotlight on a simple and elegant solution to my state sharing problem.

Before I dive into Jon's idea, take a look at how I'm currently sharing state between my command objects:

//...
UserAccount account = new UserAccount();
CompositeCommand cmd = new CompositeCommand(
    new LoadUserAccountCommand { UserName = userName, Account = account },
    new MakeDepositWithTicketCommand { Amount = depositAmount, Account = account }
);
bool result = cmd.Execute( context );
// ... 

This example represents a single task on the system under test - specifically making a deposit into a user account.  The task effort is distributed across the LoadUserAccountCommand and MakeDepositWithTicketCommand objects, which must share a common Account object in order to accomplish the ultimate goal.

As I described previously, I like this approach okay, especially compared to some of the alternatives I've tried.  I think it's simple enough to understand, but at the very least, it requires some explanation which is an API FAIL.  And although you can make it work for value and immutable types, it takes an ugly hack.

My college's solution was to isolate the shared states from the commands, and expose the units of work in a fluent interface wrapping the shared state.  I whittled down his approach into a lean and clean interface - here's an example of the end result:

// ...
Execute.Using( context )
    .ForPlayer( account )
    .Deposit( 500m );
// ... 

Same unit of work, but a lot less code and far easier to understand IMO.  

Implementation

The root of the fluency is implemented in the Execute class, which encapsulates a command context (which I describe here):

public class Execute 
{
    IContext context;
    private Execute( IContext ctx )
    {
        context = ctx;
    }
    
    public static Execute Using( IContext context )
    {
        Execute e = new Execute( context );
        return e;
    }
    public AccountCommands ForPlayer( Account account )
    {
        return new AccountCommands( user, Process );
    }
    
    public GameCommands ForGame( Game game )
    {
        return new GameCommands( game, Process );
    }
    
    bool Process( ICommand[] commands )
    {
        foreach( var command in commands )
        {
            if( ! command.Execute( context ) )
            {
                return false;
            }
        }
        return true;
    }
}

As you can see, the only inroad to this class is the Using method, which returns a new instance of the execute class initialized with the Command Context.  The various flavors of the For() method are used to capture the shared state for a set of commands.  They each return a object supporting a redundant, fluent interface of commands around the state.  For example, here is some of the AccountCommands class:

public class AccountCommands
{
    Func< bool, ICommand[] > processCommands;
    
    public AccountCommands( Account account, Func< bool, ICommand[] > callback )
    {
        processCommands = callback;
        this.Account = account;
        
        processCommands(
            Chain(
                new LoadUserAccountCommand { Account = Account },
                new CreateUserAccountCommand { Account = Account }
            )
        );
    }
    
    public Account Account { get; set; }
    
    public AccountCommands Deposit( decimal amount )
    {
        processCommands(
            new MakeDepositWithTicketCommand {
                Amount = amount,
                Account = account
            }
        );
        
        return this; 
    }
    
    public AccountCommands Withdraw( decimal amount )
    {
        processCommands(
            new MakeWithdrawalWithTicketCommand {
                Amount = amount,
                Account = account
            }
        );
        
        return this;
    }
    
    public AccountCommands SetProperties( Hashtable properties )
    {
        processCommands(
            Compose(
                new LoadAccountPropertiesCommand {
                    Account = account
                },
                new SetAccountPropertiesCommand {
                    Properties = properties,
                    Account = account
                }
            )
        );
        
        return this;
    }    
    
    // etc ...
    ICommand Chain( params ICommand[] commands)
    {
        return new ChainOfResponsibilityCommand(
            commands
        );
    }
    ICommand Compose( params ICommand[] commands )
    {
        return new CompositeCommand(
            commands
        );
    }
}


Items of note:

  • The constructor accepts two arguments: an Account object that represents the state shared by every member of the class, and a Func<> delegate that accepts an array of command objects and returns a boolean;
  • Each public method of the class represents a single task one can perform against an account;
  • Every public method simply composes one or more Command objects, which are passed to the processCommand callback for actual processing.

Huge Bennies

It still needs some work, but there are many things I like about this approach.  The thing I like most is that the fluent interface hides the complexities of composing command objects with shared state to perform system tasks.  I get all the benefits of the command pattern with minimal hassle.

With a bit of refactoring, I can easily reuse the *Commands objects from this fluent interface to do things besides execute the task.  E.g., perhaps I want to build up a system scenario and persist it, something like this:

var commands = new List< ICommand >();
BuildUp.Into( commands )
    .ForEachAccount
    .Deposit( 500m )
    .SetImage( PlayerImages.Face, testBitmap )
    .SetProperties(
        new {
            Address = "12 Main St.";
            City = "Anywheretownvilleton"
            State = "Texhomasippi"
            Zip = "75023"
        }
    );
// now the commands variable contains the defined 
// command structure and can be re-used against new
// players in the future, persisted to disk, etc.

Another big benefit of this approach is that it gives me a stable binding point for PowerShell - and by that I mean that I can deeply integrate this automation framework with PowerShell, leveraging all of the built-in freebies with virtually no effort.  But that is another post...

 



The Thing about Best Practices

§ February 12, 2009 03:34 by beefarino |

There's been a big stinky vine growing on the interwebs lately, rooted in the some comments made by Joel and Jeff during a podcast and aggravated by a recent post on Coding Horror. If you've been under a rock for the past week, a good summary can be found here.  Or go google stackoverflow podcast rant and bathe in it. 

I'm pretty late to the game on this meme, but since my experience and attitude seems to differ a bit from what I'm reading elsewhere I thought I'd share it.

I think I'm an above-average software engineer.  It's something I take seriously, and I spend a great deal of my time learning, experimenting, reading, and seeking out new knowledge in this area.  It's one of the things I would pursue even if I wasn't getting paid to do it.  That said, I routinely choose not to apply good engineering principles on software projects where it yields no benefit.  E.g., I don't do as much TDD or refactoring on spikes when I know the code is going to be thrown away.  

I also think I'm a mediocre woodworker, at best.  I enjoy doing it, but I don't feel the same compulsion to learn as much as I can, to hone those skills, sacrifice the time and resources necessary to take those skills to the next level.  I'm content doing it as poorly as I do.  However, two years ago when I was working on the two-story tree house that would be holding my girls eight feet off the ground, you can bet your ass I learned all I could about proper tree house design and construction and applied every bit of that knowledge to my project.

What I'm trying to say is this:

  • you don't always have to apply the best practices, but you can't make that choice without knowing what they are;
  • you don't have to be very experienced to realize what you don't know and when you need to learn it.


Resolution 2009: Be a Beacon, Bypass the Bugzappers

§ December 31, 2008 06:39 by beefarino |

Being the last day of 2008, I thought I would share my professional resolutions for 2009.  First, let me share with you what someone recently said to me during a discussion about leadership:

"Every person shines a light for others to see, and they choose whether that light is a beacon or a bugzapper."

He went on to explain that a beacon uses their experience, passion, and knowledge to to make people better.  A bugzapper uses their experience, passion, and knowledge to bring people down, to make themselves feel bigger by making others feel smaller. 

Now that we're talking the same language, my professional resolution for 2009 is to be a better beacon.  My goal is to be more successful at beaconage by trying some of the following things...

get out of my silo 

My team works fairly independently, along clearly delineated sandboxes defined my expertise.  I hate this - I'm not an expert in anything, so rather than feel useful I feel pigeon-holed, and my projects are usually so isolated that I end up working on them alone.  The work is stagnant, usually off-the-backlog, and I never feel like a "real" contributor.  So, I'm going to start finding ways to help out in other areas of the system, and spiking some projects ideas that touch areas outside of my sandbox. 

I'm not sure how I'll make this happen or how welcome my presence will be, but our team has become a skeleton crew steering a galleon, so I think I can make a few opportunities for myself ...

try more, do more, write more

I feel like I should accomplish more than I do, both professionally and personally.  I'm going to try some modest time management tactics and see how much more stuff I can get done.  E.g., I'm trying out maintaining my away-from-work projects and spike ideas using a backlog, and managing their execution with sprints in the hope that I don't pitter away my free time on endless and unnecessary polish.  

Moreover, I want to update this blog more frequently with details of these projects and spikes.  I love to write, and this blog my primary outlet for it.  

smile more, talk more

I know it sounds silly, but I'm starting to understand that to most people a 6-foot 2-inch 200+ pound barrel-chested dude with hair turning to dreds halfway down his back is scary-looking.  And I'm a thinker, so I tend to be pretty quiet unless I have questions.  The combination can come off ... unwelcoming.  So, I'm going to try to wear a smile and chime in more by default, and see what that gets me.  

cope with the bugzappers

This is, without a doubt, going to be the hardest part of my resolution.  There are (and always will be) people chomping at the bit to shit all over my efforts, and I tend to take that rather personal.  I never enjoy conflict, but I understand conflict is necessary to improve myself or others.  However, being brow-beaten, chided, degraded, or ignored frustrates me to no end and accomplishes nothing beyond making me want to kick the bugzapper in the sack.

That is my biggest obstacle at this point: coping with the bugzappers in a way that doesn't turn me into one of them.

Suggestions welcome.