A lesson for myself: write tests. Really.
As I've noted before, I am sort of a half-hearted user of code testing; I like it, but I haven't internalized it to the degree that I do it all the time, even if it's painful or annoying. Sometimes this bits me on the rear as a learning experience, as happened recently.
I have a Python module for dealing with ranges of IP addresses (often in the form of CIDR netblocks); I wrote it at least six years ago and have used it in various programs ever since. One of its interfaces is a method to add an improper CIDR to an IP address range object, for which the code goes roughly:
def addimproper(self, cidr): (low, high) = convert(cidr, \ improper = True) self.addrange(low, high)
Recently I wrote a program that needed to work with improper CIDRs and so used this interface. Except that it didn't work, and inspection of the IP address range objects showed that they were actually empty.
This was because my code had a bug. Actually reading it showed that
addimproper() was missing the last line, the one that actually added
the IP address range of the CIDR to itself. And this bug was not newly
introduced; it had been there since the beginning, six years ago, when
I wrote this method (and then never used it).
Some people would say that there are two failures here, but there's certainly at least one: I added this interface and then never tested it. Never mind formal tests; I never even loaded the module in the Python interpreter and tested that this method worked and did what I expected. (Given that there are various interpretations of improper CIDRs, both parts are important.)
This will hopefully serve as a salutary and humbling lesson to myself on the merits of writing tests. (Certainly it's been an embarrassing and humbling experience by itself; I just hope that I learn from it in practice, as opposed to just theory. I suppose that a good first step would be to augment the module's existing tests to cover this case.)