A good email client, please.

February 1st, 2010

Gmail proved that, despite the apparently high switching costs, a new webmail client can quickly get a lot of traction. There’s room now to do to Gmail what Gmail did to everything else. The replacement should have some concept of workflow (”archive, but remind me to respond tomorrow”, “send, and alert me if I don’t get a response within a few days”), some concept of teams and colleagues (allow threads to be shared as a first-class object, rather than flailing around with forwards and CC lines), be some way smart about mining the semi-structured mails going through the system (flight booking emails should be automatically annotated with .ics files), know something about prioritization (I like Twitter DMs because of the assumption that they’ll go to a mobile device. If I’ve sent more than 20 emails to someone, they should have the option of copying their mail to me as an SMS).

Potentially most powerfully of all, developers should be able create their own plug-ins that run on the server. There should be an agreement between plug-in developers and the webmail provider that creating a plug-in automatically grants a royalty-free perpetual irrevocable worldwide (etc.) license to the provider, and that the source code to any plug-in may be merged into the main product. Though plug-ins have niche appeal, this could be a good source of new features, and a strong competitive advantage. I’d just fix Gmail if I could.

I’d happily pay for any service that got this stuff right.

clean-downloads

December 9th, 2009

This has solved the eternal “there’s 3GB of stuff in my Downloads directory that I don’t feel comfortable deleting” problem for me:

$ crontab -l
0 * * * *   /Users/patrick/Binaries/clean-downloads
$ cat Binaries/clean-downloads
#!/bin/zsh
find ~/Downloads -maxdepth 1 -amin +720 -exec mv {} ~/.Trash \;

You have twelve hours to do something with whatever it is you downloaded, or it’ll end up in the Trash. I highly recommend it.

Surprises

October 18th, 2009

Someone asked me today what surprised me most about doing a start-up. This was my response:

  • How slowly things change. When we started Auctomatic in mid-2007, eBay was dominant but faltering, PayPal was lumbering along without any innovation, Facebook was amazing everyone (and scaring Google) with their growth, the iPhone was reshaping the cell phone industry, and everyone was talking about Twitter. Two and a half years on, that still sounds like a reasonable assessment of things. With Auctomatic, we felt this tremendous sense of urgency. That may have been good for other reasons, but it was misguided. When building something, I now think you should assume that you’ve plenty of time, and that very little will change in the interim. (This is, admittedly, the kind of rule that works until it doesn’t.)
  • Tied to this, the realization that a good product is so much more important than first mover advantage. Obvious, but keeps surprising me. Facebook, the iPhone, Dropbox, Skype, etc., have an amazing array of failed predecessors.
  • Succeeding at biz dev just requires endless persistence.
  • Internationalization is an underexploited axis—people try to expand on the x-y plane, and ignore this third dimension. We grew our iPhone app revenue by over 200% through internationalization. The biggest competitve advantage we ever had with Auctomatic was supporting the obscure international eBay sites that the big US players ignored. I’m generalizing from pretty limited experience, but if I were a floundering start-up trying to get to cashflow positive, internationalizing is probably the first trick I’d try.
  • How dangerous the assumption that you’re going to grow is: “oh, we need to build this this way, because when we’re successful, we’ll need it”. This is often used as an argument against over-engineering for scalability, but it applies more generally. Now, when coding, I try to think: “how can I write this such that if people saw my code, they’d be amazed at how little there is and how little it does”.

Undop

August 15th, 2009

Like most internet users, I waste too much time on the web. Despite that, I’ve never had much luck with the apps that set out to solve this, like Freedom or RescueTime. They feel too heavy-handed. Instead, I want fairly repetitive and annoying prods that make wasting time less fun—the equivalent of small electric shocks, counterbalancing the Dopamine hits.

So here’s undop. Every time I visit a domain in ~/.bad_sites, it dims the display by 30%, gradually returning it to its previous brightness over the course of 30 seconds. It’s both an annoyance and a reminder. The effect is small enough that I don’t mind it on those occasions when I actually do want to read Twitter or Hacker News or whatever blog, but it’s jarring enough that I now subconsciously avoiding following links to them, and have mostly broken the check-for-new-stuff muscle memory.

Caveats: it only works with Safari on OS X. (Patches with support for other browsers welcome.) I’m guessing it might not be good for display backlights.

Facebook doesn’t want you to deactivate your account

July 5th, 2009

Screenshots to URLs

June 28th, 2009

Whenever I take a screenshot, the next step is usually to paste it into an email or IM conversation. Here’s a modified version of a launchd script for OS X, originally from Avi, that automates that: whenever you take a screenshot, it uploads it to a server of your choice, places the URL on the clipboard, and beeps. Download and execute the script to install the service. It assumes you use key-based SSH authentication.

Where’d that code go?

June 28th, 2009
$ < ~/Binaries/git-find-removal
#!/bin/zsh
if [ $# != 2 ] ; then
  echo "$0 <commit> <string>" >/dev/stderr
  exit 1
fi
git bisect start
git bisect good $1
git bisect bad
git bisect run grep -qRE $2 .
$ git-find-removal HEAD~20 'def my_important_function'

App School

June 12th, 2009

App School just went live. It’s an iPhone development training course taught by my friend Daniel, and run by SQT, my Mum’s training company, and Mulley Communications. The courses will be based in Dublin—it should be a pretty cool chance for anyone Irish to quickly get up to speed with everything related to iPhone app development (including some tips on navigating the notorious app submission process…).

I’ve known Daniel since first year in secondary school—he convinced me to learn PHP, my first real (”real”?) programming language. He’s one of the best programmers I’ve ever worked with, and just won an IBM Open Source Award for his work on Yakumo [PDF], an open-source library for using the iPhone a game input device. Despite only just graduating now, a couple of companies have already spotted his win-ness—he interned with the hardcore physics guys at Havok in San Francisco last summer.

App School is lucky to have him, and I think the courses are going to be killer.

See also: Damien, Web 2 Ireland, Irish Times.

Hacking for fun and profit with Mathematica and the Google Analytics API

April 27th, 2009

I’ve always been surprised by how much web analytics software sucks. Web sites produce reams of interesting statistical data, many sites have a strong interest in growing their traffic, and yet even the leaders in the field—Google Analytics and co.—do nothing to help: they make no attempt to analyze the data; they just display it in fairly pedestrian ways.

Every day, you log into your analytics dashboard, and you see basically the same picture that you saw the day before. It’s left up to you to find out what’s changed. Did your search referrals for some mid-ranking keyword rise hugely? Are you getting referrals from some site that never linked to you before?

Additionally, most packages don’t provide any mechanism for you to integrate your business-specific data with your web site data. Sure, you can sometimes hack this with things like tracking visits to special “checkout” pages, but fundamentally there’s no direct way of integrating off-site data (sales of an iPhone app, say).

(It looks like dshbrd may fix many of these complaints—see the end of this post for details.)

I wrote some Emacs-based software to do all of this last year (including charts in the REPL), and have been using it fairly happily. Recently, I’ve started using Mathematica more and more to process log data, and have been very happy with the results.

A few days ago, Google released an API for Google Analytics (largely invisible but enormously successful). I spent a while over the weekend writing a bridge to Mathematica, and playing with the data, particularly that related to my iPhone app (Encyclopedia, which stores a copy of Wikipedia on your phone for offline browsing).

We can start off by doing fairly standard things, like number of visits from each search term by date:

And we can, say, chart the result. (First, we remove the “(not set)” results that the API returns.)

What fraction of this is from search traffic related to the iPhone app? We can select the promising search terms, and compare them with overall search traffic (as far as I know, no boolean logic is possible in the Google Analytics web interface):

Looks like most of the Google traffic is from the app-related keywords. We can also pretty trivially look at the geographical distribution of these visitors. First, let’s load the data:

And group the result by country:

We can now define a simple WorldPlot function, and use it with our data:

(Brighter colours indicate more visits.) Okay, that’s somewhat interesting. But how many sales does the app get per visit? I track my sales in Dabble DB, so I’ll load the data from there. They provide a CSV file of country code to unit sales mappings:

We can pretty easily import this into Mathematica:

Using Mathematica’s CountryData[] function, which knows about country codes (as well as their shapes), we can easily integrate the keyword referrals and the sales data to generate a heat map of purchases per search referral:

The interesting outlier here is Mexico. Though they don’t visit the site much, they do buy the app a lot. (Hundreds of times to date.) I’m still not sure why. The two maps also show that, although Ireland sends quite a bit of traffic to the site, it converts quite poorly—perhaps because my .ie domain causes my search rank there to be artificially inflated.

Okay, ignoring the app for a while, we might also be interested in questions like “what are my most important search terms?”. One way of measuring this is to look at the total time on your site due by each search term. (Google Analytics tells you the average time on site for each term, but that’s not much help in telling you where you should direct your work.)

Let’s load the data:

And define a simple function that computes the total number of seconds on the site driven by each keyword:

We can compute the set of search terms that were used to get to the site:

And sort them by time on site:

Ignoring the first two (corresponding to “(not set)”, which we could of course filter out), it seems that “wiki”, “wikipedia” and “iphone” are the important terms.

We might also be interested to see how keyword usage changes over time. Let’s load two months of keyword data:

And define a simple function to count the fraction of referrals that are from a particular keyword in some given dataset:

We can test it with something like:

Okay, 4% of the site’s visitors came by searching for something containing the word “iPhone”.

Now let’s compare two months of data:

These are the search keywords that showed the biggest increase between October and January. And they correspond quite closely to what you’d expect—default.png files on the iPhone and Back To My Mac are both topics I wrote about in the intervening time period.

Keeping with the spirit of analysing changes, we can look at non-search referrals:

We can drop the direct referrals, group them by source, and select the first referral from each site:

And then we can do something like plot the first referral from each site against the amount of traffic it sent—a chart of buzz, basically:

Next, we can look at how traffic flows around the site. First, we load (landing page, exit page) tuples:

And then hack together a function to generate a directed graph:

Yielding a pretty interesting result:

As a final example, we can, for no good reason, take advantage of the latitude and longitude metrics that the API provides and quickly create a video of visits by hour, showing traffic move across the globe. First, we load the data, and define two helper functions:

We can test it out on one of the hours:

Looks good. Let’s export an image for each hour, which we can then join with QuickTime:

The result is here. (You probably want to have it loop when you play it.)

Mathematica doesn’t get much attention from the programming community (largely because of Wolfram’s pricing, as far as I can tell). But its power is undeniable—I spent about 5 hours writing the Google Analytics interface and generating the above data. I wrote this blog post over lunch. If anyone else is interested in using the Mathematica/Google Analytics interface, let me know in the comments, and I’ll package it up and release it somewhere (it requires modified versions of a few libraries).

Lastly, over the past year, I spent a lot of time talking to my friend Avi about the state of web analytics. He and the guys at Dabble DB decided to do something about it, and it looks like dshbrd will launch soon. From what I’ve seen so far, it looks like it’ll be win.

tsocks: a nifty utility now working on OS X

April 25th, 2009

tsocks is a cool Linux utility. Using LD_PRELOAD, it intercepts calls to the OS’s socket-related functions (connect() and co.), and transparently tunnels them through a SOCKS proxy. Example usage:

$ curl http://www.whatismyip.com/automation/n09230945.asp
89.141.232.202
$ tsocks curl http://www.whatismyip.com/automation/n09230945.asp
159.29.64.14

As it happens, curl supports SOCKS proxies, but tsocks allows you to add support to programs that know nothing about them (like, say, wget).

Sadly, it’s no longer maintained.

Marc Abramowitz got it working on OS X (patch) back in 2006 by switching to DYLD_INSERT_LIBRARIES, among other things, but even this port has succumbed to bit-rot.

So I fixed it up, and the code now lives at github.