<D <M <Y
Y> M> D>

They Have Blogs: He's a Python programmer. She's... also a Python programmer. They have blogs! Also available as one huge barely-differentiated group weblog.

(PS: format taken from They Have Blogs, a web toy of about a year ago).

But It's Transgressive! Yeah, Transgressive.: Rob Walker on Carrot Top:

Perhaps the real message of his work, then, is a critique that makes a mockery not just of the entertainment industry, but of the very notion of meritocracy in America—his success being the most damning evidence to date that the marketplace of talent is a sham.

Another Day, Another Eater of Meaning: 1.2 is up, thanks to some help from Todd and some good old-fashioned elbowgrase (sryy for typos, mt elbowf are slipoery),. It now correctly handles previously troublesome sites like oblomovka.com, zeldman.com, sites with meta redirects, sites with self-closing tags, sites with frames, etc. etc. There's also a new eater which turns a page into lorem ipsum. (Obligatory "meta overload" link)

Crud, it just got linked on MetaFilter. I was going to talk about unit tests but I should work on a cache instead.

Update: OK, much better.

PS: the name "Eater of Meaning" comes from a song I wrote called "Eaters of Meaning". I've had that song stuck in my head for the past 3 days.

The Unit Price: So, with that spot of unpleasantness out of the way, we're free to talk about the really exciting thing: unit tests! I wrote the Eater because I like writing that sort of thing, but also to get into the habit of writing unit tests. Here are my observations on the process:

Before you write code, you're supposed to write unit tests. It turns out I can bring myself to do this most of the time, but I do it grudgingly because I don't like writing the infrastructure for a new type of test. The way I generally do it is to write the tests but leave the expected value for the assertions blank (unless the expected value is really easy to figure out, or is actually defined and not just the result of applying some transform to some data I just made up). Then I write the code and all the assertions fail. I use the code I wrote to figure out what the asserted values should be, fixing bugs as I do, and paste in the final, correct values for later use.

Where unit tests are really great is when you find a bug in your code. If you've put in the work to write that infrastructure for that sort of bug, it's easy to record your finding of the bug in a way that will automatically notify you if it ever shows up again. This is lesson one: unit tests give you a place to codify the results of the debugging process. By putting in some incremental effort you can ensure that you're notified should the bug you're fixing ever recur. Usually it doesn't recur, but your real worry is not the bug recurring; it's the bug recurring without your knowledge. With unit tests, you know.

Sometimes when I refactor code I worry that some portion of the code I never exercise has broken due to refactoring. This is the worst thing about Python: unless you're using Leo (which I'm still not, despite my earlier touting of it), when you refactor the code the indentation changes, and when that happens you have to redo the indentation because the automatic indenter never works right, and all sorts of problems can crop up.[0] Unit tests find the problems, and if there are any you fix them and that's that. Lesson two: with unit tests, instead of worrying about code you broke while refactoring, your mind is free to worry about less rational things, like bloodthirsty packs of feral hamsters roaming the streets.

I have unit tests for all my Eaters, and some decent coverage for the HTML parser, but nothing yet for the user interface (even though I wrote the user interface to be drivable from Python code) or the thing that grabs URLs. This is because of lesson three: the closer a piece of code is to an actual user, a piece of hardware, or data from the outside world, the more aggravating it is to write unit tests for it. I am convinced this demonstrates a close affinity between unit tests and Lisp.

The big wrapper lesson is that unit tests are a way of creating a grammar with which to describe the behavior of the system so that you can offload to the computer the task of checking that behavior. Unit tests are easier to write when the elements of the grammar have simple APIs that you control, and harder to write when the elements are complex things with outside dependencies, like URLs and mouse movements. Even if you only write unit tests for the simple stuff, it means your agonizing over the more complicated stuff will be untroubled by the suspicion that the problem is something lower-level and simple (of course, then it turns out to actually be something lower-level and simple, and the code says "Gotcha!" like Lucky Ducky and struts off, but I can't help you there).

[0] Eventually I'm going to write my own autoindenting Emacs hook which operates on the very simple principle of moving the cursor line to where autoindent takes it, then moving every child line left or right the same number of spaces. I don't know why other indenters have these fancy algorithms that don't work, when that algorithm works fine. With my algorithm you have to go down arbitrarily many lines before moving the first line, to see how many lines are underneath the first one, then go back up to the top and go through all those lines again, but on the plus side it actually works.


Unless otherwise noted, all content licensed by Leonard Richardson
under a Creative Commons License.