Effectiveness of Teams

Agile places an emphasis on the importance of the team. The team make the decisions: what do we work on today, how do we tackle our constraints, even who should be in the group. But yet some research seems to suggest that individuals are more effective than teams.

For example in “59 seconds” Richard Wiseman questions the effectiveness of brainstorming – groups tend to focus on mundane, easily agreed upon suggestions; or be swayed by uncreative, charismatic team members.

How do we reconcile this conflict? If groups tend to lack creativity and flexibility in their thinking, why do agile teams appear to be more creative, more flexible and above all more effective? Is it an illusion, or does agile actually help teams achieve more?

Just one developer?

The trouble with software is its rarely a lone sport anymore. There aren’t many fields where one developer on his own can make a significant contribution. But where one developer can make meaningful progress you will get the best bang for buck. As soon as you add a second team member you need much more communication (ok, I might sit and talk to myself sometimes, but I talk much more when there’s another human being there). By the time you’re adding a third, fourth or fifth developer, you’re spending loads of time just talking and drawing on whiteboards and standing around having meetings.

If I’m the only person to have touched the code, when it crashes – I know exactly whose fault it is. As soon as there are more developers, we get to play blamestorming. “Well it works fine on my PC”, “It worked last time I ran it”, “You checked in last – it must be your bug”. You start to get the diffusion of responsibility that Wiseman talks about. People don’t feel personally responsible for the output, so they don’t feel compelled to make it better: half assed is good enough, it’s not my problem.

The truth is most activities of any size nowadays require a team of people to work on, which immediately raises the question of who works on what, when.

Fluidity

Maybe agile helps teams be more effective by letting the team be more fluid. Rather than the smartest people getting stuck on one problem or in one area, the fluidity and constant reassessment of agile allows the smart people to automatically refocus to where they need to be. But critically, it doesn’t need someone to micromanage the situation and tell them to work on the most important things – people will “self-organise” and naturally gravitate to where they can help most.

At the daily standup Harry says:

Jim – are you doing ok with the checkout flow? You’ve never done anything like that before so would it help if I came and paired with you today? The order history page can wait until next week so we can hit our target for Friday.

Magic: a “self-organising team”. Imagine some asshat manager had said that! Jim would feel like an idiot, Harry gets to feel awkward so tries not to ride roughshod over Jim’s work – both get dragged down and demotivated; the end result is slow, sloppy work and a miserable team. Instead, because the team came up with the idea, everyone’s happy about it and the work gets done as quickly as possible.

Because different people are always offering help – either because they’re nosy and want to know how something works, or because they’re some smartass know-it-all that’s good at everything – the fact that the smartest people are quickly rotating round the group’s biggest problems isn’t always plain to see. Everyone is moving around; but most of the movement is noise: the important thing is that the brightest, most capable people are moving to where they are needed most.

Maybe the fluidity simply creates a socially acceptable way for the smart people on the team to leap from problem to problem without the rest of the team feeling stupid.

Who’s the rockstar?

I hate the term, but if agile teams are more effective because the “rockstar” developers are working on all the important stuff – that suggests everyone else is working on the unimportant stuff. Now, if your company has time to pay idiots to work on stuff that nobody wants – maybe I can offer you some overpriced consultancy?

But that doesn’t happen, does it? Perhaps because the “rockstar” on the team, is probably only good at playing guitar (stretching the tortured analogy). I’ve heard him play a drum solo: it’s shit. But the drummer? Yeah, he’s not too bad at that. Everyone on a team has different strengths, and will do best at certain tasks. As a manager, it’s almost impossible to try and assign people to tasks to get the best out of everyone and deliver the most value possible. You’re basically trying to allocate resources centrally, which turns out to be pretty hard.

Instead by delegating resource allocation to the team, the team decide who would be best on each activity; the team take responsibility for delivering as much value as quickly as possible. Even if that sometimes means people are working on tasks they’re not suited for – those who are better at it might be working on something more valuable. Sometimes you need a drummer, even if they’re not the best drummer in the band.

Costs

Regular task switching and lots of pairing is great for creating an environment where developers can move from task to task easily. But this comes with a cost – I can’t immediately pick up where James left off, I need to talk to him to find out what he was doing and where he got to, I need to learn and understand the code he wrote yesterday before I can write more. This has a cost to it.

What about the diffusion of responsibility? If six different people all work on the same feature, won’t we find that nobody really cares whether it works, because everyone blames the other guys? Well, assuming we’re all professional developers, I’m sure we wouldn’t sink to such childish behaviour. But it’s surprising how easy you can become detached from the goal you’re aiming for – the overall benefit you’re trying to deliver for the customer. You know what’s left to do, so you do your little bit. You don’t think about the overall goal and what the customer actually wanted. You take your eye off of quality for a split second and bang! You screwed up.

I suspect diffusion of responsibility is a genuine problem in agile teams – which is why shared ownership is emphasised. We all own this code – so treat it as your own. In another light, it’s the craftsmanship ethic – to leave the code a little better than you found it. Don’t just assume the other guy knew what he was doing: fix it, properly. Without this, the diffusion of responsibility would lead to chaos.

To tolerate all these costs: task switching, diffused responsibility, communication and coordination overhead – there simply must be a massive benefit. The upside of having the right people on the right task at the right time must outweigh all those downsides.

But does it always? Does it on your team?

Testing asynchronous applications with WebDriverWait

Want to learn more about WebDriver? What do you want to know?

If you’re testing a web application, you can’t go far wrong with Selenium WebDriver. But in this web 2.0 world of ajax-y goodness, it can be a pain dealing with the asynchronous nature of modern sites. Back when all we had was web 1.0 you clicked a button and eventually you got a new page, or if you were unlucky: an error message. But now when you click links all sorts of funky things happen – some of which happen faster than others. From the user’s perspective this creates a great UI. But if you’re trying to automate testing this you can get all sorts of horrible race conditions.

Thread.sleep

The naive approach is to write your tests the same way you did before: you click buttons and assert that what you expected to happen actually happened. For the most part, this works. Sites are normally fast enough, even in a continuous integration environment, that by the time the test harness looks for a change it’s already happened.

But then… things slow down a little and you start getting flickers – tests that sometimes pass and sometimes fail. So you add a little delay. Just 500 milliseconds should do it, while you wait for the server to respond and update the page. Then a month later it’s flickering again, so you make it 1 second. Then two… then twenty.

The trouble is, each test runs at the pace that it runs at its slowest. If login normally takes 0.1 seconds, but sometimes takes 10 seconds when the environment’s overloaded – the test has to wait for 10 seconds so as not to flicker. This means even though the app often runs faster,  the test has to wait just in case.

Before you know it, your tests are crawling and take hours to run – you’ve lost your fast feedback loop and developers no longer trust the tests.

An Example

Thankfully WebDriver has a solution to this. It allows you to wait for some condition to pass, so you can use it to control the pace of your tests. To demonstrate this, I’ve created a simple web application with a login form – the source is available on github. The login takes a stupid amount of time, so the tests need to react to this so as not to introduce arbitrary waits.

The application is very simple – a username and password field with an authenticate button that makes an ajax request to log the user in. If the login is successful, we update the screen to let the user know.

The first thing is to write our test (obviously in the real world we’d have written the test before our production code, but its the test that’s interesting here not what we’re testing – so we’ll do it in the wrong order just this once):

@Test
public void authenticatesUser()
{
    driver.get("http://localhost:8080/");

    LoginPage loginPage = LoginPage.open(driver);
    loginPage.setUsername("admin");
    loginPage.setPassword("password");
    loginPage.clickAuthenticate();
    Assert.assertEquals("Logged in as admin", loginPage.welcomeMessage());
}

We have a page object that encapsulates the login functionality. We provide the username & password then click authenticate. Finally we check that the page has updated with the user message. But how have we dealt with the asynchronous nature of this application?

WebDriverWait

Through the magic of WebDriverWait we can wait for a function to return true before we continue:

public void clickAuthenticate() {
    this.authenticateButton.click();
    new WebDriverWait(driver, 30).until(accountPanelIsVisible());
}

private Predicate<WebDriver> accountPanelIsVisible() {
    return new Predicate<WebDriver>() {
        @Override public boolean apply(WebDriver driver) {
            return isAccountPanelVisible();
        }
    };
}
private boolean isAccountPanelVisible() {
    return accountPanel.isDisplayed();
}

Our clickAuthenticate method clicks the button then instructs WebDriver to wait for our condition to pass. The condition is defined via a predicate (c’mon Java where’s the closures?). The predicate is simply a method that will run to determine whether or not the condition is true yet. In this case, we delegate to the isAccountPanelVisible method on the page object. This does exactly what it says on the tin, it uses the page element to check whether it’s visible yet. Simple, no?

In this way we can define a condition we want to be true before we continue. In this case, the exit condition of the clickAuthenticate method is that the asynchronous authentication process has completed. This means that tests don’t need to worry about the internal mechanics of the page – about whether the operation is asynchronous or not. The test merely specifies what to test, the page object encapsulates how to do it.

Javascript

It’s all well and good waiting for elements to be visible or certain text to be present, but sometimes we might want more subtle control. A good approach is to update Javascript state when an action has finished. This means that tests can inspect javascript variables to determine whether something has completed or not – allowing very clear and simple coordination between production code and test.

Continuing with our login example, instead of relying on a <div> becoming visible, we could instead have set a Javascript variable. The code in fact does both, so we can have two tests. The second looks as follows:

public void authenticate() {
    this.authenticateButton.click();
    new WebDriverWait(driver, 30).until(authenticated());
}

private Predicate<WebDriver> authenticated() {
    return new Predicate<WebDriver>() {
        @Override public boolean apply(WebDriver driver) {
            return isAuthenticated();
        }
    };
}

private boolean isAuthenticated() {
    return (Boolean) executor().executeScript("return authenticated;");
}
private JavascriptExecutor executor() {
    return (JavascriptExecutor) driver;
}

This example follows the same basic pattern as the test before, but we use a different predicate. Instead of checking whether an element is visible or not, we instead get the status of a Javascript variable. We can do this because each WebDriver also implements the JavascriptExecutor allowing us to run Javascript inside the browser within the context of the test. I.e. the script “return authenticated” runs within the browser, but the result is returned to our test. We simply inspect the state of a variable, which is false initially and set to true once the authentication process has finished.

This allows us to closely coordinate our production and test code without the risk of flickering tests because of race conditions.

Enough whitespace already

In most sensible languages the compiler ignores whitespace; it’s only there to help humans understand the code. The trouble is, without automated checking of whitespace it’s very hard to have consistent style. Without a compiler telling you when you get it wrong, it’s hard to enforce a standard. Sometimes it leads to bugs and, ironically, hard-to-understand code. Maybe it’s time to realise that formatting of code is different from its semantics. Maybe in the 21st century, programmers should be using more than just a text editor?

No Whitespace

For example, the following is perfectly legal Java:

public String shareWishList() {
    User user = sessionProcessor.getUser();  WishList wishList =
    loadWishList.forUserByName(user, selectedWishListName); for(
    String friend : friends)  { if ( !friend.equals("") )  { new
    ShareWishListMail(  friend,  user,  wishList,  emailFactory,
    this.serverHostName ) . send();   }   }   return  "success";
}

But most normal human beings would much prefer to see this written the “traditional” way, with line breaks in appropriate places and sensible use of the space character:

public String shareWishList() {
    User user = sessionProcessor.getUser();
    WishList wishList = loadWishList.forUserByName(user,
                            selectedWishListName);
    for (String friend : friends) {
        if (!friend.equals("") ) {
            new ShareWishListMail(friend, user, wishList,
                                  emailFactory,
                                  this.serverHostName)
                .send();
        }
    }
    return "success";
}

Builders

Of course, most IDEs can reformat code for you. And with careful tweaking of the settings you can get something useful. But there are always cases where you want to do something different, to help readability.

For example, I often format uses of builders differently to other code. While I might normally prefer long lines to be wrapped and continue to the line break on the following line, when calling a builder it makes it hard to read:

Trade trade = tradeBuilder.addFund(theFund).addAsset(someAsset).atSharePrice(2)
    .forShareCount(10).withAmount(20).tradingOn(someDate)
    .effectiveOn(someOtherDate)
    .withComment("This is a test trade").forUser(myUser)
    .withStatus(ACTIVE).build();

This is about a billion times easier to read as:

Trade trade =
    tradeBuilder.addFund(theFund)
                .addAsset(someAsset)
                .atSharePrice(2)
                .forShareCount(10)
                .withAmount(20)
                .tradingOn(someDate)
                .effectiveOn(someOtherDate)
                .withComment("This is a test trade")
                .forUser(myUser)
                .withStatus(ACTIVE)
                .build();

Test Setup

Tests seem to end up particularly dependent on whitespace. For example, in my current job I recently had cause to try and write something like the following:

var sharePosition = CreateAnnualSharePosition
    .InAsset(someAsset)
    .Quarter1Shares(0)        .WithQ1Price(1.250, GBP)
    .Quarter2Shares(10000)    .WithQ2Price(1.15,  GBP)
    .Quarter3Shares(1000000)  .WithQ3Price(1.35,  GBP)
    .Quarter4Shares(1000000)  .WithQ4Price(1.45,  GBP)
    .Build();

Because I had several similar tests, with subtle variations of share count & price quarter-to-quarter it massively helped me while writing it, to have it clearly laid out – so I could see when share count had changed and when price had changed. Unfortunately, VisualStudio had other ideas and removed some of my whitespace when copy & pasting this, which led to me reformatting every damned time.

Internal DSL

Effectively these builders are a form of internal DSL. You’re (ab)using the source language to provide a domain specific language to let you describe what you want to actually do. My previous company used a home grown Java based BDD framework – Narrative. This leads to very fluent acceptance tests, but lots of method chaining. As with the builder pattern this would be totally unreadable without liberal use of whitespace. Take this not particularly unusual example:

Then.the(user)
    .expects_that(the_orders(),
         Contains.only
         (an_order()
                  .of_type(SELL)
                  .for_asset(someAsset)
                  .for_amount(150, gbp())
                  .with_trades(
                      allOf(
                          Contains.inAnyOrder(
                              a_trade_selling("Sub asset 1"),
                              a_trade_selling("Sub asset 2")),
                          trades_totalling("150")
                      ))));

Now, there’s a very particular “style” to how this is laid out. Whoever thought this looked clean and readable (probably me) was clearly on something that day. But it’s difficult to lay out a “sentence” like this because of the massive amount of nesting inherent in what it’s saying.

How can we possibly define rules for whitespace to layout such statements in a clear, readable, machine-enforceable way? After months of seeing different people spend endless hours tweaking whitespace to their own personal preference you know what I realise? You can’t automate it.

So maybe we’re trying to solve the wrong problem? Is the fact that we’re so reliant on whitespace to make code not look like total shit, a hint that maybe our text editor isn’t giving us the expressive power we need? Maybe, just maybe, in the 21st century, programmers could be using something richer than a text editor? Maybe there’s some structure in our source code that we could show better?

Builders – Revisited

Let’s go back to a simple example, my trade builder. Wouldn’t this be easier to read if it was written in the table it so obviously is?

Trade builder

Shock! Horror! Fancy that! Source code that’s not just plain old text but – OMG – a table. The humanity of it! Sacrilege! Giving programmers powerful, expressive, rich text instead of a dumb old text editor.

My share position builder is helped even more by being expressed in a table:

share position builder

But what about the complex set of nested matchers?

Here the nested structure is clearly visible, there’s no need to rely on whitespace – the nested structure is clear and unambiguous. The editor understands the structure and renders the correct layout making it easy to write and much easier to read. It actually becomes impossible to indent things wrong accidentally: a nested table is either nested or it isn’t.

But… how would it work?

Well, obviously our editors would need to be more powerful to support this. The indentation can be derived from the source code: the editor can parse brackets much more easily than the human eye and translate that to a more structured form that’s easier to read.

The critical part is defining the presentation style when declaring a method/class – e.g. identifying builder methods so we can present more naturally.

Would it work?

There are numerous implementation details – but I’m sure it could be made to work easily enough. But, is the complexity worth it? Am I stark raving mad or is it about time our editors were dragged kicking and screaming into the 20th century?

Dealing with technical debt

We’re drowning in technical debt. We have a mountain to climb and don’t really know where to start. Sound familiar? For many of us working on legacy code bases this is the day-to-day reality. But what to do about it?

How did we get here?

Technical debt is always the fault of those “other guys”. Those idiot developers that were here a few years ago. Morons. Obviously couldn’t code their way out of a game of life if their on-going existence depended on it.

I hate to tell you but: we are those other guys. The decisions we make today will look foolish tomorrow. We’ll have more information then, a different perspective; we’ll know how the product and technology were going to evolve. We can’t know that today, so many of our decisions will turn out to be wrong.

Where to start

Classes are like best-selling novels – some are spectacularly more popular / more debt-laden than others. One class, one package, one module – will be much worse than the others. There’ll be a handful of classes, packages etc… that are much worse than all the rest.

How does this happen? Well, one class ends up with a bit of technical debt. Next time I come to change that class, I’m too lazy to fix the debt, so I just hack something together to get the new feature done. Then next time round, there’s a pile of debt – only that guy’s too busy to fix it so he adds in a couple of kludges and leaves it. Before you know it, this one class has become a ten thousand line monster that’s pure technical debt.

It’s like the broken-windows theory – if code is already crappy, its much easier to just make it a little more crappy. If the code’s clean, it’s a big step to add in a hack. So little by little, technical debt accumulates in areas that were already full of debt. I suspect technical debt in code follows a power law – most classes have a little bit of debt, but a few are really shitty, with one diabolical class in particular:

technical debt graph

Where to start? Resist the temptation to make easy changes to relatively clean classes – start with the worst offender. It will be the hardest to fix, it might take a long time – but you’ll get the best bang-for-buck by fixing the most debt-heavy piece of crap code. If you can fix the worst offender, your debt will have to find somewhere else to hide.

The 80/20 rule

There’s a cliché that 80% of the cost of software is maintenance, only 20% is the initial build.

Let’s imagine a team that has 1200 hours a month to spend on useful work. For that 1200 hours of useful work, we’ll spend four times that much over the lifetime of the software maintaining it – from the 80/20 rule. Although we completed 1200 hours of feature work this month, we committed ourselves to 4800 hours of maintenance over the lifetime of the code.

That means next month, we have to spend a little of the 4800 hours of maintenance, with the rest of the time spent on useful, feature-adding work. However, adding new features commits us to even more maintenance work. The following month, we’ve got nearly twice the code to maintain so spend nearly twice the amount of time maintaining it and even less time producing value-adding features. Month-by-month we spend more and more time dealing with the crap that was there before and less and less time adding new features.

productivity graph

Does this sound familiar? This is what technical debt feels like. After a couple of years the pace has dropped; you’re spending half your time refactoring and fixing the junk that was there before. “If only we could get rid of this technical debt”, you cry.

What is technical debt?

We can all point to examples of crappy, debt-laden code we’ve seen. But what’s the impact of technical debt? Technical debt is simply an inability to quickly make changes to an existing system. This is the cost to the business of technical debt – what should be quick changes take an unpredictably long time.

What do we do when we remove technical debt? We generalise and find more abstract solutions. We clarify and simplify. We remove duplication and unnecessary complexity.

The net effect of reducing technical debt, is to reduce inventory.

Perhaps the amount of code – our inventory – is a good approximation for the amount of technical debt in a system. If I’m confronted with a million lines of code and need to make a change, it will probably take a while. However, if I’m only confronted by 1000 lines of code the change will be much quicker. But, if I’m confronted by zero lines of code, then there’s zero cost – I can do whatever I like. The cost of making a change to a system is roughly proportional to the size of the system. Large, complex systems take longer to make changes to than small, self-contained ones.

All code is a liability – the more code you have, the bigger the debt. When we’re paying back technical debt – are we really just reducing inventory? Is what feels like technical debt actually interest payments on all the inventory we hold?

What are the options?

Big bang

One option is to down-tools and fix the debt. Not necessarily throw everything out and rewrite, but spend some time cleaning up the mess. The big bang approach to dealing with technical debt. It’s pretty unusual for the business to agree to a plan like this – no new features for a year? Really? With no new features for a year what would all those product managers do all day?

From the 80/20 rule, the lifetime cost for any piece of code is four times what it cost to create. If it took three months to make, it will take a year to pay back. So wait, we’re gonna down tools for a year and only pay back three months of technical debt? Seriously? We’ll be marginally better off – but we’ll still be in a debt-laden-hell-hole and we’ll have lost a year’s worth of features. No way!

Dedicated Team

Even if you try to do big bang, it ends up becoming the dedicated team approach. As a compromise, you get a specific team together to fix the debt, meanwhile everyone else carries on churning out new features. One team are removing debt; while another team are re-adding it. What are the chances that debt is being removed faster than it’s being added? Exactly. Nil.

It makes sense – you need a team removing debt four times bigger than the team adding new features just to stay still.

Boy Scout

You could adopt a policy of trying to remove technical debt little and often – the boy scout approach. On every single development task try and remove debt near where you’re working. If there are no tests, add some. If the tests are poor, improve them. If the code’s badly factored, refactor it. The boy scout rule – leave the camp cleaner than you found it.

This is generally much easier to sell, there’s only minimal impact on productivity: it’s much cheaper to make changes to a part of the system you understand and are already working in than to open up whole new ones. But over time you can massively slow down the rate at which debt grows. Inevitably the system will still grow, inevitably the amount of debt will increase. But if you can minimise the maintenance cost you’ll keep the code small and nimble for as long as possible.

Professionalism

If we can lessen the maintenance cost of code even just a little we can save ourselves a fortune over the life of the code. If we can reduce the multiple to just three times the initial cost, so our 1200 hours work only costs 3600 hours in maintenance, we’ve saved enough development capacity to build another feature of the same size! For free! Hey, product manager, if we do our job better it’ll take no longer and you’ll get free features. Who doesn’t want free features?

If we can create well-crafted, DRY, SOLID code with good test coverage we have a good chance of minimising the lifetime maintenance cost. This is the best way we can keep our productivity up, to try and avoid getting mired in technical debt and keep the code base responsive to changing requirements. It’s the only way we can remain productive and agile.

Frankly, anything else is just unprofessional. If you’re deliberately committing your company to spend excessive amounts maintaining your shitty code – what the fuck, exactly, are they paying you for?

Growing hairy software, guided by tests

Software grows organically. One line at a time, one change at a time. These changes soon add up. In an ideal world, they add up to a coherent architecture with an intention revealing design. But sometimes software just grows hairy – full of little details that obscure the underlying logic. What makes software hairy and how can we stop it?

Hairy code

Generally code starts out clean – brand new, shiny code. But each time you make a change that doesn’t quite fit the original design you add a hair – a small, subtle detail. It doesn’t detract from the overall purpose of the code, it just covers a specific detail that wasn’t thought of originally. One hair on its own is fine. But then you add another, and another, and another. Before you know it, your clean, shiny code is covered in little hairs. Eventually code becomes so hairy you can’t even see the underlying design any more.

Let’s face it, we’re all basically maintenance programmers. How many of us actually work on a genuinely greenfield project? And anyway, soon after starting a greenfield project, you’re changing what went before and you’re back into maintenance land. We spend most of our time changing existing code. If we’re not careful, we spend most of our time adding new hairs.

The simplest thing

When changing existing code, there’s a temptation to make the smallest change that could possibly work. Generally, it’s a good approach. Christ, TDD is great at keeping you focused on this. Write a test, make it pass. Write a test, make it pass. Do the simplest thing that could possibly work. But, you have to do the refactor step. “Red, green, refactor“, people. If you’re not refactoring, your code’s getting hairy. If you’re not refactoring, what you just added is a kludge. Sure, it’s a well tested, beautifully written kludge; but it’s still a kludge.

The trouble is, it’s easy to forgive yourself.

But it’s just a little if statement

It’s just one little change. In this specific case we want to do something subtly different. It may not look like it, but it’s a kludge. You’ve described the logic of the change but not the reason. You’ve described how the behaviour is different, but not why. Congratulations, you just grew a new hair.

An example

Perhaps an example would help right about now. Let’s imagine we work for an online retailer. When we fulfill an order, we take each item and attempt to ship it. For those that are out of stock, we add to a queue to ship as soon as we get new stock.

public class OrderItem {
    public void shipIt() {
        if (stockSystem.inStock(getItem()) > getQuantity()) {
            warehouse.shipItem(getItem(),
                               getQuantity(),
                               getCustomer());
        } else {
            warehouse.addQueuedItem(getItem(),
                                    getQuantity(),
                                    getCustomer());
        }
    }
}

As happens with online retailers, we’re slowly taking over the universe: now we’re expanding into shipping digital items as well as physical stuff. This means that some orders will be for items that don’t need physical shipment. Each item knows whether it’s a digital product or a physical product; the rights management team have created an electronic shipment management system (email to you and me) – so all we need to do is make sure we don’t try and post digital items but email them instead. Well, the simplest thing that could possibly work is:

public class OrderItem {
    public void shipIt() {
        if (getItem().isDigitalDelivery()) {
            email.shipItem(getItem(), getCustomer());
        } else if (stockSystem.inStock(getItem()) >
                       getQuantity()) {
            warehouse.shipItem(gettem(),
                               getQuantity(),
                               getCustomer());
        } else {
            warehouse.addQueuedItem(getItem(),
                                    getQuantity(),
                                    getCustomer());
        }
    }
}

After all, it’s just a little “if”, right?

This is all fine and dandy, until in UAT we realise that we’re showing delivery in 3 days for digital items. That’s not right, so we get a request to show immediate delivery for digital items. There’s a method on Item that calculates estimated delivery date:

public class Item {
    private static final int STANDARD_POST_DAYS = 3;
    public int getEstimatedDaysToDelivery() {
        if (stockSystem.inStock(this) > 0) {
            return STANDARD_POST_DAYS;
        } else {
            return stockSystem.getEstArrivalDays(this) +
                       STANDARD_POST_DAYS;
        }
    }
}

Well, it’s easy enough – each item knows whether it’s for digital delivery or not, so we can just add another if:

public class Item {
    private static final int STANDARD_POST_DAYS = 3;
    public int getEstimatedDaysToDelivery() {
        if (isDigitalDelivery()) {
            return 0;
        } else if (stockSystem.inStock(this) > 0) {
            return STANDARD_POST_DAYS;
        } else {
            return stockSystem.getEstArrivalDays(getSKU()) +
                       STANDARD_POST_DAYS;
        }
    }
}

After all, it’s just one more if, right? Where’s the harm? But little by little the code is getting hairier and hairier.

The trouble is you get lots of little related hairs smeared across the code. You get a hair here, another one over there. You know they’re related – they were done as part of the same set of changes. But will someone else looking at this code in 6 months time? What if we need to make a change so users can select electronic and/or physical delivery for items that support both? Now I need to find all the places that were affected by our original change and make more changes. But, they’re not grouped together, they’ve been spread all over. Sure, I can be methodical and find them. But maybe if I’d built it better in the first place it would be easier?

A better way

This all started with a little boolean flag – that was the first smell. Then we find ourselves checking the state of the flag and switching behaviour based on it. It’s almost like there was a new domain concept here of a delivery method. Say, instead I create a DeliveryMethod interface – so each Item can have a DeliveryMethod.

public interface DeliveryMethod {
    void shipItem(Item item, int quantity, Customer customer);
    int getEstimatedDaysToDelivery(Item item);
}

I then create two concrete implementations of this:

public class PostalDelivery implements DeliveryMethod {
    private static final int STANDARD_POST_DAYS = 3;
    @Override
    public void shipItem(Item item, int quantity,
                         Customer customer) {
        if (stockSystem.inStock(item) > quantity) {
            warehouse.shipItem(item, quantity, customer);
        } else {
            warehouse.addQueuedItem(item, quantity, customer);
        }
    }
    @Override
    public int getEstimatedDaysToDelivery(Item item) {
        if (stockSystem.inStock(item) > 0) {
            return STANDARD_POST_DAYS;
        } else {
            return stockSystem.getEstArrivalDays(item) +
                       STANDARD_POST_DAYS;
        }
    }
}

public class DigitalDelivery implements DeliveryMethod {
    @Override
    public void shipItem(Item item, int quantity,
                         Customer customer) {
        email.shipItem(item, customer);
    }
    @Override
    public int getEstimatedDaysToDelivery(Item item) {
        return 0;
    }
}

Now all the logic about how different delivery methods work is local to the DeliveryMethod classes. This groups related changes together; if we later need to make a change to delivery rules we know exactly where they’ll be.

Discipline

Ultimately writing clean code is all about discipline. TDD is a great discipline – it keeps you focused on the task at hand, only adding code that is needed right now; all the while ensuring you have near complete test coverage.

However, avoiding hairy code needs yet more discipline. We need to remember to describe the intention of our change, not just the implementation. Code is primarily to be read by humans so expressing the reason the code does what it does is much more important than expressing the logic. The tests only ensure your logic is correct, you also need to make sure your code reveals it’s reasoning.