Student Login

Assertive assertions

A quick defensive coding lesson:

For a webapp I was coding recently, I wrote a little helper function to convert dollar-cent ints into a specifically formatted string:

  1. def dc2amount(dollars, cents):
  2. 'Convert (dollars, cents) to formatted "amount" string'
  3. assert dollars >= 0, dollars
  4. assert cents >= 0, cents
  5. if dollars == 0:
  6. return f'{cents:02}'
  7. return f'{dollars}{cents:02}'

The format is just what some API needed - that doesn't matter.

But look at the assert statements.

You see, when coding this function, I realized it should only ever be called with non-negative values for dollars and cents.

But I realized that if that was not true, it may result in a tricky bug.

So even though I could not imagine any way that those numbers could be negative... I started that function with a couple of assertions.

Because just because I can't imagine something will happen, doesn't mean it will not.

Proactively using assertions like this has two benefits:

First, once in a while, it'll save you a lot of time.

Because the assertion fails. And when you get over your shock, you can quickly adapt the code.

So that instead of scratching your head deciphering some massively baffling monster of a bug...

It immediately and loudly told you, in no uncertain terms: the assumptions you made for this function are not, in fact, legit.

The other benefit:

It forces you to be clear on what your assumptions are.

You have to decide: what are the bounds, exactly, for this "dollar" variable? Is 0 an okay value? Why or why not?

And then you explicitly document it for yourself, and everyone else, in a way that's impossible to miss.

And since I know some of you will ask:

This nearly never affects performance. Asserts are cheap. If you're not 3 or 4 levels deep in a nested "for" loop, don't ever worry about it.

See how you can start using defensive asserts in your code. I think you'll like it.

Newsletter Bootcamp

Book Courses