Tuesday, 28 June 2011

Evil Developers From The Future Will Get You!

I like my code tested. It's not only because there are important and successful people in the industry that say that's the thing to do. I like my code tested, because I have trust issues. I don't trust other developers, not the people I work with right now, they are all right, but the people who will pick up my code 6 months from now, or even later, when I'm not around. I don't even trust myself from the future, sooner or later all this partying will catch up with me and I'll forget all about the good practices and I'll turn to evil! And evil developers break your application. In my mind there is no such a monstrosity that an evil developer cannot do. They'll remove random lines from your code and make it look like that's a valid re-factoring, they'll change your methods, move your variables, break your functionality, all this while pretending they work for good. And there's only one thing you can do in this situation - you have to show them thy can't mess around with your code and break it without consequences. And the best tool we have for that (besides visiting everybody who ever checked out your code and beating them with a stick) are Real Unit Tests.
Lots of people do unit testing this days. They write some impressive methods that get the job done, and they make sure that with given input expected output is returned. It's very rewarding to see your code working, so usually you see the method main functionality tested properly at least in happy case scenario. But not all the code you write is exciting and interesting. You have to do all the not null and no empty checks, exception handling, input parameters parsing, logging and so on. Nobody wants to test that code. We all know that "every if statement you make is a design error" but sometimes there's no getting away from it I'm afraid, random acts of goodness can't mean re factoring the whole damn app just so you can remove couple of if statements. But surely you don't have to test all of them, right? Consider this method:

public List do(String input){
if(input == null || input.isEmpty()){
return Collections.emptyList();
}
return createResultsListFrom(input);
}

So you passed in proper String input with parameters you'd usually pass into the method. But your line coverage is too low, you never return empty list. So you pass in empty string just to go through the line, you even check if it's an empty list you got back, the line coverage is 100%, your work here is done. Or is it? Imagine 6 months from now, somebody opens the code you just tested and changes it a bit:

public List do(String input){
//null value should cause exception!
if(input == null){
throw new IllegalArgumentExcpetion("panic!");
}
if(input.isEmpty()){
return Collections.emptyList();
}
return createResultsListFrom(input);
}

You can tell it's an evil developer we're dealing with, because they don't even open your unit tests for this class. They just try to build the project. Your tests won't fail, the empty string still gets you an empty list and the happy case scenario didn't change. It could be that you have some classes somewhere depending on the fact that when you pass null to the do method you get an empty list, but the evil developer couldn't care less. They push the change and happily move on to next thing on their to do list. They just broke your code and there was no resistance whatsoever.
Now I hear the "there's no point in testing this simple thing here" argument a lot. Sometimes I hear it in my head, especially on Friday afternoon, when the last thing I want to do is check if the type of Exception thrown by my method is correct for different arguments. But to force myself to go through with it I think about Evil Developers from the future. They're out there to get us all, so we'd better be ready!

No comments:

Post a Comment