Test-driven-development can be labor intensive

I wanted to add a list of checkboxes to the “create employee” and “edit employee” pages. Each checkbox adds that employee to a group, and each group has certain privileges. Really standard stuff. I wrote the code in my controller and template in about 20 minutes

Then I played around with the new pages in my browser to check for obvious errors. I created some employees, monkeyed with their groups, then saved them, then opened up the edit screen, verified everything worked right, then monkeyed with them some more, and so forth. That probably took 5 minutes of clicking around lazilly.

In the past, that’s when I would have committed the code to the repository and moved on to something else. I played with it, it didn’t break, so we’re done. Total dev time: 30 minutes.

This time, I wrote a series of twill scripts to go through the different combinatorials of users and groups.

For example, if I have groups A and B, I would really test creating 4 different employees:

  • new user with no group membership
  • new user in group A
  • new user in group B
  • new user in groups A and B

After each creation, I verify that the page displays the data correctly and I then hit the database and make sure that everything is set correctly.

For the screen that allows editing employees, the most thorough possible test would take those four new employees and loop until each has been changed to every other possible configuration.

This took about another two hours by the time it was done. The next time I have to write code like this, it will be much faster because I figured out how to write code that yields tests iteratively. Using TDD, total dev time hit about 2.5 hours.

So, in this particular case, is it worth it?

Here’s the reasons why I would say that it was worth it:

I’m still learning how to write good tests. Writing thorough tests requires a different mindset, for me anyway. If I wait until I face some really gnarly complex code to write tests, I’m likely to write some crappy incomplete tests. Each test I write makes me faster at writing tests. Also, when I’m regularly writing tests, I write application code with testing in mind. I think more about design and protecting against what could go wrong, rather than just reaching the finish line any way I can.

And here’s the contrarian view:

Time is scarce and writing tests takes time. In a time-constrained environment, writing needless tests is as silly as blowing off real work to write blogs.

I’m not sure which voice in my head I will listen to on this one.

MVC Blasphemy

I just put HTML code into my data model. I have a list-of-objects page. Each object is an instance of an object defined in my data model, derived from a row in a database. Each object needs a pretty link drawn that object’s detailed-view page. So I added a property on my object:
class Message(SQLObject):
def _get_view(self):
"Draw a link to the view page for this message."
return cElementTree.XML("""VIEW""" % self.id)
# Lots of other stuff snipped out.

This is now what my kid template looks like:

MESSAGE STUFF

I pass in messages and columns; messages is a list of objects and columns is a tuple of strings that map to attributes or properties, like “view”.

I’m happy with this decision. I know I could have manipulated the messages or created some new classes in my controller, but I couldn’t really see any advantage. This way works.

I just don’t want anyone else doing this 🙂

Don’t put parentheses around your assert expressions and the error string!

I had a bunch of unit tests that were passing even though I knew they should be failing. I traced it down to the fact that I put parentheses around my assert statements because the tests were really really long and I wanted to put the error string on a separate line.

This is what I spent the last 45 minutes trying to figure out:

>>> assert 1 == 0, "OH NOES"
------------------------------------------------------------
Traceback (most recent call last):
File "", line 1, in
AssertionError: OH NOES

>>> assert (1 == 0,
... "OH NOES")

>>> assert (1 == 0, "OH NOES")

>>>

The assertion doesn’t raise because I suspect that the assert evaluates each element in the tuple separately, and the string returns True.

And these don’t work, but for different reasons:

>>> (assert 1 == 0, "OH NOES")
------------------------------------------------------------
File "", line 1
(assert 1 == 0, "OH NOES")
^
SyntaxError: invalid syntax

>>> assert 1 == 0,
------------------------------------------------------------
File "", line 1
assert 1 == 0,
^
SyntaxError: invalid syntax

Dangit.

Review of Wicked: The Life and Times of the Wicked Witch of the West by Gregory Maguire

Wicked: The Life and Times of the Wicked Witch of the West (Harper Fiction)

I started out loving everything about this book. Elphaba’s (the wicked witch) childhood and youth and adolescence are a beautiful coming-of-age story about a girl coming to terms with being obviously different than everyone else (she’s bright green). Then Elphaba goes off to college, where the story just keeps getting better and better, until Elphaba and her friends go to the weird trippy night club where a bunch of really far-out stuff goes down. Then in the next chapter, we skip forward a few months, the tight clique has disintegrated, and all the characters have been permanently changed and disconnected from each other.

I spent the rest of the book hoping we’d get some explanation for what happened, but we never go back. We never get any details about that night, only a few cryptic elliptical references. Instead, the story follows a monotonic downward trajectory towards an end everyone already knows is inevitable. This is a major bummer. By the end of the book, I was just glad the story was finished.

Finally, almost all the interesting plot and action and characters have nothing to do with the Dorothy plot line. By the time Dorothy and the Wizard show up in any meaningful way, the book is almost finished. I suspect McGuire is a closeted fantasy writer, but ashamed of it because of his “real literature” aspirations. McGuire only transplanted his story into the Oz universe as a marketing gimmick and/or post-modern commentary.

In the end, this book has a lot of the traits that make Harry Potter appealing: it reclaims the fantasy genre from the Dungeons and Dragons geek domain and the characters deal with problems that are at once alien and also very human.

Here’s a pretty Amazon link that includes my referrer ID:

Final harvest from the garden for 2007

On Saturday, December 15th, I pulled up the last row of carrots from the garden. I had set up my cold frame around them about a month ago, when the snow started falling. The cold frame is really just a big wood box with heavy-duty cellophane across the top. It works like a miniature greenhouse, and it keeps the snow off my plants. So, it let the carrots grow for another month when everything else had frozen.

Anyway, here’s a few pictures. This one shows the carrots before getting washed:

Photo0255.jpg

After scrubbing the dirt off, they look like food:

Photo0268.jpg

And in this picture I lined them up like little people.

Photo0281.jpg

I set the oven to 400 degrees, sliced all the carrots into little discs, tossed them in lots of olive oil, salt, pepper, and thyme, then spread them out over a cookie sheet. Once the oven was ready, I put the cookie sheet in and set the timer for an hour. Then I went outside to shovel my driveway.

By the time I finished shoveling snow, the carrots were ready. I ate all of them while standing over the sink. They were so delicious I couldn’t stop eating in order to take any pictures.

I have more gardening pictures on flickr, including a lot more carrot pics.

Ubuntu Gutsy twill package breaks the showforms command

On one computer named snowball, I installed the ubuntu twill package, then tried to test my webapp:

$ twill-sh -u http://coleridge:8181/login2
==> at http://coleridge:8181/login2

-= Welcome to twill! =-

current page: http://coleridge:8181/login2
>> showforms
current page: http://coleridge:8181/login2
>> show




Login 2

Login 2



current page: http://coleridge:8181/login2
>>

The page clearly contains a form, but twill’s showforms command doesn’t display it. Fortunately, I found this post on the twill mailing list and so I didn’t waste too much time scratching my head. Then on this other box, coleridge, I installed twill using easy_install, and all was well:

$ twill-sh -u http://localhost:8181/login2
==> at http://localhost:8181/login2

-= Welcome to twill! =-

current page: http://localhost:8181/login2
>> showforms

Form name=login2 (#1)
## ## __Name__________________ __Type___ __ID________ __Value__________________
1 user_name text (None)
2 passwd password (None)
3 1 None submit (None)

current page: http://localhost:8181/login2

Sidenote: snowball is my new computer. She is a beaut; a 600mhz Compaq Presario with 60mb of ram, and a hard drive that makes clicking sounds when anything happens. I think Clinton was still in office when she was manufactured. I’d like to thank my son for helping decorate her with some very cool Godzilla stickers.

Photo0250.jpg

Installing on such an old machine meant I had to monkey a fair amount with some kernel modules, which is always a blast, and I am now much more aware of how much every program really costs in terms of CPU utilization and memory footprint.

Funny comic about python

This about sums up my experience:

XKCD Python comic

Absurd nitpick: I’m not a fan of modules that execute code on import. I would prefer that importing antigravity doesn’t automatically do anything, and if I want to use antigravity, then I have to call a function or something like that.

My .screenrc is a testament to obsession over meaningless details

Most every time I start a new screen session, I set up four windows using particular window names. After several hours of reading the screen man page and trying stuff out, I discovered how to automate the process. I added this section to my .screenrc:

screen -t ipython 0 /usr/bin/ipython -p matt
screen -t code 1 # This is where I use vi.
screen -t psql 2 /usr/bin/psql -U mydbusername mydb
screen -t irssi 3 /usr/bin/irssi

You can use the -c option when you start screen to specify a file other than $HOME/.screenrc. So I might write a bunch of different .screenrc config files and then I can choose what ever one I want. I can already imagine a .screenrc customized for doing python work, and another one customized for writing rants, and another one for doing sysadmin work.

A few other useful screen options:

  • screen -S sessionname will start a screen session and name it sessionname.
  • screen -ls will list all the screen sessions already running. Those session names are helpful in this case.
  • screen -r sessionname will attach a screen session that you specify.