Software: December 2007 Archives

 

December 28, 2007

Just paid a traffic ticket (see here) via Santa Clara county's not very impressive IVR (amazingly, there is no Web system). Among the high-tech features:
  • Extreme amounts of clipping and distortion to the extent to which you can only understand about 3/4 of the prompts. It's strangely inconsistent—some of the prompts sound fine, but some are almost incomprehensible.
  • The interface for entering your citation number and your last name is pretty bad. Say your citation number is H01234. First it asks you if there are any letters. Then it asks you to key in the letter, then prompts you for each possible letter on the number key. Then it asks if there is another letter. If not, it asks you to key in any numbers there are. Then it asks if there are any letters. Repeat. I'm not sure this is actually the IVR's fault, but rather that they have to deal with tickets from a wide variety of jurisdictions. Still, there seem like a bunch of ways to make this better (standardize citation numbers, add a jurisdiction/format code so that the format is predictable, etc.)
  • After you've paid your fine, it gives you a (really long) receipt number and then asks you to press one to repeat, two to continue. If you press two, it asks you to key in your citation number. I assume you're done at this point and can hang up, but if not there may soon be a warrant out for my arrest.

Oh, there's also a $12.95 "convenience fee" for using this system to pay your fine by credit card.

 

December 2, 2007

I spent yesterday at the IETF coding sprint. The idea here was to rewrite a bunch of the IETF software tools in a more modern system (Django), as well as write a bunch of new tools. I'd never worked with Python or Django before—other than writing test programs—but that didn't stop Cullen Jennings and I from trying to write an IETF charter management tool (still in development). Some initial notes after 15 hours or so of screwing around:

  • This kind of framework really does let you get an app up and running quickly. I figure I could have gotten slightly more done working directly in CGI and Perl, but when you factor in that I didn't really figure out how to get Django to do anything useful until about 3:30, Django seems to come out pretty far ahead.
  • Django embeds a lot of data in the URL itself rather than in arguments. The way this works is that there is a map table from URL patterns (regexes) (Jamie Zawinski, call your office). So, you get something like this:
            (r'^(?P[a-z0-9]+)/$',views.current),
            (r'^(?P[a-z0-9]+)/all/$',views.list),
            (r'^(?P[a-z0-9]+)/fake/$',views.fake_wg),
            (r'^(?P[a-z0-9]+)/add/$',views.add),
            (r'^(?P[a-z0-9]+)/$',views.current),
            (r'^(?P[a-z0-9]+)/all/$',views.list),
            (r'^(?P[a-z0-9]+)/fake/$',views.fake_wg),
            (r'^(?P[a-z0-9]+)/add/$',views.add),
    

    So, looking at the first of these lines, it says that any URL that matches the pattern ^(?P<wgname>[a-z0-9]+)/$ gets handled by the function views.current and the first parenthesized match gets passed as an argument via a parameter named wgname. This is clever, but kind of weird, especially when you realize that these expressions are evaluated in sequence, so there's a chance for collisions. I got bitten by this once already.

  • It's great to have automated mapping from data types to database schema, but it would be a lot better if it could hide the behavior of the relational DB a little better. To take an example, when you want to have a many-to-one mapping, (e.g., cards -> deck of cards), you use a "foreign key", like so:
    class Deck(models.Model):
          brand = models.CharField(max_length=20)
    
    class Card(models.Model):
          suit = models.CharField(max_length=10)
          value = models.IntegerField()
          deck = models.ForeignKey(Deck)
    

    Thinking about this as a data structure, this does two things, one obvious and one unobvious:

    • Create a pointer from any given Card object to the deck it belongs to. This is the forward mapping you'd expect since it's explicitly declared in Card
    • Create a slot in the Deck class called card_set which contains pointers to all the Card objects that belong to the Deck. This is fairly unobvious, since it's not explicitly declared, it just happens automatically.

    Of course, these aren't just data structures; they are mapped to underlying stuff in the database, so this creates some weirdness. To give you an example, I spent about 30 minutes trying to figure out when I created a Deck and then inserted a Card (ok, not really, but analogous structures), I ended up with null pointers in both directions. It turns out that you need to do a save() of the container (Deck) before creating the contained object (Card), otherwise it ends up pointing at nothing. I don't really know why—SQL experts should feel free to tell me—and ultimately had to have Fenner tell me how to make it work.

  • It's pretty clear that there are sophisticated and arguably elegant ways to do jobs (e.g., rendering HTML), but I don't know any of them, so I end up just doing things crudely, hardwiring forms into the HTML, etc. Probably if I were going to really work on this kind of stuff regularly, that would be worth learning.