Slow ride, make it easy

Many of us are developing iPhone applications running in a simulator connected to a very fast Internet connection. Too bad the customers of these applications won’t be using the same environment.

It’s very important to be able to profile and debug your application while it’s running on a slow network. You’ll find lots of weird timing problems, bad connection error handling, timeouts that are too short, and other things that are likely to occur in real world conditions.

Initially, I did testing for Twitterrific by loading the latest version onto the device and then walking around outside away from my office Wi-Fi network. That was a good first step, but also one that didn’t allow me to run gdb or Instruments when a problem occurred.

And then one day it hit me: the iPhone Simulator is running on top of the Mac OS X network stack. An environment that I can manage with standard Unix command line tools. Here’s the result:

#!/bin/bash

# configuration
host1="twitter.com"
host2="search.twitter.com"

# usage
if [ "$*" == "" ]; then
  echo "usage: $0 [full|fast|medium|slow|wwdc|off]"
  exit
fi

# remove any previous firewall rules
sudo ipfw list 100 > /dev/null 2>&1
if [ $? -eq 0 ]; then
  sudo ipfw delete 100 > /dev/null 2>&1
fi
sudo ipfw list 110 > /dev/null 2>&1
if [ $? -eq 0 ]; then
  sudo ipfw delete 110 > /dev/null 2>&1
fi
sudo ipfw list 200 > /dev/null 2>&1
if [ $? -eq 0 ]; then
  sudo ipfw delete 200 > /dev/null 2>&1
fi
sudo ipfw list 210 > /dev/null 2>&1
if [ $? -eq 0 ]; then
  sudo ipfw delete 210 > /dev/null 2>&1
fi

# process the command line option
if [ "$1" == "full" ]; then
  echo "full speed"
elif [ "$1" == "off" ]; then
  # add rules to deny any connections to configured host
  if [ -n "$host1" ]; then
    sudo ipfw add 100 deny tcp from $host1 to me
    sudo ipfw add 110 deny tcp from me to $host1
  fi
  if [ -n "$host2" ]; then
    sudo ipfw add 200 deny tcp from $host2 to me
    sudo ipfw add 210 deny tcp from me to $host2
  fi
else
  # create a pipe with limited bandwidth
  bandwidth="100Kbit"
  if [ "$1" == "fast" ]; then
    bandwidth="300Kbit"
  elif [ "$1" == "slow" ]; then
    bandwidth="10Kbit"
  elif [ "$1" == "wwdc" ]; then
    bandwidth="1Kbit"
  fi
  sudo ipfw pipe 1 config bw $bandwidth

  # add rules to use bandwidth limited pipe
  if [ -n "$host1" ]; then
    sudo ipfw add 100 pipe 1 tcp from $host1 to me
    sudo ipfw add 110 pipe 1 tcp from me to $host1
  fi
  if [ -n "$host2" ]; then
    sudo ipfw add 200 pipe 1 tcp from $host2 to me
    sudo ipfw add 210 pipe 1 tcp from me to $host2
  fi
fi

sudo ipfw list

You’ll notice a couple of configuration parameters: host1 and host2. Unless you’re one of the hundreds of Twitter client developers, you’ll probably want to change those values.

Turning a connection “off” can be used to simulate a site being offline. Using the “wwdc” setting allows you to relive those exciting moments of waiting in line with thousands of other geeks banging on the SOMA EDGE network. To turn off the bandwidth limit, use the “full” setting. The other values can be used to alter the quality of the connection in the simulator and make it feel more like it’s on a cellular network.

(I actually uncovered a bug in the beta version of Twitterrific while waiting in line for the WWDC 2008 keynote, so don’t think that setting is purely a joke.)

This bandwidth trick can be extended for device testing. On your development machine, turn on Internet Sharing (in System Preferences > Sharing.) Then use your device to connect to that shared network. Any ipfw rules you set will affect the device since all of its packets pass through the gateway you’ve established on your machine.

Another trick you can use to test your networking code is by opening the Networking preference panel and making your outbound connection inactive. Since the iPhone Simulator’s networking code sits on top of the System Configuration framework, any state changes will be passed onto your app running in the simulator. (If you’re using the Reachability class, this will make sense.)

And as I mentioned above, being able to do all these things from the comfort of your office chair and Xcode debugging environment has a lot of advantages. So slow down and do some real testing!

Updated March 25th, 2009: Mike Schrag has written a nice System Preference panel called Speed Limit which does the same thing in a nice GUI. You really have no excuse now :-)

Front Row To Go

Everyone and his brother has a prediction about Apple and the mythical “netbook.” This is mine.

Before I get into the actual prediction, let me say that I’ve come to this conclusion by looking at Apple as a business, not as a supplier of shiny gadgets for our technolust. As much as we love the things they make, their goal as a corporation is to make the stockholder’s happy. They do that by selling lots of products. We’re just a means to that end.

A lot of the speculation regarding the netbook says that it provides functionality in the price gap between a $200 iPhone and a $1000 MacBook. While that’s true, it misses the point.

Apple would rather sell you another device in addition to the ones they already sell. They’re not interested in cutting into (presumably healthy) MacBook sales with a netbook. Likewise, selling a bigger touch device could cut into iPhone sales: keep your crappy cell phone and buy the netbook to throw in your purse or backpack.

One of the things that saved Apple was a simplified product line based around professional and consumer uses. Does it really make sense to have more than one consumer-level device for laptop computing? The MacBook already kicks ass in that department: having another device in that category just muddies the water.

But what if there was a device that could work in conjunction with your other Apple products? Something that extended their capabilities. Something that made each product better for a few hundred dollars.

Apple and their shareholders would love this: you’d buy the iPhone and the “netbook”. And eventually the MacBook. And maybe an Apple TV. And probably an iPod, too.

So what are some of the problems with the current hardware lineup?

  • iPhone / iPod touch – Small screen, small keyboard.
  • Mac – No touch screen, running Front Row prevents using your Mac for other things.
  • Apple TV – crappy remote, no keyboard.
  • iPod – Very small screen with no touch screen or keyboard.

So what kind of product could fill in these gaps? I call it “Front Row To Go.” Think of it as a second screen for the current hardware. Something that could:

  • Display photos on a larger screen than on the iPhones and iPods. It would also be effective as an adjunct to iPhoto on the desktop: Microsoft’s Surface prototype shows how effective it is to display pictures on a horizontal surface that can be manipulated by multiple viewers.
  • Provide a touch screen keyboard for the iPhone and Apple TV: a better input mechanism than hunting and pecking on chiclets. (Maybe this is the reason Bluetooth keyboards aren’t available for the iPhone.)
  • Show movies on a larger screen: anyone who’s taken a transoceanic flight knows that looking at the iPhone/iPod screen for more than a couple hours can be quite tiresome. An added benefit is that the player’s battery wouldn’t be consumed by the display’s power needs.
  • Provide touch input to desktop applications. Multi-touch is never going to happen on a vertically oriented display, so make a separate device that works horizontally. An obvious benefit to developers is that they don’t have to rewrite code: if it makes sense, multi-touch can be added to enhance current applications.

As with all other Apple products, Front Row To Go could obviously work as a standalone device. Sync your content onto the device and take it with you: no more dragging a laptop to a family reunion just because Aunt Bessie can’t see the tiny photos on the iPhone. Get your bookmarks and feeds from the Mac and surf the web using Front Row To Go’s version of Safari while you’re listening to music or watching TV.

As far as how these features would be implemented, that’s anyone’s guess. There might be an API for developers, or maybe it’s a closed system. The device might be able to play iPhone games or run multiple iPhone applications at once (much like the current Dashboard works in Mac OS X.) With a common base of OS X running throughout the product line, pretty much anything is possible.

And that gets to the real point of this essay: think about what Apple has learned from the halo effect surrounding the iPod (and now the iPhone.) If you have any doubt that this effect is alive and well, drop into an Apple Store on any weekend and take a look around: plenty of customers who are happy with one product and looking at others.

In my opinion, these consumers are the ones that Apple will target with a “netbook,” not the ones that are jonesing for a sexy little machine that fills a perceived gap in the product range. I hope I’m right, because I’d love to be one of those customers lining up to buy Front Row To Go.

Open sesame

Here’s a simple little script that saves me a lot of time:

#!/bin/sh 

if [ -z "$1" ]; then
  echo "usage: $0  [ Preferences |  ]"
else
  base=~/Library/Application\ Support/iPhone\ Simulator/
  apps=Applications
  app=`ls -1td "$base/"*"/$apps/"*"/$1.app" | head -1`
  if [ -n "$app" ]; then
    dir=`dirname "$app"`
    if [ "$2" = "Preferences" ]; then
      open "$dir/Library/Preferences"
    else
      open "$dir/Documents/$2"
    fi
  fi
fi

Put this script somewhere on your PATH and name it opensim. Use it to find the most recent application loaded in the simulator and open the Preferences, Documents or a named document in the Finder.

For example, to open the current Documents folder for an application in the iPhone Simulator, just do this:

$ opensim Thunderbird

To open a document within that folder, you can do this:

$ opensim Thunderbird chockenberry.db
$ opensim Thunderbird accounts.plist

You can easily get to your preferences folder with:

$ opensim Thunderbird Preferences

Notice how I haven’t mentioned a GUID in this essay? That’s the feature…

Trendy

If you’re reading my essays, it’s likely that you’re selling some kind of software on the Internet. (Or soon will be.)

To be successful at this endeavor, you need to monitor your sales and plan development around the revenue. Ask anyone who’s had success with a software product, and I can guarantee you that they have some kind of metric that tells them how well they are doing.

What I’d like to do today is share one of my favorite methods. But before I do, let me share some advice that will help you understand why this tracking scheme is so effective.

If you’ve released a product, you no doubt have witnessed the “first day spike.” It’s one of the great things about doing a release: you find that people really do love your work.

But there can be a problem. Typically, that initial spike is followed by an exponential curve: every month you’re making half as much money. And even though your income is less and less each month, the support load from existing and new customers stays fairly constant. You’re working just as hard, but earning less.

So how do you work around this? As you would in any other business: by planning ahead.

As software developers we often fall into the “just one more feature” trap. We want a 1.0 release to be awesome, and that one more thing will only take a day or two, and people will love it, so why not?

Because that awesome feature could be a very good thing to generate buzz and sales for a 1.1 or a 1.2 release. And by not “doing it all” in the first release, you get your product to market faster. You’ll be making money while you implement that cool new feature.

And holding back can have another advantage: you might find that your users want something different than what you had planned. Their input can often change your idea, so don’t waste time doing something without feedback.

So when do you know that it’s a good time to do a 1.1 release? A general rule of thumb is 30-90 days after your 1.0 release. On the day you release your 1.0, you should have some code already in the works for the 1.1 release. Give yourself a head start on the next release, because you’ll find those first 30-90 days are consumed by customer support and go by very quickly.

(I can also guarantee that you’ll have a 1.0.1 release because of some stupid little bug you overlooked. So make sure you plan ahead for that, too.)

With all this in mind, I present a simple way to visualize your release cycles by graphing trends of averaged daily sales:

The graph shows four hypothetical products and their sales. The Y axis shows how much the product earned. The X axis shows increasingly short time intervals. To plot each Y value, you just take the total amount sold in that period and divide it by the number of days. The intervals were chosen because they’re nice approximations of monthly, bi-monthly, quarterly, bi-yearly and yearly cycles.

Let’s say the Y grid lines are at $10, $20, $30 and $40 earned per day. The red product has sold about $2.50 per day over the past month, and about $10 per day over the past year. It’s a product that’s definitely in need of a version bump. An update should push it over $10 per day in the 30 day interval.

The gray product shows how a new release looks. Instead of seeing a spike, you’ll see the averages for all intervals go up (with the most change at the most recent intervals, of course.) You’ll also see the most recent averages go up as a result of ads, reviews and other good PR. As time goes on, the 30 day average will eventually drop. When it gets below the 60 or 90 day average, that’s a good time to do a release.

The goal is to end up with a product like the green one. For the most part, it trends upwards. You’re doing things right.

Finally, this graph also shows products that you shouldn’t spend time on. The lavender product isn’t performing as well as the others. Your time is better spent on things that are going to generate more revenue.

In case you’re wondering how I generated these graphs, it’s proprietary Ruby on Rails code that reads our financials and feeds them to XML/SWF Charts. The information in these graphs will change frequently: you’ll want to find a way to automate the collection and processing of your own sales data.

I’ve been talking with Dylan Bruzenak about incorporating this trend graph into AppViz. Hopefully we’ll see it in a future release—make sure to let him know if you’d find it helpful. (And if you’re not already using AppViz to track your iTunes sales, pull your fricken’ head out and start using the trial version.)

Who knew that accounting could be so trendy?

Sharing iPhone projects

The latest version of Xcode has a “feature” that prevents you from specifying a wildcard name for the Code Signing Identity. (This feature does make it easier for new developers or people working alone, so I’m not going to write a Radar for this behavior.)

When you have multiple people working on an iPhone project, this behavior is very annoying because every developer has to change the Code Signing Identity before they can run the latest version on the device. Here’s a typical scenario:

  1. I set the Code Signing Identity to “iPhone Developer: Craig Hockenberry” and do my device build. Everything is wonderful and I check in a new SekretApp.xcodeproj/project.pbxproj.
  2. I add some cool new features to SekretApp and I want Anthony Piraino to try them out. Anthony updates his working copy to the latest version.
  3. Anthony has to change the Code Signing Identity to “iPhone Developer: Anthony Piraino” so that he can do the device build. He does, and everything is wonderful.
  4. Anthony then adds some new files to the project. He checks in a new SekretApp.xcodeproj/project.pbxproj as a result of this change.
  5. I need these new files, so I get the latest version of the project. Unfortunately, this latest version has Anthony’s Code Signing Identity in it. Everything is not wonderful.
  6. Lather, rinse, repeat.
It gets even more fun when you have merge conflicts. The solution to this problem is to get rid of the individual developer names in the project.pbxproj file.

Before you begin, make sure that you’ve closed the Xcode project you’re going to be updating. You are going to be modifying files used directly by Xcode, so things can get screwed up if you make changes while the project is alive.

The first step is to locate SekretApp.xcodeproj in the Finder and right click on the file. Select “Show Package Contents” to reveal the project.pbxproj file.

Now, open project.pbxproj with your favorite text editor and look for the Code Signing Identity. It will look something like this:

CODE_SIGN_IDENTITY = "iPhone Developer: Craig Hockenberry";
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer: Craig Hockenberry";

Change the identity to look like this:

CODE_SIGN_IDENTITY = "";
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";

You also need to delete the embedded provisioning profiles. These are normally located a few lines below the CODE_SIGNING_IDENTITY:

PROVISIONING_PROFILE = "DEADBEEF-1337-FACE-F00D-EA7A7BADCAFE";
"PROVISIONING_PROFILE[sdk=iphoneos*]" = "DEADBEEF-1337-FACE-F00D-EA7A7BADCAFE";

(And, yes, I felt very lucky the day I was assigned that GUID.)

Note that there will probably be more than one CODE_SIGNING_IDENTITY (depending on your Project and Target settings.) Make sure to search through the whole file.

After making these changes, re-open the project in Xcode, clean it, and do a device build. If you make it through the CodeSign build phase, you’re good to go. Now all you have to do is check in the new version of project.pbxproj.

This trick works because the underlying codesign utility searches your keychain for a match. From the SIGNING IDENTITIES section of the manual page:

To be used for code signing, a digital identity must be stored in a key-chain that is on the calling user’s keychain search list. The identity is located by searching all such keychains for a certificate whose subject contains the identity string given. If there are multiple matches, the invocation fails and no signing is performed.

Since you and everyone else on your team has only one certificate with the pattern “iPhone Developer”, this search works correctly and no one will need to update the project settings after they check out the latest version of project.pbxproj.

And everything will stay fricken’ wonderful.