Blue Sky On Mars

Thoughts on Building Software Products

Month: July, 2008

iPhone 2.0 apps and synchronization

by Kevin Dangoor

I’ve installed a number of iPhone applications, some of which I’m already using quite regularly. Unlike Apple’s own applications, third party apps cannot synchronize data via iTunes. That’s a real shame, given that Apple clearly has built support for such a thing. It’s possible that iTunes itself is not set up to handle third party sync while still ensuring that Apple controls what’s getting synced to where. Whatever the reason, developers have had to come up with their own means for syncing data between desktop and phone.

To make matters worse, the SDK has been available only under NDA all of this time. So, developers couldn’t even go into much detail with each other about how they were handling their sync functions, let alone actually sharing useful framework code.

My first synchronization experience was with OmniFocus. You could either sync via MobileMe or via your own WebDAV server. I don’t need MobileMe’s services, so $99/year simply wasn’t worth it. I set up WebDAV on my hosting server (which proved to not be very difficult), and sync works.

But, it’s slow. Agonizingly so (though there may be a temporary solution to this). On my computer, I don’t really notice, because my computer can do more than one thing at a time. Not so with the phone. I can do other stuff with OmniFocus while sync is going on, but I can’t use other apps.

So, OmniFocus’ sync is either a pain to set up and slow, or will set you back $99 a year.

Intriguingly, OmniFocus will transfer synchronization settings from your computer to your phone via wifi and Bonjour. It’s super simple to use and quick. Why didn’t OmniGroup just use that as the sync mechanism for the data? That would have saved a lot of pain for a lot of people.

I’ll grant that they can have a somewhat more transparent sync process now, but I’d much rather have a quick (with no wacky setup and no $99/year) manually-started sync process. It turns out that OmniGroup is working on this.

It also turns out that the free new 1Password application for the iPhone does its sync in just that way. They’ve even got high-quality security checks to ensure that people can’t hijack your synchronization session while you’re trying to set it up. 1Password is different from any other password manager I’ve used, but I will say that these guys have definitely thought through the many wrinkles of convenient password management. Let’s hope that iPhone 2.1 includes copy-and-paste so that you can copy passwords out of 1Password and into Safari. (Right now, they have their own little browser, since there’s no way to copy passwords out.)

If you find yourself writing an iPhone app that you want to sync up with a Mac app, please consider the wifi+Bonjour, manually-started synchronization route.

links for 2008-07-30

by delicious

Thanks to Mark for channelling me at PyOhio

by Kevin Dangoor

I had lunch with Mark Ramm-Christensen today, and he gave me the scoop on PyOhio which was last Saturday. It sounds like a good time was had by all. Mark guessed there were 80 people there, which is a good turnout for a regional event like PyOhio! Congrats to the organizers! It sounds like you did quite a job getting the word out and building the turnout.

I couldn’t be there because my daughter’s 5th birthday party was on the same day. Thanks to Mark, my Paver talk happened at PyOhio anyhow. He had the tough 2:30PM timeslot. If you’ve ever given a talk or sat through a talk at 2:30, you’ll probably remember that as “siesta time”. Everyone’s energy level tends to be very low at that point of the day.

So, thanks everyone for learning a bit about my new little project and to Mark for presenting my talk at that time and keeping the energy up.

links for 2008-07-29

by delicious

links for 2008-07-26

by delicious

Nose and Decorators: be careful!

by Kevin Dangoor

One theory of unit testing is that your tests should all be entirely independent. I’ve heard that Google actually has a test runner that randomizes the order of the tests on each run, so you’re guaranteed that they’re independent (otherwise they fail).

I want my test files to be independent, but I find that having one test lead into another is often a good way to reuse fixture and avoid making my test fixture more complicated than it needs to be.

Nose (and py.test) make this really easy, because they run the tests in the order in which they appear in the file. (Note that if you’re using Nose to run unittest.TestCases, those tests still run alphabetically as they do under Python’s built-in test runner). The file order running of tests is very natural and leads to few surprises. It’s very easy to make a string of tests that build up a nice, complicated fixture testing little pieces as they move along. I’ll mention that most of my tests will actually run just fine in any order, but I like being able to count on the order when it’s handy to do so.

All of that is a lead-in to my fun from today. I’m using Fuzzyman’s Mock module to drop in stand-ins for things that are annoying to test. Mock comes with a handy @patch decorator that will replace the callable of your choice with a Mock on the way in, and restore it automatically on the way out. It works great and is really easy to use.

I was thrown off for a bit today because I put a @patch on one of my test functions, and it started failing because a file that it expected to see did not exist! Removing the decorator brought the file back. That file was created in a test function earlier in the file.

If you’re nodding knowingly at this point, you’ve probably worked with decorators a fair bit before. I’ve been known to use more than my fair share of decorators. I’ve found that while the syntax is great, some of the side effects can be really annoying. That’s why Paver‘s decorators aren’t true decorators. They just register behavior rather than replacing the function object.

So, what’s the relationship between using a decorator and the file-based ordering of tests? To sort by file order, Nose looks at the test function’s func_code.co_firstlineno. In the case of ,my test today, that was around 250. However, when I applied the patch decorator, the function was no longer my original function… it was the function that Mock’s decorator returned (the one that does the nifty swapping in and out of the Mock). That was around line 97 of mock.py.

When Nose went to sort the functions by func_code.co_firstlineno, after decoration my test function was thought to be at line 97. I naively thought that I’d just change func_code.co_firstlineno. Nope, read only. Then I tried sticking an object in place of func_code that returned the value I wanted for co_firstlineno. Nope, func_code has to be a ‘code’ object.

Luckily, Nose itself has a solution to this problem. The function object can have a ‘compat_co_firstlineno’ attribute on it, and that attribute will be used instead of func.func_code.co_firstlineno. A one-line change to mock.py was all it took.

links for 2008-07-25

by delicious

links for 2008-07-24

by delicious

links for 2008-07-19

by delicious

Everyone for President (and so can you!)

by Kevin Dangoor

News 3 Online has got the scoop:


That’s entirely too funny. (Before the grammar police come after me, the post title is a play on “I Am America (And So Can You!)” (Stephen Colbert)).