Friday, May 18, 2012

Agile Does Not Mean Being Micromanaged

Today I joined some friends (ex-coworkers) in a goodbye party for an ex-coworker who is moving on to greener pastures. I haven't seen several of these people in a few years, so naturally they asked "What are you doing now?" And I told them that I am an agile coach. And I got asked "And you haven't killed yourself yet?"

Clearly, something is wrong here.

A little background: the company I used to work for was acquired and 'Agile' was imposed upon my old friends. This is an 'Agile' which may be far too familiar to some of you, but I've only heard stories of it before. At the party, two separate people told me they thought 'Agile' was intended to turn programmers into replaceable sprockets who need not think. For example, if they come across a bug in the system, they are supposed to create a defect in the tracking system and move on. Someone will add it to a sprint sometime. Or not. All decisions are made by project managers, and handed down.

The Agile Manifesto and the Agile Principles are a good place to start to validate whether an organization is acting in an agile way. "Individuals and interactions over processes and tools" from the manifesto, and "Build projects around motivated individuals" from the principles both give us an indication of the role of management in these environments: contribute, don't control.

Sunday, May 6, 2012

Why We Refactor

I have always enjoyed Mike Taylor's Reinvigorated Programmer, probably because he so obviously enjoys several things I also enjoy (Doctor Who, programming, Buffy The Vampire Slayer, sushi). I was perusing some of his posts from the last year and came across the following comment regarding the process of refactoring code:
"the purpose of all that shuffling is really only to get the deck clear so we can concentrate properly on the hard bits without getting distracted by crud".

I think this is missing the point. Refactoring give us tools for rigorously transforming code. There are several reasons why this might be useful. One reason is that the programmer before us was an incompetent buffoon  Another reason is that we work in and with teams, and collaborative work tends to get messy with time. We need to perform housecleaning so the technical debt doesn't cause us to go bankrupt.

These reasons are largely in line with what Mike is suggesting, I think. However, there's another reason to perform refactorings on a regular basis, and it is crucial to how we work as programmers.

The code you wrote six months ago (or six weeks ago) solved one particular problem pretty well. This is probably not the exactly problem you're trying to solve anymore. The requirements may have changed (accounting suddenly really _does_ want to run reports against itemized receipts), or maybe you just saw a better way to code the whole thing. Now you've got to pull all the affected abstractions up to the new world order. Classes start to fit together differently. Design patterns get replaced by different patterns, or disappear altogether. Engines suddenly find themselves servicing wholly new systems.

The way forward is with the refactoring tools. Instead of rewriting the system to conform to our new way of thinking, we can transform it. We can mold it so it continues to fit our needs. And we prefer this to a rewrite because it is less costly, we can deliver with only half of the transformation done (usually) without unduly impacting features, and the new designs practically write themselves.

I think "the hard bits" Mike references are exactly where refactoring shines. Making sure the performance profile is acceptable is a refactoring task. Ensuring the application is extensible through plugins is an exercise in refactoring. Extracting out the timer behaviors from the license module to be reusable is refactoring; so is reconciling the 3 different timers you just found in the system, because they were disguised as something else. Refactoring touches nearly everything we do, so we really need to make sure we do it well.

Tuesday, May 1, 2012

How Do You Name Your Tests?

How do you name your classes? You probably think of the noun or verb which best describes the behavior you want; perhaps there are some technical details which slip through like the name of a design pattern. But generally, a class' name should tell you what that class is responsible for. (Edit: Jeff Langr and Tim Ottinger have written an excellent article on the mechanics of how to name your tests.)

Methods are easier to name, perhaps because we do it so much more often. Usually, you'll decide that the method is important because of the return value or the side effects on the enclosing class. Then try to communicate that in as few characters as possible.

Test fixtures and methods are different. A test name doesn't communicate what the test does, it communicates what SOMETHING ELSE does.

Let's look at some common naming conventions used in tests. Our System Under Test will be a Video Store billing system.

TEST_F(BillingTest, WhenRentingARegularMovie_GoodCustomerGetsOneFrequentRenterPoint)
TEST_F(BillingTest, CustomerWithNoLateFeesGetsOneFrequentRenterPointWhenRentingOneRegularMovie)

These two examples are pretty standard fixture names. Specifically, they just tell you the system being tested at the macro level. This may be common at the early stage of TDD because you haven't extracted subsystems yet. This is expected to change as development continues.

TEST_F(CustomerTest, WhenRentingARegularMovieGoodCustomerGetsOneFrequentRenterPoint)

This example names the fixture after the subsystem being tested. There's duplication between the test method name and the fixture name because there's a subset of Customers which we're concerned with. This will happen eventually to every test named this way.

TEST_F(GoodCustomerTest, WhenRentingARwegularMovieGetsOneFrequentRenterPoint)

This example learned a small lesson, and named the fixture after the general condition of the subsystem, thus eliminating the duplication.

TEST_F(CustomerFrequentRenterPointTest, WhenRentingARegularMovieGoodCustomerGetsOne)

This example tries to describe the effect as if it were the system under test. It is common to confuse the two, but it confuses the writer of the tests as much as the reader.

TEST_F(CustomerInGoodStandingRentingOneRegularMovie, GetsOneFrequentRenterPoint)

The last example demonstrates two features of good naming. The first derives from the fact that the fixture is used to share setup between tests, and so can be explicit about what is being shared.

The second feature is that the test method tells you what behavior to expect before the condition under which to expect it. This puts the emphasis of the test on the property of the system which the test is exercising. You would expect to see tests in the same fixture to be easy to compare against eachother. For example:

TEST_F(CustomerInGoodStandingRentingOneRegularMovie, GetsOneFrequentRenterPoint)
TEST_F(CustomerInGoodStandingRentingOneRegularMovie, Pays1_95ForOneDay)
TEST_F(CustomerInGoodStandingRentingOneRegularMovie, Pays2_95ForTwoDays)

Tests document our systems' expected behavior, and names play an important part of that. You want names which help navigate through that documentation. Put the most important information about your system at the first place the next coder will look: the beginning of the test method name. And if you've got underscores in your name to separate the parts, you're probably doing it wrong.