Archive for September, 2006

Two Things That Have to Happen to Mobile

There are two major things that make mobile software development vastly different and more frustrating than development in other industries. These hindrances are holding the whole sector back, and really, it’s in everyone’s best interest to smooth the development path for mobile software, both for WAP and downloadable applications.

Carriers need to learn how to let go.

Remember Prodigy, and the good old days of AOL? The carriers do, and they’re totally in love with the “walled garden” style of trapping a user in their own universe. Carriers still want to control all of the mobile content that the user sees, buys, and uses. This goes both for the mobile web and for downloadble applications. This has a couple effects:

  • Users are given limited choices. Obviously. But this means that it’s very hard for the industry to grow organically. You’ll hear over and over again that “nobody knows what works yet” in mobile, and this is largely due to the fact that it’s extremely difficult to get the audience to try new things. What the user sees and gets is dictated from the top down.
  • Mobile software companies depend hugely on carrier relationships. The success of your game/application depends a lot less on free market capitalism and how good your product actually is, and much more on how strong your relationships with the big carriers are.

Handsets need to obey standards.

There’s a terrible tension between the need for software and browser compatibility across multiple handsets, and the need for handsets to distinguish themselves from others in the market with wacky features. That’s not to say that Nokia or Motorola should stop making phones with peculiar geometry or features nobody else has, but they need to do so without requiring developers to bend their code to fit into yet another sub-model. A single phone represents a fraction of a percent of a developer’s user base, so maintaining so many SKUs quickly becomes unmaintainable.

Java ME needs to stabilize. Porting games and apps — that is, making a mobile app work across multiple handsets — is an awesomely frustrating chore. There’s a special room in hell where you have to port Java ME apps to support handsets full of undocumented bugs. From this torture has risen a thriving cluster of small startups that specialize in porting, who have knowlege of the handsets’ different capabilities and bugs and retool code that works well for one phone to work against three dozen other phones. Those shops often rely on a third-party database of undocumented phone capabilities, another mini-industry built on the inefficiencies of the mobile space. A big part of the promise of Java is supposed to be that “write once, run anywhere” feel-good feeling, and maybe with the exception of varying graphics sizes for different screen sizes, it should. Full-time porting jobs should not exist! But they do, and they probably will continue to for a few years. It must be said that BREW is much better in this respect; it doesn’t hurt that Qualcomm is the tightly-controlled central source for the firmware.


All of this is sort of a crying shame for a technology that should be so much farther along than it is, but it also presents a neat, obvious opportunity to people willing to move it forward. The silver lining for the United States is that our backwardness and slowness has given us two crystal balls into the future of mobile: The internet, and the rest of the world’s mobile industry. You can guess some things about the future: Walled gardens will give way to third party portals, and as more site come online and cross-connect to each other, search engines will become more useful and the portals will become less so. The greater the connectivity capabilities, the better the apps — and we can watch the huge successes half a world away that will likely be repeated here in two more years. The industry is moving, fast, and everyone (even the carriers, in their own weird way) seem to recognize this situation and are working to move everyone out of the darkness, and soon, this mini-rant will be obsolete.

Concurrency in Concurrency Web in Apps Web Apps

Recently, I’ve made a few embarrassingly obvious concurrent-programming faux pas, so as a means of retribution to the multi-threaded daemon, I’ll try to confess a couple of my own anti-patterns here.

1. Servlets are reusable.

Here’s a snip of sample code:

public class MyServlet extends HttpServlet
{
  private HttpServletRequest _request;
  private HttpServletResponse _response;

  public void doGet(HttpServletRequest req, HttpServletResponse res)
  {
    _request = req;
    _response = res;
    ...
    new ResponseHandler().handle(this);
    ...
  }

  public HttpServletRequest getRequest() { return _request; }
  public HttpServletResponse getResponse() { return _response; }
  ...
}

What’s the most awful thing about this code? The big catch is that the servlet engine (Tomcat in my case) will reuse the same MyServlet object for subsequent requests, and when you make it big (or when someone’s, ahem, excessively aggressive crawler finds you), the servlet engine will call the same doGet()/doPost() on request B before request A one finishes. This means that, in the above example, when the ResponseHandler object calls MyServlet.getRequest() or MyServlet.getResponse(), it could potentially return the wrong object. This means that requests A and B could end up with their schwartz twisted, and you’ll probably end up with something like both responses appended together in B’s output stream, with A’s response lost and gone forever.

The solution is pretty simple in this case: Don’t use member variables in your servlet. Here’s the same code fixed:

public class MyServlet extends HttpServlet
{

  public void doGet(HttpServletRequest req, HttpServletResponse res)
  {
    ...
    new ResponseHandler().handle(req, res);
    ...
  }

  ...
} 

You’ll probably find you don’t even need the servlet object anymore and can pass its parts in. That thing is dangerous anyway.

2. Protect your cron jobs

This you can file under the “like, duh” folder, just don’t file it under the “my script only takes a few seconds to run, it can’t happen to me” category, like someone writing this entry did. Long-running jobs can get backed up on each-other, as cron will obediently lob another program out of the gate, whether or not the first one finishes. If you’ve got a serious hang-up or delay, this backup can get pretty severe. Take a flip through David Pashley’s excellent article on writing robust shell scripts and you’ll find something along these lines for that you can pretty much rip off and use:

if ( set -o noclobber; echo "$$" > "$lockfile") 2> /dev/null;
then
  trap 'rm -f "$lockfile"; exit $?' INT TERM EXIT

  [critical-section]

  rm -f "$lockfile"
  trap - INT TERM EXIT
else
  echo "Failed to acquire lockfile: $lockfile."
  echo "Held by $(cat $lockfile)"
fi

When you think you’ve fully redeemed yourself, and you can’t ever be totally sure, you absolutely must test your code. Testing for race conditions is notoriously difficult — for a start, I’d recommend some free load testing software like Apache JMeter, unless you have the megabucks for something like LoadRunner. JMeter seems like it can handle both web and non-web apps, including trying to injure JUnit tests with multithreaded calls. Very handy.

One quick concluding word about race conditions: You never think they’ll happen to you, and they don’t. Until they do, and when they hit, they’ll take down your entire site with hundreds of megabytes of logged stacktraces, at 3:30 in the morning, on your first day of vacation. This is not an exaggeration, it’s just life.