Monthly Archives: September 2009

Feedback about lost sales

“Great post by Jason Cohen”:http://blog.asmartbear.com/blog/put-down-the-compiler-until-you-learn-why-theyre-not-buying.html on why you need feedback about the real reason people aren’t buying your product:

“You need to talk with the people who were interested enough to find your website, read your marketing copy, download your product, and then _give up without even an email_. That’s the low-hanging fruit; those are the people who are _in your grasp_, who should be buying _today_, but aren’t.”

I fall into this trap quite often, of pretending I know what the product needs for sales to finally take off. So I’ll add all the features I hope customers want, or I’ll make a small change and see if sales improve. But the truth is that there are so many variables in this system that it’s difficult to know which change made the difference.

As an example, I decided recently that I was being too generous with the demo limits in “Clipstart”:http://www.riverfold.com/software/clipstart/, so in the 1.2.1 release I turned them down a little. Instead of letting you tag 30 videos and upload 3 for free, it’s down to 20 videos and 2 uploads. The idea is to just do a little bit more to encourage users to buy the software when they are first trying it out and like it, rather than waiting a month until they decide to use it again.

Sales have been up the last week, so this worked, right? Maybe not. Clipstart has a review in this month’s print edition of Macworld, so it’s possible the sales are up because of that. Or because a couple of my blog posts have been linked more heavily recently. Or for any number of other reasons.

Unless you measure why the product doesn’t sell, success will be based on luck and intuition, which only go so far. I’m looking forward to reading Jason’s next post.

It’s okay to ignore the iPhone

I talked in “Core Intuition episode 22”:http://www.coreint.org/2009/08/episode-22-not-just-a-hobby/ about how I’ve stopped working on my indie iPhone apps. Mike Ash is also done with it. “He writes”:http://www.mikeash.com/?page=pyblog/the-iphone-development-story-one-year-later.html:

“I have abandoned the platform. Apple’s nonsense is just too much for me. There’s no joy in iPhone development, and an enormous amount of frustration.”

Reading through the comments got me thinking. I’m not abandoning the iPhone just because the App Store is such a frustrating environment to run a business in, or that I have a bunch of real work I could be doing instead of playing games with Apple. It’s also because most of the apps I would write have already been done, and in some cases done very well.

I love having a small computer in my pocket and mine is full of third-party apps. I’m thankful for the developers who are coming from other platforms and focusing all of their attention on the phone. And they are thrilled to be an a platform that is such a step up from traditional mobile development. The financial success stories of developers hitting on a great idea and it just taking off in the App Store are real and inspiring.

But the iPhone doesn’t need me.

As a user there’s no way I’ll give up the phone, but as a developer I can focus my time on “things that I have control over”:http://www.riverfold.com/, and add value to places where no one else has a good solution. Perceived gold rush or not, stretching myself too thin with both iPhone and Mac development is a great way to fail at both.

Imagine for a moment that “Yellow Box for Windows”:http://www.cocoadev.com/index.pl?YellowBox wasn’t killed off — that we could build Windows apps using Cocoa. Should I make my apps cross-platform just because it’s Objective-C? No. Writing software for a platform I don’t use would be like still supporting Mac OS X 10.2; there’s no way I’m going to boot into that thing to test and fix my app.

If you’re a Mac developer, my message to you is the same: just because the iPhone is awesome and runs on Objective-C does not mean you are required to build software for it. Maybe your time would be better spent refining old apps or building new ones on the Mac. Maybe… the iPhone doesn’t need you, either.

VoodooPad help update

Somehow it’s been a couple years since I wrote about “using VoodooPad for authoring help”:http://www.manton.org/2007/01/falling_in_love.html. I always meant to update the post with more information, and I still receive occasional follow-up emails from developers who are trying this for themselves. My workflow is virtually unchanged since then, and the help for “Clipstart”:http://www.riverfold.com/software/clipstart/ is built the same way.

Here is the Clipstart VoodooPad document in case it’s helpful to other developers: “Clipstart_Help.vpdoc.zip”:http://manton.org/misc/Clipstart_Help.vpdoc.zip. The important parts are the special pages WebExportPostflightScript and WebExportPageTemplate.

Meanwhile, “Philippe Casgrain wrote a great blog post”:http://developer.casgrain.com/?p=16 that is nearly identical to what I do, but with more detail and steps for triggering an export from Xcode. Lately I’ve been pointing people to his post since it’s more technical than mine was.

“Mark Dalrymple also posted”:http://borkwarellc.wordpress.com/2009/09/07/voodoopad-and-subversion/ a time-saving SVN script for VoodooPad today. I’ve been needing this!

VoodooPad is just a really good fit for this stuff. (Also see “Macworld’s 4-mice review”:http://www.macworld.com/article/141473/2009/07/voodoopad41.html for VoodooPad 4.1.) Or if you are more of an OmniOutliner kind of person, check out “Omni’s Helpify tool”:http://blog.omnigroup.com/2008/10/02/helpify-the-omni-help-emitter/ for converting outlines to an Apple help book.

Image Capture API

In “episode 21 of Core Intuition”:http://www.coreint.org/2009/07/episode-21-the-tyranny-of-commit-access/, I called the Image Capture API “quirky”. What did I mean by that? A few things.

Refcon. This should be familiar to anyone who has built Mac OS 9 or Carbon apps. I’ve certainly written plenty of code that stuffed a pointer to an object in the refcon field of a structure or passed to a callback method. It’s an essential pattern for being able to integrate C++ or Objective-C objects with a C-based API.

For Image Capture, the code might look like this:

  ICAGetDeviceListPB pb = {};

pb.header.refcon = (unsigned long)self;

OSErr err = ICAGetDeviceList (&pb;, YourDeviceListCallbackHere);

Then in the callback you cast the refcon back to your controller object and go about calling methods and accessing member variables.

  void YourDeviceListCallbackHere (ICAHeader* pbHeader)

{

YourController* ic = (YourController *)pbHeader->refcon;

[ic doSomethingUseful:pbHeader];

}

Works fine, but what about 64-bit? The reason I noted this part of the API to blog about was because the first version of my code accidentally cast my pointer to a UInt32. Luckily for us, the refcon is actually declared as an unsigned long instead, so it should share the same pointer size in 64-bit land, where long and void* are both 8 bytes. Other data types in Image Capture, such as ICAObject, are declared to be UInt32.

(What would we do if the refcon was UInt32? The solution is not terribly difficult: use a simple lookup table that maps a random ID or incrementing number stored in the refcon to your 64-bit compatible pointer. But this just doesn’t seem to be necessary very often.)

No delete function. I found this one strange, and had to dig in example code to find the solution. There is no first-class function in Image Capture for deleting objects off of a camera. Apparently this isn’t a feature that is supported by all devices, but nevertheless it seems common enough that it deserves something more than an enum constant hidden in a secondary header file.

Here’s how you go about deleting a video off of the iPhone:

  ICAObjectSendMessagePB pb = {};

pb.header.refcon = 0;

pb.object = (ICAObject)your_movie_id_here;

pb.message.messageType = kICAMessageCameraDeleteOne;

OSErr err = ICAObjectSendMessage (&pb;, NULL);

Bad delete on success design. Related to the above, Image Capture has this trick that seems clever at first but which I don’t think could be used for most applications. You can set a flag to tell Image Capture to delete a video after it imports. Maybe this also explains why there’s no standalone delete function, but the design feels dangerous to me; if an import fails halfway through importing 10 videos, the first 5 will still be deleted. I much prefer to examine the imported files to make sure they were saved correctly, and then after everything was successful go back and delete the imported objects.

It’s been a couple months since we recorded Core Intuition 21, but there are some other segments worth noting. Daniel and I talked about the WWDC 2009 session videos, a plug for “rooSwitch”:http://www.roobasoft.com/rooswitch/, beta testing MarsEdit 3, and a listener question about working for non-developer managers. Listen at coreint.org or “subscribe in iTunes”:http://phobos.apple.com/WebObjects/MZStore.woa/wa/viewPodcast?id=281777685.

LEGO minifigures

My son is seriously into LEGO Star Wars right now. He’ll spend hours every day building ships, and it’s the most incredible thing watching how good he’s gotten at it over the last couple of months. For his birthday we ordered him the X-wing set, which is “all kinds of awesome”:http://www.flickr.com/photos/manton/3766379995.

One of my favorite posts to this blog was partially about LEGOs. “In 2006 I wrote”:http://www.manton.org/2006/01/limitations_in_toys.html:

“If the toy is made to do a few specific amazing things, with a bunch of bullet points and exclamation marks on the side of the box, be weary of it. For example, modern LEGOs come in all sorts of pre-molded shapes. If you buy the pirate set, it will be great fun for the first few days until you realize that it can only be a pirate ship. But if you buy a bucket of LEGOs (yes, they still sell these), you can build a pirate ship one day and a barn the next.”

There’s a lot more to the post, and I still believe what I wrote. But it turns out that LEGO Star Wars sets are surprisingly well designed. There are very few custom pieces, and almost all the sets (we must have about 10) share the same shapes, just with different colors and for different purposes. I’m a big fan now.

lego_minifigures.jpg

Tonight we sat in bed together and looked at LEGO catalogs. I’m in those awesome years where being a dad is just like being a kid again, and this post is to capture a little part of that moment, before it’s gone.

Crippled iPhone LGPL

I mentioned on the “latest Core Intuition”:http://www.coreint.org/2009/08/episode-22-not-just-a-hobby/ that I no longer have any plans to release my own iPhone software. While that decision is mostly based on my unwillingness to give Apple so much control over my business, and frustrations with the App Store process in particular, there are a handful of technical reasons why iPhone development is not a good fit for me. Here’s one: open source.

“Daniel Jalkut’s essay on the GPL”:http://www.red-sweater.com/blog/825/getting-pretty-lonely hits all the points about how the GPL can hurt developers by discouraging commercial participation. I’ve used LGPL projects in both “Clipstart”:http://www.riverfold.com/software/clipstart/ and “Wii Transfer”:http://www.riverfold.com/software/wiitransfer/, and I am careful to use them correctly. But iPhone development presents an interesting problem.

Can’t run command line tools. Separating the GPL code into a command line tool that is inside your application bundle is a common way to get around licensing issues. This is not allowed in the iPhone SDK.

Can’t replace dynamic libraries. The LGPL says that you can also link to libraries at runtime, but the catch is that the user must be able to replace an LGPL library with a newer version of their choosing. There is no way for normal users to do this on the iPhone.

Can’t use private frameworks. Oh, that point above about dynamic libraries? Actually it’s a moot point because Apple requires everything to be statically linked anyway. So you are blocked at every pass; you can’t ship an app that loads code dynamically even if the user could touch it.

The only solution I’ve seen so far is to release a special version of your Xcode project, with most of your application split into compiled libraries instead of source code, and allow developers with the iPhone SDK to relink your application with a different copy of whatever LGPL code you used. I stopped researching this when I put my own iPhone projects on hold, though. It’s just another example of how the closed nature of the platform creates an unnecessary burden in the software development process.

Better is the best marketing

“Gus Mueller”:http://gusmueller.com/blog/archives/2009/08/setting_the_right_priorities.html, in response to a post from Joel Spolsky:

“If no one is buying your app then you’ve either got a dud and you need to focus on something else, or you need to improve your app so it’s worth paying for.”

I hinted at this in “my last post about new Clipstart features”:http://www.manton.org/2009/08/clipstart_12_ships.html. When Clipstart 1.0 launched and sales were lower than I had secretly hoped, the feedback was still so encouraging that it was obvious I had to keep rolling out new versions. Release 1.1, a month later. Release 1.2, which is “shipping today”:http://www.riverfold.com/software/clipstart/.

Some products are just easier to sell than others. For Wii Transfer, people enter “music wii mac” in Google and then a few minutes later they are clicking the Buy button on my web site. But with Clipstart, even though I believe it to be a superior product, it’s going to take work and marketing and word-of-mouth and demo coaxing and making it so good that you’d be nuts to shoot video and not have it installed.