Announcing In Season 1.0

I am pleased to announce the immediate availability of In Season 1.0 for the iPhone and iPod touch. In Season is a produce shopping guide, inspired by a couple of recent books that address the problem of missing flavor in most produce found in American markets.

Here in America, we’ve become rather used to the idea that fresh fruits and vegetables are available whenever we want them. What we don’t always realize is that this convenience comes at the cost of flavor and price. Plants grow according to a schedule, and while we can force things somewhat (hothouse tomatoes, for example), if you want peaches in the dead of winter, they aren’t coming from the northern hemisphere.

Shipping produce from South America is a long trip to an American market, though, so food has to be bred to survive the journey and someone (the consumer) has to cover the costs of that travel.

There are even disadvantages to strawberries grown and sold in season. Strawberries are so fragile, growers have had to breed them exclusively for shipment, resulting in a berry that has only a pale shadow of true strawberry flavor left.

I created In Season to help my own family, and hopefully others, with this problem. Food tastes better when it’s grown according to its natural schedule, and even more so if you can find a local farmer supplying produce to your market. It will take less effort to grow it and supply will be higher, so you will pay less. Locally-grown produce also means less fuel is burned bringing that food to market, further bringing prices down and reducing your carbon footprint at the same time.

The economics of the App Store being what they are, version 1.0 is a toe in the water. If it is well received and I can justify further development, I have some great ideas to make it an extremely useful and educational app.

If you are interested in those books I mention above, they are terrific reads: How to Pick a Peach: The Search for Flavor from Farm to Table, by Russ Parsons and Animal, Vegetable, Miracle: A Year of Food Life, by Barbara Kingsolver.

It’s Just Software

This is a post I’ve been meaning to write for a very long time, but I’ve always had other, more pressing work, to do, and so I never wrote it.

Rands posted his version today, though he’s using my point as an introduction to an Election Day moral than as a post about software development itself.

Still, the first half of his post is spot-on. In software, given enough time, it’s possible to do just about anything. There’s a classic joke in software development circles: fast, cheap and good: pick two. It’s not a question of if, it’s a question of when.

My customers don’t always understand this. A seemingly minor change can have wide-reaching ramifications, perhaps doubling the time (and cost) of a project.

It’s great to have an idea of what you want to build, but it’s just as important to listen to an expert when it comes to implementation. “Can we do this?” is not a good question. The answer is almost always “yes.” “I’d like to do this, but I only want to spend this much (or, I’d like it by this date)” is far better.

Apple Sanctioned Developer Forums

Hallelujah: Apple is now offering official developer forums for the members of the iPhone Developer Program. It’s tied to your Apple ID, so they know who’s in and who’s not, and part of the usage agreement implies that they may provide forums for the discussion of pre-release software.

I hope they extend this to Mac development, too. The Apple mailing lists are great, but up until Leopard was released, the moderators on cocoa-dev were constantly fighting the tide of questions about Leopard-only APIs.

(Seen on Daring Fireball.)

Safari’s Web Inspector in Nightly

Surfin’ Safari has a great post talking about some recent improvements to the Web Inspector in the latest WebKit nightly builds. Safari’s Web Inspector has long been a really great tool for examining the DOM and simple profiling of a requested page and its resources, but these new updates make it a serious tool for web developers.

If you’ve never tried a WebKit nightly build before, it is easy (on a Mac, anyway) to run it side-by-side with Safari. You don’t have to give up your stable, released browser to check out these new features. Still, it will be very nice when these improvements make it into an official release.

For Firefox users, YSlow is a very nice extension built on top of Firebug that provides a detailed report card on page load performance, including suggestions for improving it.

Announcing Pat Counter for iPhone

This evening I finally received an email from Apple informing me that our first application for the iPhone and iPod touch is ready for sale. I’m pleased to announce Pat Counter, a simple way to keep track of a running count without having to hold something in your hand or look at a screen to tap a button.

It’s a simple application, but it was an interesting experience in developing and shipping an application for a new platform. Rands was right about 1.0: it’s amazing how much work and time it takes to take care of all the little details, even in something as simple as Pat Counter. Valley start-ups really do go out of business because it can be so hard. (Aside: Rands’s book Managing Humans is quite good.)

I wasn’t able to find any data points out there about lead times, but for me it was five days between submission of the binary to Apple and approval for sale. That includes a weekend, but it seems like apps are still approved then, just at a slower rate.

Finally, a word of advice: make sure your binary is right the first time. I goofed my initial build and it took seven days before Apple told me about it, by which time I’d already noticed it myself. Replacing the binary was effectively the same as the initial submission; I went to the back of the line. Read the instructions for a distribution build closely and follow them exactly.

Update: It’s now available on the App Store with a direct link, but isn’t in the search results.

Update 2 (Sep. 15): It now shows up in search results, a mere five days after approval.

What else might be in Snow Leopard?

Apple Inc. announced Mac OS X 10.6 “Snow Leopard” at WWDC’08 on Monday, but other than a press release and a page each for 10.6 Client and Server, very little information was given that isn’t covered under the WWDC NDA.

Still, one “feature” is interesting, especially in the face of (mostly confirmed) rumors that 10.6 will drop support for the PowerPC:

Snow Leopard dramatically reduces the footprint of Mac OS X, making it even more efficient for users, and giving them back valuable hard drive space for their music and photos.

Dropping PowerPC will save reduce the size of executable code by around 50%. Here is the output of otool -f for iTunes:

Fat headers
fat_magic 0xcafebabe
nfat_arch 2
architecture 0
    cputype 18
    cpusubtype 0
    capabilities 0x0
    offset 4096
    size 17345088
    align 2^12 (4096)
architecture 1
    cputype 7
    cpusubtype 3
    capabilities 0x0
    offset 17350656
    size 17053824
    align 2^12 (4096)

The PowerPC’s CPU type is 18 (look in /usr/include/mac/machine.h), so the PowerPC code in the main iTunes executable accounts for 50.4% of the total. I’m going to assume that this ratio will mostly hold true for frameworks, too.

The entire iTunes bundle is 122 MB, though. Trimming the 16.5 MB + 1 MB of bundled frameworks off of that is only about 14%; not what I’d call a “dramatic” footprint reduction. What else might they have planned?

Another couple of options are transparent compression at the filesystem layer and conversion of image resources to a vector format.

Apple’s own page says that read/write ZFS will be in 10.6 Server, so it’s reasonable to expect it will be in Client, too, perhaps with some of the more advanced features disabled. ZFS includes an option to transparently compress data. NTFS on Windows has had this for years, and third-party products did it on FAT years before that, so it’s entirely reasonable to expect that Macs will finally get this, too. 71% of the iTunes bundle is resources, mostly localizations, and inside those, the largest directories are for the in-app help, which is HTML.

Support for resolution independence has been rumored for years, and while Apple has supported it to some degree since 10.4, it hasn’t really caught on. Might they finally be converting all of the system image resources to a vector format? I don’t have any numbers on it, but a vector graphic is certain to take up much less space than a 512×512 PNG.

Advertising and Making Money Online

David Heinemeier Hansson gave an amusing talk at Startup School ’08 and it echoes something I’ve been thinking about for some time. A lot of web sites out there get very, very popular and yet there is no indication they plan to make money. Many more web sites fall back on advertising as their primary business model.

ZingLists isn’t terrifically popular, but I’ve given a lot of thought to how it might generate some revenue and least pay the hosting bill. Up to now, I’ve taken the easy route and put Google ads on the list summary pages. They aren’t very intrusive and once in a while they’re actually useful, displaying an ad that helps you cross something off that list.

There are really two problems with relying on advertising as a business model. The first is my problem. Relying on someone else to sell the ads (Google) means you essentially have a single customer. If something happens to that customer, all of your revenue disappears in a puff of smoke. Google disabled my account about a week ago and I can’t get them to tell me why. It’s the whole account, too: AdSense, Analytics, Gmail, Calendar, everything. I have no idea what the perceived problem is, though my best guess is click fraud. That sucks, though, because I can’t control an end-user’s behavior, and if I don’t show them the ads, I have no chance of generating revenue. So Google AdSense (or any single provider of ads) is not a real business model.

The second big problem with advertising is this simple question: why are you in business? Is it to sell advertising or to write software / provide a service? If it’s the latter, I’m sorry to inform you that generating revenue by selling your own ads means you are in fact in the business of selling ads, not writing software. This is not a business I want to be in.

Another Example of How Not to Do Customer Relations

Mozy finally announced their 1.0 release for Mac OS X. I haven’t heard from these guys since I signed up for the notification, probably more than a year ago. Then today, out of the blue, I get an email that leads off with:

One of the nice things about being an ugly American is that I make all sorts of ignorant and culturally insensitive remarks about other countries. And as luck would have it, I had that opportunity last week when I visited Montreal. (That’s in Canada.)

The first thing I noticed about Montreal is that it’s a very clean city – like Toronto in that respect. Oh wait – actually, the first thing I noticed was the streets were on fire and full of police and rioting citizens because I guess they won an O-KAY (that’s hockey) game.

Admitting that you’re a jerk doesn’t give you a free pass to go ahead and act like a jerk. If anything, it’s worse because you’ve made it clear that you know it’s wrong.

And as a method of contacting a list of people who otherwise haven’t heard from your company before? This isn’t how I’d choose to establish a relationship with potential customers.

I’ll rest well knowing that Mozy won’t get any of my money, especially with so many other options available in their market.

sql_logging Updated for Edge Rails

I updated the sql_logging plug-in today to work on Edge Rails.  The PostgreSQL adapter on Edge tries to load a different database driver, and explicitly loading it when the application isn’t using it causes a crash when the server starts.  Today’s change reworks things by asking ActiveRecord what adapter it’s using and only loading the extensions for it.

One other change includes making PostgreSQL query statistics work on Rails 2.0.  The adapter there prefers to call the execute method instead of query.

Things should still work on Rails 1.2, but I’m moving applications to 2.0 whenever possible, so I’ll rely on a bug report if something is broken.

Finally, I’ll leave with a little tip: statistics aren’t kept for queries that lack a name or look like Rails asking for schema information.  If you have a significant amount of query work done using the raw connection (select_all or select_one), make sure you give the query a name so it can be tracked properly and show up in the top 10 list.

Get the plug-in from svn at http://svn.lightyearsoftware.com/svn/plugins/sql_logging.

Quality of Service

I clearly take my job a little too seriously.

I’ve been filling up some free hours these past couple of weeks putting some polish on ZingLists. Most of the changes involve tweaking a few things here and there, but the big one is that I’m adding a mobile interface for the most essential features, and that necessitated moving from Rails 1.2 to Rails 2.0.

Everything went smoothly during development, but late Friday, when I pushed the code to production, anything that touched the new code died with a scary-looking illegal instruction signal. My production server runs FreeBSD, and I had upgraded a few other packages to stay current with security issues and bug fixes, so this left me with the cold feeling of a completely dead site late on a Friday afternoon.

As it turns out, while I haven’t solved the problem yet, I got lucky through some over-engineering on my part when I first wrote my Capistrano deployment recipes. I do deployments in two stages. Stage 1: push the code, run migrations and background tasks (e.g generating a Google sitemap). Stage 2: move configuration files into place, switch the “current” symlink and restart processes. Since I hadn’t run stage 2 yet, everything was still working fine.

Twitter also pushed some new code on Friday, but they’re having problems big enough that the site may as well be down.

ZingLists is microscopic compared to Twitter in just about every way imaginable. I’m one guy with no VC, Twitter is a dozen-ish people with at least a few million in VC. Neither of us are making any money off our web sites. Shouldn’t I be the one that doesn’t care about my uptime?

I’m optimistic that I will solve my “illegal instruction” problem with Rails 2.0, so in the interest of priming this post for anyone else who runs into the same thing, here’s a summary of the issue. (I expect most of you will stop reading here.)

The “illegal instruction” seems to be a case of the Ruby interpreter not dealing well with a stack overflow. This could be from deep recursion, but I doubt it in my case since the same works fine in development. Even simple things like List.find(:all) from script/console causes the problem, and that’s a simple ActiveRecord query.

On FreeBSD 6.2, the Ruby port is always compiled with pthreads. Because of the way that this version of FreeBSD is written, if a dynamic shared object loaded into a running program needs a shared library (like pthreads), that library must be linked to by the executing program. In this case, that’s the Ruby interpreter. The default pthreads stack size on FreeBSD is relatively small compared to other operating systems, though I couldn’t track down an exact number. It’s in the ballpark of 64 KB or 128 KB. Linux usually uses something closer to 1 or 2 MB.

My theory at the moment is that Rails 2.0 nests method calls deeper than 1.2, just enough to exhaust the stack and trigger the illegal instruction signal. I’m guessing this is because the stack overflow results in some random bit of code being executed. I’m on the AMD64 platform, and I believe it marks non-code pages with the NX (no execute) bit, so a jump off to a random address is highly likely to be caught by the kernel.

I don’t really want to recompile or hack the Ruby interpreter to make pthreads stacks larger, since I’d have to make the same fix every time Ruby is updated. I’m going to try to replicate the problem in a 6.2 virtual machine, then upgrade it to 6.3 and possibly 7.0 to see if either of those solve it. Barring a response from the Ruby port maintainer, I may even look at switching to Ubuntu Linux, though I hate to do that since I’m otherwise very satisfied with FreeBSD.

Updated April 24: so as usual, admitting in public that I have a problem with some code virtually guarantees that the problem is in my code.  I had an infinite recursion bug due to an <tt>:include</tt> on an association.  FreeBSD simply died really fast, probably due its small thread stack, but I also was missing an adequate test case to catch the problem.