Diary of a bug in an iOS app

Last week we released version 2.9.2 of WordPress for iOS, and it had a terrible bug which killed the ability to paste text from other apps, which is probably a critical feature for a blogging app.

We should have done a better job at testing it, but somehow the bug escaped our tests and it got released. Most of the feedback on the forums was perfect: users concerned that they can’t use the app properly, but understanding that it can’t be fixed overnight.

But then this happened:

It is unacceptable that I STILL can not use the iphone app. It’s been DAYS! Fix the PASTE issue!!!

Well, it’s definitely unfortunate, but here’s how it goes:

  • Dec 5: 2.9.2 released on the app store
  • Dec 6, 6AM: first report on the forums
  • Dec 6, 11AM: after some testing, it’s confirmed that 2.9.2 broke copy/paste and it’s not an isolated problem.
  • Dec 6, 1PM: Went through the list of changes for this version and the only thing that made sense was an update to the Flurry library (used for stats/analytics). Emailed Flurry support to ask if they had similar reports or know how to fix it.
  • Dec 7: no reply from Flurry yet, we decide to remove the Flurry library from the app.
  • Dec 8: still no reply. Removed library, prepare a new build and test it.
  • Dec 9: submitted 2.9.3 to the App Store
  • Dec 11: Apple approves 2.9.3. That’s new, I didn’t know they work on Sundays, but I won’t complain🙂
  • Dec 12: released 2.9.3 on the App Store

Looking at that timeline, there’s always room for improvement, and we could have just skipped waiting for Flurry to reply (no word from them yet), and remove the library from the app directly. But even then, I’d say 2 hours from noticing a bug until we know what’s wrong and how to fix it is not that bad. Most of the times the bugs are way more obscure and hard to find.

If you’re lucky, 2 business days is the usual wait time for a bug fix release to be reviewed and accepted: I was expecting it to be published on Tuesday (Dec 13).

Goodbye Flurry

I don’t think we’re going back to Flurry after this. It’s enough trouble debugging against a proprietary framework (iOS SDK) to add another binary library to the app.

The problem here was that we had to update the Flurry library, since the old one was getting the app rejected by Apple. And the new one first broke our build server: it needs the 4.3 base SDK and we were using 4.2. And then this.

Plus, I think it collects way more data than we’re interested in. In the end, we want to know how many people is using the app, and what features are more interesting to people. Also, at some point, which kind of devices/versions users have, to know when we can drop support for older platforms.

Spotify is the new Napster

I was searching for a solution to a small Spotify bug and found this user praise: Spotify is what napster was for ten years ago.

Then another user replied:

how do you mean?

ten years ago Napster was an illegal channel for sharing and downloading music, built p2p.

are you ironic and i missed the punchline?

Fair enough. But still this guy had a point. Spotify is not the same thing as Napster, but another milestone in the Music Industry transformation.

Napster started a revolution. I’m not talking about piracy, I’m talking about spreading the message that the current formats were obsolete and people had different musical needs. The success of the iTunes Store is a good proof of that.

Spotify, as I see it, is the beginning of the end of that revolution. Say goodbye to useless CDs and DVDs. Goodbye to paying for an album with a couple of good songs and crap for filling.

The next logical step would be a Spotify for video.

The only thing I’ve seen coming from the (music and movie) industry in the last 10 years has been the message that piracy was illegal, and immoral, and that it would kill the music and movies. Maybe they have a point, maybe not.

Recently, they’ve been trying to ban download sites in Spain. What then? Without P2P:

  • I can only get movies on theaters (when/where they want) or DVD (how they want). Theaters are expensive (especially if you account for most of the movies not being worth the price) and I just don’t see myself going to a store or having to wait for a DVD to arrive to watch a movie
  • If you want movies in VO, there are little options. Thankfully we have now one cinema playing VO movies in our town, but still not enough
  • If you want TV Shows on VO you have to wait until the DVD comes out. Most of the successful shows are on TV, but delayed for weeks (or even months) and in Spanish

I found a quote yesterday that summed it up pretty well:

“People don’t go out of their way to pirate movies and TV programs; they’re not intrinsically bad people. They do it because often it’s quicker and easier than legitimate means. The quicker the film and TV industries recognise this and make it as easy to buy legal content as it is to download illegitimate content, the more likely they are to stem the flow.”

But I believe if they shut up for a minute and listen, they’d realize there’s people willing to pay, but they are not selling to them.

My 2009 in pictures

Looking back at 2009, it seems I haven’t been taking so many pictures as I did in 2008, but I see more variety. Here are some of those, some I feel proud of, some bring some good memories and some just make me smile

How we track outbound links with Google Analytics Events API

eBox Platform homepage

Since the redesign of eBox platform, our bounce rate increased dramatically. After a short investigation, it made sense: our new website was just the homepage and news, and the rest of the content was on different domains (trac, eBox Technologies, …).

So our bounces were either real bounces, or people visiting our other sites (which I wouldn’t count as bounces).

My solution: track outgoing links.

I searched for a solution and found this article, but it wasn’t exactly what I wanted.

It’s a good first approach, but tracking external links as pageviews makes the analytics reports more confusing. Events Tracking API to the rescue! This API was conceived to track actions that don’t match a page view, like video plays and other application interactions.

So, with events we could track our exits separately, get the information we need, and get a more accurate Bounce rate.

The extra code:

The original article used rel="external" to mark the links to track. There is an easiest way: searching for absolute URLS in the href attribute. Also, I’m using the action parameter to differentiate between internal (our other websites) and external (facebook, twitter,…) links.

What we are tracking, and will be able to see on the Analytics reports is:

  • Category: Exits. Could have been called ‘outbound links’, or any other variation
  • Action: external or internal
  • Label: the destination URL
  • Value: not using it. This could be useful for other kind of events, like tracking video load times

Warning: your bounce rate will probably drop by tracking events. For us, it reflects our visits more accurately, but that might not be your case.

This is what google has to say on bounce rate impact:

In general, a “bounce” is described as a single-page visit to your site. In Analytics, a bounce is calculated specifically as a session that triggers only a single GIF request, such as when a user comes to a single page on your website and then exits without causing any other request to the Analytics server for that session. However, if you implement Event Tracking for your site, you might notice a change in bounce rate metrics for those pages where Event Tracking is present. This is because Event Tracking, like page tracking is classified as an interaction request.

For example, suppose you have a page with a video player where the bounce rate is historically high, and you have not implemented Event Tracking for the page. If you subsequently set up Event Tracking for the player, you might notice a decrease in the bounce rate for that page, because Analytics will record user interaction with the player and send that interaction to the server as an additional GIF request. Thus, even though the same percentage of visitors to the page might still exit without viewing any other page on your site, their interaction with the video player triggers Event Tracking calls, which disqualifies their visit as a bounce.

In this way, “bounces” for your event-enabled pages means something slightly different: a single-page visit that includes no user interaction on tracked events.

Redesigning eBox homepage

It’s been 3 weeks since we launched the new eBox Platform homepage, and I wanted to share the different steps through the redesign.

Do you like the new design?

Do you like any of the previous steps better?

Do you have any suggestions?

Fixing Snow Leopard ruby readline

Building ruby readline

Since I upgraded to Snow Leopard I’ve been missing readline whe using irb. As I discovered in this article, this is due to apple’s ruby linking to libedit instead of libreadline. I didn’t have that problem before the upgrade since I had compiled ruby myself.

This time, I was looking for another solution. I could have compiled ruby with readline support, but then probably I’d had to reinstall some gems too. So I present you the quick way to fix your readline

Step 0: Setup temp dir

mkdir -p /tmp/rlruby
cd /tmp/rlruby
sudo -s

Step 1: Install readline

curl -O ftp://ftp.cwru.edu/pub/bash/readline-6.0.tar.gz
tar xvf readline-6.0.tar.gz
cd readline-6.0
./configure && make && make install
cd ..

Step 2: Get ruby source

To keep the complications to a minimum, I downloaded ruby from apple (check 10.6.2 open source, or other releases). The current patchlevel is ruby-75 so fetch that one:

curl -O http://www.opensource.apple.com/tarballs/ruby/ruby-75.tar.gz
tar xvf ruby-75.tar.gz
cd ruby-75

Step 4: Build readline extension

We don’t need to build all ruby, just the readline extension

cd ruby/ext/readline/
ruby extconf.rb

At this point, you’ll probably get the following error:

readline.c: In function ‘username_completion_proc_call’:
readline.c:730: error: ‘username_completion_function’ undeclared (first use in this function)
readline.c:730: error: (Each undeclared identifier is reported only once
readline.c:730: error: for each function it appears in.)
readline.c: In function ‘username_completion_proc_call’:
readline.c:730: error: ‘username_completion_function’ undeclared (first use in this function)
readline.c:730: error: (Each undeclared identifier is reported only once
readline.c:730: error: for each function it appears in.)
lipo: can't open input file: /var/folders/s4/s4qO7oueE3ijABAH7qB6Dk+++TI/-Tmp-//ccW5lOLL.out (No such file or directory)
make: *** [readline.o] Error 1

We need to tell gcc that our readline is in /usr/local

make readline.o CFLAGS='-I/usr/local/include -DHAVE_RL_USERNAME_COMPLETION_FUNCTION'
cc -arch i386 -arch x86_64 -pipe -bundle -undefined dynamic_lookup -o readline.bundle readline.o -L/usr/local/lib -L/System/Library/Frameworks/Ruby.framework/Versions/1.8/usr/lib -L. -arch i386 -arch x86_64 -lruby -lreadline -lncurses -lpthread -ldl

To be sure we are using the real readline run otool and make sure libedit doesn’t appear on the results:

$ otool -L readline.bundle
/System/Library/Frameworks/Ruby.framework/Versions/1.8/usr/lib/libruby.1.dylib (compatibility version 1.8.0, current version 1.8.7)
/usr/lib/libncurses.5.4.dylib (compatibility version 5.4.0, current version 5.4.0)
/usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 125.0.0)

Step 5: Replace readline.bundle

cd /System/Library/Frameworks/Ruby.framework/Versions/Current/usr/lib/ruby/1.8/universal-darwin10.0/
mv readline.bundle readline.bundle.libedit
cp /tmp/rlruby/ruby-75/ruby/ext/readline/readline.bundle readline.bundle

Now launch irb and check if all your favorite shortcuts are in place

Sick of getting your wordpress hacked? (contest below)

Crashed again

I sure am. After a proper installation/configuration, the most important factor is to always stay updated to the last version. I’m managing at this time 8 or more blogs/websites running different versions of WordPress and it’s hard to keep them up to date.

Automatic upgrades help, although they still terrify me after the 2.8 crash.

The problem is, some of these blogs are set up for friends or old projects, and I forgot to frequently check if they are using the latest version. Most of the times, they become crammed with spam, and eventually trigger google’s malware detectors. Most of the times I notice the hack because of firefox malware warning.

So I started a side project to help me keep track of all those blogs and their versions, and it’s seems is close to see the light. This is how it looks right now:

beta screenshot

I will need testing, so if you want to participate in the beta, fill the signup form, and I’ll send some invitations.

Also, I’m looking for a nice name for the thing. If you have a good idea, put it in the ‘Proposed name’ field on the signup form. The winner(*) will get the first beta invitation and free full access to the product for 1 year after it launches. Make sure a .com domain is available for the name you propose or it won’t have many chances.

(*) There will be only 1 winner: the first person to propose the chosen product name. Simple rules, but… without rules we are nothing but savages.