Using Assertions

Bill Venners: You write in your book, "Don't use assertions in place of real error
handling. Assertions check for things that should never happen." Can you elaborate?

Andy Hunt: You shouldn't use assertions to validate user input, for instance, or for
general errors. Say you are doing some systems programming on a Unix platform, for
example, and you are about to check the return value of opening /etc/passwd. We could
probably debate about this, but I would think that would be more a class of assertion,
because /etc/passwd should be there. It can never happen that that file is not there. OK, there
are some extreme cases where that file may not be there, but it means something really really
bad is going on. I would be inclined to say that's not traditional error handling, because that
could "never happen." Now, if you're just looking to go open some properties file, or some
file the user told you to go open, that's just normal error handling. The file may be there. It
may not. It doesn't fall into the class of can't ever happen, so it's not an appropriate use for
an assertion.

Bill Venners: What are the benefits and costs of using asserts?

Andy Hunt: There is a great anecdote from a small company that was making
network diagnostic software. This company had a very strict policy about asserts. They
asserted just everything—everything that could go wrong, that they thought might be a
problem. They had tons and tons of asserts. And what made them different from other
companies was they left in all of the asserts in their shipping product.

This was a real-time sensitive application. It wasn't just a report writer. This was
time-critical network monitoring software. They left all the asserts in, to the point where if
something managed to get through testing, and produced an error out in the field, they
would actually put up a nice warning to the user saying, "Here's some information. We need
you to call up and get tech support, because something bad happened."

And as a result of leaving all these assertions in, getting that feedback loop all the way
out to the end user for the few bugs that did escape testing, they had a nearly bug-free
product. They did so well they got purchased by some other software company for about a
billion dollars. So as far as cost versus benefit, ...

Bill Venners: It sounds like they got about $1000 per assert.

Andy Hunt: Yeah, whatever the asserts cost them, their company got purchased for
a huge amount of money. They did very well.

Dave Thomas: So let's look at the cost of actually writing an assert. There are two
aspects to actually writing an assert. One is, you have to think about what you want to be
true at this point in the code. Secondly, you have to find a way to express it. Finding out
what you want to be true at this point in the code is in my mind the definition of
programming. That's exactly how you write a line of code. You must ask, "What change do
I want to make in the state of the world in this line of code?" So you have to have answered
that question anyway if you're programming correctly. And people who say, "Oh, I can't
work out what an assertion would be at this point," aren't programming. You should be able
to know what assertion to put at any point in your code to verify that what you've just
written does what you think it does.

Andy Hunt: You have to clarify your assumptions. To me, you can't use the word
assertion without having the word assumption real close to it. Because with everything we
program we've got this huge raft of assumptions in our mind—"Of course this must be like
this. I know the state of this is set, and I'm about to do this." You've got this whole raft of
assumptions. What you have to do is just take those assumptions, or some subset of those,
and put that into an assert. I want to make sure that my assumption really does hold.

Bill Venners: In your book you say, "Whenever you find yourself thinking, 'Of
course that could never happen,' write code to check it." Personally, I feel the urge for an
assertion when there's enough complexity, for example, if there are several methods that
must work together to keep something true at this point in this method. I think it works, but
I'm not 100% confident I fully grasp the complexity. And I'm not confident that although it
may work now, the people making changes over time may not grasp the complexity
sufficiently to avoid breaking it in the future. That's when I feel the urge to put in an
assertion.

Dave Thomas: That's really an interesting observation. I would say that there are
many people who do that. I do the same myself, in particular if I'm doing something that is
full of off-by-one boundary condition issues. I will put asserts in there just to check
boundary conditions. Invariably, what it really means is I don't understand what my code is
doing. So I put the asserts in there because I think I understand, but I don't really
understand, what the code is doing. So I'll let some user check it for me. Whenever I find
myself putting in asserts to try and clarify something, then I try to use that as a little warning
bell that I should step back, simplify the code so I can understand it, and then put decent
asserts in.

The other side of the coin is this. When we say in the book, "Whenever you find yourself
thinking something can't happen, put asserts in," that could be misunderstood. We're not saying
you have to assert everything. We're trying to undermine the kind of arrogance of the
attitude, "I've just written this. It can't go wrong." Clearly there is code, setter and getter
methods for example, where there is zero point in doing asserts just as there is zero point in
doing unit testing. But it's more the case that this can never happen, because this file must
exist. This socket must be open. This parameter must be greater than zero. Those are the
ones where maybe that arrogance isn't quite appropriate.

Bill Venners: That makes sense. What you're saying is in the areas where I do feel
confident, don't be so sure of myself.

Dave Thomas: Exactly.

Bill Venners: In areas where I'm not sure of myself, take that as a red flag that I
should maybe try and simplify and clarify the code.

Dave Thomas: Yeah.

Andy Hunt: The other related topic is, in other engineering disciplines, bridge
building for example, they are much more focused on what can possibly go wrong.
Unfortunately, we have a tendency when we're writing software to focus on trying to find
that one path through that will go right. And that's a very different focus. And we get so
focused on finding that one path through that might work right, we tend not to spend so
much time thinking about the 100 million things that could go wrong. And that's where you
get all these errors that we don't trap, assumptions we don't check, boundary and edge
conditions we don't deal with properly. That really is what makes the difference between a
good programmer and a bad one. The good programmer tries to think of and deal with all
the things that can go wrong.

Next Week

Come back Monday, May 5 for Part X of this conversation with
Pragmatic Programmers Andy Hunt and Dave Thomas. If you'd like to receive a brief weekly email
announcing new articles at Artima.com, please subscribe to
the Artima Newsletter.

Talk Back!

Have an opinion about assertions, crashing early, or the appropriate level of confidence to have in the code you write?
Discuss this article in the News & Ideas Forum topic,
Programming Defensively.