Sure, it’s probably one of the meanest spots on the intarweb, but there’s just so many smart people on there. I can get good advice on just about any topic imaginable. Some recent diary posts:
David Stanek wrote a nice utility to measure code complexity. This post explains the details. Anyway, I downloaded his code and tried it out. I really like it:
$ cat matt.py
"""A few functions for use with pygenie."""
def f(x):
"Make an 8-way branch, 1 layer deep."
if x == 1: return 1
elif x == 2: return 2
elif x == 3: return 3
elif x == 4: return 4
elif x == 5: return 5
elif x == 6: return 6
elif x == 7: return 7
elif x == 8: return 8
def g(a, b, c):
"This function has 8 paths."
if a:
if b:
if c:
return 1 # a and b and c.
else:
return 2 # a and b and not c.
else:
if c:
return 3 # a and not b and c
else:
return 4 # a and not b and not c.
else:
if b:
if c:
return 5 # not a and b and c.
else:
return 6 # not a and not b and c.
else:
if c:
return 7 # not a and b and not c.
else:
return 8 # not a and not b and not c.
def h(x):
if x: return True
else: return False
And this is what happens when I run the code:
$ ./pygenie.py complexity matt.py
File: /home/matt/svn-checkouts/cyclic_complexity/matt.py
Type Name Complexity
------------------–
F f 9
F g 8
The functions f and g have a complexity exceeding 7, so they print out.
These four paragraphs have the same number of characters, but because the letter M is fat and the letter I is skinny, different amounts of characters appear in each line:
M M M M M M M M M M M M M M M M M M M M M M M M M M M M M M M M M M M M M M M M M M M M M M M M M M M
I I I I I I I I I I I I I I I I I I I I I I I I I I I I I I I I I I I I I I I I I I I I I I I I I I I
This is the exact same text, but now I’m using a monospace font:
M M M M M M M M M M M M M M M M M M M M M M M M M M M M M M M M M M M M M M M M M M M M M M M M M M M
I I I I I I I I I I I I I I I I I I I I I I I I I I I I I I I I I I I I I I I I I I I I I I I I I I I
March 25, 2008 at 7:22 pm
· Filed under mlp, funny, web
I got a subscription to Backyard Poultry magazine earlier this year. It’s awesome. This month’s issue led me to to the City Chicken website. And that led me to this hilarious video that chronicles one man’s quest to find out if he can raise chickens in Chicago:
Subversion is great and I have been using it for years. But I keep running into the same two problems over and over:
I did a bunch of work and I want to commit it, but I don’t have network access.
I spent a day playing around with a crazy idea, and I want to store my half-finished and buggy work. I don’t want to put it into the trunk because it will break a bunch of other people’s work. I don’t want to make a branch because I find branching and merging again to be tedious.
Both problems could be solved if I could make commits that were local to my hard drive and visible to me only.
Today I spent a few hours on IRC and I found out that bazaar plays really nicely with subversion, and now I have a solution.
First, I loaded my subversion repository into bazaar. Here’s the command I ran:
My subversion repository has 990 revisions. This command took about 3 minutes to finish.
Then I went into the local myproj directory and edited some code. I used bzr status and bzr diff to see what I changed while I worked. They operate nearly identically to their svn counterparts, but bzr diff has no --summarize option.
Committing locally is really simple:
bzr commit -m "This is a local commit and svn won't see it!"
Then I did some more edits and committed those:
bzr commit -m "OK, now maybe I have something that I want to put into subversion."
Before committing to the subversion repository, I pulled down other people’s updates to the subversion repository like this:
Now when anyone runs svn update in their subversion working copy, they will get my work along with my commit comment.
So far, I’m really happy with this set up. The Bazaar-Subversion FAQ had a lot of really useful tips. Finally, there’s still a lot of stuff I haven’t tried yet, like renaming or copying files with svn.
Yeesh. This is akin to a programmer mixing up javascript and java:
Questioned by reporters, McCain continued, adding that it is “common knowledge and has been reported in the media that al-Qaida is going back into Iran and receiving training and are coming back into Iraq from Iran, that’s well known. And it’s unfortunate.”
Then, Senator Joseph Lieberman, who, like McCain is a staunch supporter of the war in Iraq, stepped forward and whispered in McCain’s ear.
McCain then said, “I’m sorry, the Iranians are training extremists, not al-Qaida,” the Washington Post reported.
As near as I can tell, looking up a string inside a set is effectively free.
I made a 9000-element set, where each element is foo_0, or foo_1, foo_2, … , on up to foo_8999. Then I measured the time cost of testing whether an element belongs to that set:
$ python -m timeit -s 's = set(["foo_%s" % i for i in range(9000) ])' '"foo_4500" in s'
1000000 loops, best of 3: 0.447 usec per loop
Next I measured a few scans across a list of the same size:
$ python -m timeit -s 's = ["foo_%s" % i for i in range(9000) ]' '"foo_0" in s'
1000000 loops, best of 3: 0.447 usec per loop
$ python -m timeit -s 's = ["foo_%s" % i for i in range(9000) ]' '"foo_1" in s'
1000000 loops, best of 3: 0.659 usec per loop
$ python -m timeit -s 's = ["foo_%s" % i for i in range(9000) ]' '"foo_900" in s'
10000 loops, best of 3: 130 usec per loop
$ python -m timeit -s 's = ["foo_%s" % i for i in range(9000) ]' '"foo_4500" in s'
1000 loops, best of 3: 631 usec per loop
It takes more time to do to two string comparisons than it does to hash the string and look it up in the set.
These are a few of the rules I try to follow in my design. So far, they’ve helped me out.
I aim to finish all interaction with the database before I get to the template layer.
This is non-trivial because it is so easy to forget that a method or an attribute will evaluate into a query. I use this rule because it lets me be certain about the number of interactions each page will have with the database.
I avoid branching (if-else clause) in my templates as much as possible.
I have a really hard time detangling code when I find a bunch of nested if statements. For all but the most trivial instances, I prefer to have a bunch of similar templates and then choose the best one. For example, instead of handling both a successful login and a failed login in a single template, I’ll make two different files and then choose the right one in my controller.
In practice, I have some really similar templates. But then I go back and strip out as much of the common code as possible and put those into widgets.
Any time I find a select() call in my controller, I consider making a new method in my model.
When I write something like this in a controller:
bluebirds = model.Bird.select(Bird.q.color == 'blue')
I usually come back later and put in something like this into the Bird class:
class Bird(SQLObject):
color = UnicodeCol()
Now I have something that I can reuse. If I’m feeling whimsical I’ll use functools.partial to do something like this:
class Bird(SQLObject):
color = UnicodeCol()
Sidenote: I couldn’t figure out how to use the @classmethod decorator in the second version of by_color because partial complained. Appararently, callable(some_class_method) returns False, and partial requires the first argument to be a callable.
Maybe a reader can explain to me what’s going on there…