Stop fixing it already…

 photo MicrosoftFIX_IT_zpsoqz3jnck.pngOver in Fix it twice? I discussed why a second attempt at fixing an issue, to use hindsight of an actual fix as a way to improve the software, was a great idea. In this piece, I’d like to discuss the aim of bug fixing.

Why do we fix bugs?

Is it to make the error go away?

Well, kind of, but that’s only part of the story. The aim of fixing a bug is:

  • Make the software work
  • Fix the thing which caused the bug (which can be software, or process, or communication etc)
  • Make it harder to repeat the mistake

I don’t want software with fixes in, I want software without issues. I don’t want issue resolution, I want it to be hard to make that issue occur again.

Removing the source of a mistake and being mistake-proof are two sides of the same coin. However, it seems to be against human behaviour to fix the cause, rather than the side-effect of a bug, and it seems to be hard, sometimes, to identify the cause as something that can be mistake-proofed in future.

Here’s an example:

public class RouteSoFar {
    private final List<String> streetsVisited = new ArrayList<>();

    // adds the street to the route
    public void visitStreet(String street) {
        streetsVisted.add(street);
    }

    // get a fresh copy
    public RouteSoFar makeCopy() {
        RouteSoFar copy = new RouteSoFar();
        copy.streetsVisited.addAll(this.streetsVisited);
        return copy;
    }

    // show route
    public String getRoute() { ... }
}

In the above class we have an object that’s tracking a route by accumulating streets. Maybe the idea is to print out some routes to interesting stores radiating out from an initial street. In fact, that’s a nice algorithm to write.


    StreetMap streetMap = new StreetMap("Bordeaux");
    Street firstStreet = streetMap.get("Rue De Winston Churchill");
    RouteSoFar routeSoFar = new RouteSoFar();
    printRoutesToStores(firstStreet, routeSoFar);

    ...

void printRoutesToStores(Street currentStreet, RouteSoFar routeSoFar) {
    // we're now on this street
    routeSoFar.visitStreet(currentStreet.getName());

    // print interesting stores on this street
    currentStreet.getStores().stream()
        .filter(Store::isInteresting)
        .map(store -> store.getName() + " is at " + routeSoFar.getRoute())
        .forEach(System.out::println);

    // and recurse to all neighbouring streets
    currentStreet.getNeighbours().stream()
        .forEach(neighbour -> printRoutesToStores(neighbour, routeSoFar));
}

Ignoring for a moment the fact that the neighbouring streets could easily give us one of the streets we came from (let’s pretend it’s rigged not to) the above code looks like it will work, but won’t. You’d find out if you ran it that the routeSoFar doesn’t contain the route to the store, but instead is polluted with any street it’s visited. This is because it’s a mutable object and is shared between layers in the hierarchy of the program.

Ah. So that’s why there’s that makeCopy function, a kind of clone method, then? Do we just change one line?

    // replace this
    currentStreet.getNeighbours().stream()
        .forEach(neighbour -> printRoutesToStores(neighbour, routeSoFar));

    // with this
    currentStreet.getNeighbours().stream()
        .forEach(neighbour -> printRoutesToStores(neighbour, routeSoFar.makeCopy()));

}

It’s probably clear by context, that the answer I’m aiming for is no. If you’re pedantic enough to debate that it’s yes, then I applaud you. In this instance as written, yes would be fine… but then what?

In a real life project, I got into the habit of fixing bugs like the one above on a class with a similar purpose to the one above, by remembering to do that thing… Yes, if you’ve got this mutable object and it might travel beyond the method that owns it, then it might be better to send a copy, not the real thing.

How many times do you need to apply that fix to a piece of code before you realise you need to make it mistake proof?

The problem the above has is that it’s a mutable object being used naively by multiple parts of the program. If it were immutable, then you would have to knowingly change it, and you couldn’t accidentally have your copy changed. It’s a reversal of the paradigm, and the side effect is that the thing you’re interested in becomes slightly more conscious a thing to do, and the thing you don’t want to happen become impossible to do accidentally.

Here’s the same Route class made as an immutable object. I think you can see how it might be used.

// immutable pojo - no setters, but can be transformed into a new immutable pojo
public class RouteSoFar {
    private final List<String> streetsVisited = new ArrayList<>();

    // adds the street to the route and returns a new object
    // so you store the reference to that if you want to keep it
    public RouteSoFar havingVisitedStreet(String street) {
        // rather than have a clone method, we innately create a copy 
        // of this, modify that and return IT
        RouteSoFar newRoute = new RouteSoFar();
        newRoute.streetsVisited.addAll(this.streetsVisited);
        newRoute.streetsVisted.add(street);
        return newRoute;
    }

    // no need for a copy/clone method

    // show route
    public String getRoute() { ... }
}

Philosophically, this is what bug fixing is – finding a mistake and eradicating it. However, spotting an opportunity to remove the opportunity for future errors of the same sort is a ninja trick. Use it!

Advertisements

Software developer, stand-up comedian, musician, writer, jolly big cheer-monkey, skeptical thinker, Doctor Who fan, lover of fine sounds.

Posted in Uncategorized

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: