Distributing Real World Tasks with a Web Application

True Story Follows

So we’ve been on the grind with Workout Generator, and the numbers are looking reasonably good:

mixpanel

After almost 2 weeks in production, we’ve gotten over 60 people to enter credit card information to agree to a free trial potentially followed by a monthly payment. Of the people that begin the signup process, a little less than 10% continue through payment. It could stand to reason then that if we could increase traffic to the site, the payments could be scaled up as well

The Plan to Raise the Numbers

Right now, there are about 200 to 300 people that visit our site daily. Those people are visiting the site because they searched “Workout Generator” in Google. We want to create additional inlays into the site with as little work and cost possible.

One such strategy is to create other content that’s free that leads users to the application. Given the current infrastructure that’s been setup, the easiest thing I could think of it would be to create a separate site, say “ExerciseDatabase.com” or something like that (I haven’t bought or even checked out that domain, but that’s the idea), and create a separate site that’s just an encyclopedia of exercises with video demonstrations. It seems like a relatively quick win because:

  • The exercise database already exists that I can filter against
  • Competition for a similar site sucks
  • Ideally I could create an application with hundreds of pages (1 for each exercise) that could potentially rank high on The Google
  • The time it would take to setup such a site would take me only a couple of hours

The Problem

Everything sounds good so far, but the downside is that the video quality of the existing exercises is not perfect. As standalone demonstrations there’s not too much of a wow factor.

Screen Shot 2015-02-07 at 5.46.04 PM

You can see the above image as a sample of poor video quality. At the time we put this together, I was off fighting The Great War in Afghanistan, and it was back in 2K9 when none of us had a cool SLR camera.

Moreover, if we can re-film the videos, then not only can we use them for external purposes to try and garner traffic, but the video demonstrations on the app itself will drastically improve quality.

The Solution

Things have changed a bit since 5 years ago. Now I have a nice camera, and I have a brother-in-law that’s on the USA’s Olympic Rugby team.

He expressed interest in helping us out with a few of his teammates. All of them lift weights and are generally capable of crushing skulls. Also, a lot of them have sweet tattoos.

sweet_tat

So we need to re-film about 700 exercises, and we can get help from a handful of people. Maybe 5 to 10 I guess? So given that I’m getting the help from all these guys, I wanted to make the tasks they were helping me with as simple as possible.

A typical person that doesn’t even lift AND doesn’t even code would probably put together a spreadsheet of exercises, maybe print them out, maybe divvy out by person. Maybe spread the task out over a few days to make it manageable.

But as a programmer, it could be made pretty painless to write a quick web application that divvies out exercises automatically. One of the lifters could simply visit a website on his phone and see the current video demonstration, then he would just need to do the exercise and mark it as filmed. Exercises would be unique to each request, and they’d be ordered by required equipment in order to batch together related exercises.

In this way, there’s close to no overhead. One person films, and people line up and just complete exercises one after another.

The Finished Web Application

Screen Shot 2015-02-07 at 5.49.27 PM

The web application is super simple and loads super fast and has no styling. I wrote an app in about an hour and just deployed it to Heroku.

There’s just one URL, one view, and one model. Here’s the entire essence of the view code. The model is just an implementation of the method calls you see here:

def home(request):
    if request.method == "POST":
        action = request.POST['action']
        action_map = {
            'discard': Film.mark_will_not_film,
            'later': Film.mark_in_progress,
            'filmed': Film.mark_filmed,
        }
        fn = action_map[action]
        exercise_id = int(request.POST['exercise_id'])
        fn(exercise_id)

    try:
        exercise = Film.get_next_exercise()
    except ValueError:
        return HttpResponse("<h1>YOU'RE ALL DONE!  THANKS!</h1>")
    finished_count = Film.get_finished_count()
    total_count = Film.get_total_count()
    render_data = {
        "dev": True if os.environ.get("I_AM_IN_DEV_ENV") else False,
        "video_id": exercise.video_id,
        "exercise_name": exercise.name,
        "finished_count": finished_count,
        "total_count": total_count,
        "exercise_id": exercise.id
    }
    return render_to_response("basic_navigation/base.html", render_data)