Sponsored Link •
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.
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.
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,
Andy Hunt and Dave Thomas are authors of The Pragmatic Programmer, which is available on Amazon.com at:
The Pragmatic Programmer's home page is here: