Sponsored Link •
|
Summary
Passing null into methods is considered bad practice, but sometimes it can be very powerful.
Advertisement
|
When I was in school, I had a great calculus teacher. He knew how to spin off memorable phrases, phrases that made learning fun. Some of them have stuck with me to this day. For instance, one day he was going over a problem and he pointed out that if we were not careful we'd end up dividing by zero. "Dividing by zero", he said, "isn't that like violating the virginity of algebra?"
I used to think of that phrase whenever I saw a line of code like this:
new ADBDocument(null, defaultSize, palettes[n]);
Passing null isn't quite the same as dividing by zero, but it often conjures up the same feeling, that feeling that something is wrong, that we have to re-think something. If you are lucky, you already know that passing null is a bad idea. If you're not, you probably have an incredible amount of checking code in your code base. "Is this reference null? Yes? Okay, I have to throw an exception. No? Okay, I can actually use it."
If that's been your experience, you should stop passing null into methods. Me? I do it relatively often, and I don't really care about writing checking code when I do it either.
Shocked? Well, like everything else in life, context is important. I don't pass null in production code, I pass it in tests.
Let's look at an example. We need to test the paginate() method of a class named ADBDocument. ADBDocument has a single constructor which accepts three parameters:
public ADBDocument(ToolFactory factory, int initialSize, TypePalette palette) { ... }
How many of these parameters are really needed to test paginate()? You don't know? Well, neither do I really. But, I know that I can write a test like this:
void testConstruct() { new ADBDocument(null, 0, null); }
and find out very quickly. If the parameters are really being used, I'll get a null pointer exception. If they aren't, I may very well get a nice live object that I can use when I start writing my paginate() tests:
void testPaginateSingle() { ADBDocument doc = new ADBDocument(null, 0, null); doc.setText("\n"); doc.paginate(); assertEquals(1, doc.pageCount()); }
This trick works well in most languages. The key to using it well is noticing that triggering exceptions when we are writing tests is no vice. If we trigger an exception, the test harness will catch it and we will learn something new about the code we are working with. If you work in a language whose runtime does not throw exceptions on a null dereference, this technique isn't very useful. Fortunately, runtime support is adequate in most languages.
Passing null is not a panacea. Most of the time, we do need fake or mock objects when we are trying to get older classes under test. But, there are cases where it makes it easy to get some quick tests in place, cases where fakes or mocks would be superfluous.
If you want to see some more Pass Null scenarios, take a look at Sally and Ramon's experiences with it.
Have an opinion? Readers have already posted 10 comments about this weblog entry. Why not add yours?
If you'd like to be notified whenever Michael Feathers adds a new entry to his weblog, subscribe to his RSS feed.
Michael has been active in the XP community for the past five years, balancing his time between working with, training, and coaching various teams around the world. Prior to joining Object Mentor, Michael designed a proprietary programming language and wrote a compiler for it, he also designed a large multi-platform class library and a framework for instrumentation control. When he isn't engaged with a team, he spends most of this time investigating ways of altering design over time in codebases. |
Sponsored Links
|