Gamification for me as a software developer

December 21, 2012
3 comments Web development

"Gamification is the use of game-thinking and game mechanics in non-game contexts in order to engage users and solve problems" -- wikipedia

Gamification sneaks into a software developer's life whether he/she likes it or not. Some work for me, some don't.

What works for me

  1. PyPI downloads on my packages
    Although clouded with inaccuracies and possible false positives (someone's build script could be pip installing over zealously), seeing your download count go up means that people actually depend on your code. Most likely, they're not just downloading to awe, they download to use it.

  2. Github followers and Starred projects
    Being followed on Github means people see your activity on their dashboard (aka. home page). Every commit and every gist you push gets potential eyes on it.
    When people star your project it probably means that they're thinking "oh neat! this could come in handy some day
    so I'll star it for now". That's kinda flattering to be honest.

  3. Twitter followers
    This doesn't apply to everyone of course but to me it does. I really try my best to write about work or code related stuff on Twitter and personal stuff on Facebook. Whenever a blog post of mine gets featured on HN or if I present at some conference I get a couple of new followers.
    Some people do a great job curating their followers, responding and keeping it very relevant. They deserve their followers.
    Yes, there are a lot of bogus Twitter accounts that follow you but since that happens to everyone it's easy to oversee. Since you probably skim through most of the "You have new follower(s)" emails, it's quite flattering when it's a real human being who does what you do or somewhat similar.

  4. Activity on Github projects
    This one is less about fame and fortune and more of a "damage prevention". Clicking into a project and seeing that the last commit was 3 years ago most definitely means the project is dead.
    I have some projects that I don't actively work on but the code might still be relevant and doesn't need much more maintenance. For those kind of projects it's good to have some sporadic activity just to signal to people it's not completely abandoned.

  5. Hacker News posts and comments "Show HN: ..."
    I've now had quite a few posts to HN that get promoted to the front page. Whenever this happens you get those almost [embarrassing spikes in your Google Analytics account/static/cache/7c/3b/7c3be91fa89401add4f423e944878706.jpg).
    However, it happened. Enough people thought it was interesting to vote it up to the front page.
    It's important to not count the number of comments as a measure of "success" because oftentimes comments aren't simply constructive feedback but just comments on other comments.
    Keep this one simple, the fact that you have built something that is "Show HN:..." means you probably have worked hard.

What does NOT work for me

  1. Unit test code coverage metrics
    Test coverage percentages are quite a private matter. Kinda like your stool. Unless something amazing happened, keep it to yourself.
    It's nice to see a general increase of the total percentage but do not dare to obsess about it. What matters is that you look through the report and take note that what matters is covered. Coverage on code that is allowed to break and isn't embarrassing if it does, does not need to be green all the way. Who are you trying to impress? The intern you're mentoring or the family you don't have time to spend time with because you're hunting perfection?
    I must, however, admit that I too have in the past inserted pragma: no cover in my code. Also, being able to say that you have 100% test coverage on a lib can be good "advertisement" in your README as it instills confidence in your potential users.

  2. Number of tests
    When you realize that 1 nicely packaged integration test can test just as much as 22 anally verbose unit tests you realize that number of tests is a stupid measure.
    A lot of junior test driven developers write tests that cover circumstances that are just absurd. For example "what if I pass a floating point number instead of a URL string which it's supposed to be??".
    Remember, results and quality count. Having too many tests also means more things to slow you down when you refactor.

  3. Commit counts
    On projects with multiple contributors commit counts is not a measure of anything. It has no valuable implications or deductions. Adding a newline character to a README can be 1 count.
    If you skim through the commit log on a Github project you'll notice that surprisingly many commits are trivial stuff such as style semantics or updating a CREDITS file.
    Yes, someone has to do that stuff too and we're always appreciative of that but it's not a measure of excellence over others. It's just a count.

  4. Resolved bugs/issues count
    If this mattered and was a measure of anything you could simple just swallow everything with a quick turnaround and resolve or close it.
    But not every bug deserves your attention. Even if it is a genuine bug it might still be really low priority which working on costs time and focus distraction away from much more important work.

  5. Number of releases
    It's nice to see projects making releases (or tags) but don't measure things by this. There's so much good quality software that doesn't really fit the release model.

My new web marketing strategy: Begging

December 9, 2012
13 comments Web development

From one of the monthly summary emails
Building a side project is fun. Launching it is fun. Improving and measuring it is fun. But marketing it is aweful!

Marketing your side project means you're not coding, instead you're walking around the interwebs with your pants down trying your hardest to get people to not only try your little project but to also get beyond that by tweeting about it, Facebook status update about it, blog about it or use whatever devices inside it to help the viral spread. Now that! ...is freckin hard.

I'm struggling to even get my best friends and my wife to even try my side projects. I can't blame them, unlike a lemonade stand at a farmers market it's very impersonal. When I tried to get my buddies to try Around The World several did but only very briefly and granted some few did give me feedback but it's really not much to go by.

So, today I'm launching the start of my new web marketing strategy: Begging

Or rather, politely asking people to help me. Instead of using the usual "we" or "our" language I'm referring to it in first person instead. The platform for this strategy experiment is on HUGEpic and it looks like this: hugepic.io/yourhelp/

I'm recently built a feature into HUGEpic that once a month emails everyone who uploaded a picture a little summary of their upload and the number of hits and comments and boldly in the footer of this email there's a link to the /yourhelp/ page (see screenshot above).

Let's see how this works out. Mostly likely it'll be just another noise in the highways of peoples' internet lifes but perhaps it can become successful too.

Mind you, the motives of all of this is for my "insert-sideproject-name-here" to become successful. And by successful I mean popular and lots of traffic. None of my side projects make me any money which makes it easier to beg. However, none of them make any money for the people I'm asking for help. Perhaps that's what could be the version 2.0 of my web marketing strategy.

Introducing: HUGEpic - a web app for showing massive pictures

November 3, 2012
19 comments Python

So here's my latest little fun side-project: HUGEpic.io http://hugepic.io

Zoomed in on Mona Lisa
It's a web app for uploading massive pictures and looking at them like maps.

The advantages with showing pictures like this are:

  • you only download what you need
  • you can send a permanent link to a picture at a particular location with a particular zoom level
  • you can draw annotations on a layer on top of the image

All the code is here on Github and as you can see it's a Tornado that uses two databases: MongoDB and Redis and when it connects to MongoDB it uses the new Tornado specific driver called Motor which is great.

Truncated! Read the rest by clicking the link below.

Fastest way to thousands-commafy large numbers in Python/PyPy

October 13, 2012
15 comments Python

Here are two perfectly good ways to turn 123456789 into "123,456,789":



import locale

def f1(n):
    locale.setlocale(locale.LC_ALL, 'en_US.UTF-8')
    return locale.format('%d', n, True)

def f2(n):
    r = []
    for i, c in enumerate(reversed(str(n))):
        if i and (not (i % 3)):
            r.insert(0, ',')
        r.insert(0, c)
    return ''.join(r)

assert f1(123456789) == '123,456,789'
assert f2(123456789) == '123,456,789'    

Which one do you think is the fastest?

Truncated! Read the rest by clicking the link below.

hastebinit - quickly paste snippets into hastebin.com

October 11, 2012
9 comments Python, Linux

I'm quite fond of hastebin.com. It's fast. It's reliable. And it's got nice keyboard shortcuts that work for my taste.

So, I created a little program to quickly throw things into hastebin. You can have one too:

First create ~/bin/hastebinit and paste in:


#!/usr/bin/python

import urllib2
import os
import json

URL = 'http://hastebin.com/documents'

def run(*args):
    if args:
        content = [open(x).read() for x in args]
        extensions = [os.path.splitext(x)[1] for x in args]
    else:
        content = [sys.stdin.read()]
        extensions = [None]

    for i, each in enumerate(content):
        req = urllib2.Request(URL, each)
        response = urllib2.urlopen(req)
        the_page = response.read()
        key = json.loads(the_page)['key']
        url = "http://hastebin.com/%s" % key
        if extensions[i]:
            url += extensions[i]
        print url


if __name__ == '__main__':
    import sys
    sys.exit(run(*sys.argv[1:]))

Then run: chmod +x ~/bin/hastebinit

Now you can do things like:

$ cat ~/myfile | hastebinit
$ hastebinit < ~/myfile
$ hastebinit ~/myfile myotherfile

Hopefully it'll one day help at least one more soul out there!

How I stopped worrying about IO blocking Tornado

September 18, 2012
5 comments Tornado

So, the cool thing about Tornado the Python web framework is that it's based on a single thread IO loop. Aka Eventloop. This means that you can handle high concurrency with optimal performance. However, it means that can't do things that take a long time because then you're blocking all other users.

The solution to the blocking problem is to then switch to asynchronous callbacks which means a task can churn away in the background whilst your web server can crack on with other requests. That's great but it's actually not that easy. Writing callback code in Tornado is much more pleasant than say, Node, where you actually have to "fork" off in different functions with different scope. For example, here's what it might look like:



class MyHandler(tornado.web.RequestHandler):
    @asynchronous
    @gen.engine
    def get(self):
        http_client = AsyncHTTPClient()
        response = yield gen.Task(http_client.fetch, "http://example.com")
        stuff = do_something_with_response(response)
        self.render("template.html", **stuff)

It's pretty neat but it's still work. And sometimes you just don't know if something is going to be slow or not. If it's not going to be slow (e.g. fetching a simple value from a fast local database) you don't want to do it async anyway.

Truncated! Read the rest by clicking the link below.

Introducing: League of Friends on Around The World

September 15, 2012
0 comments Web development

League of Friends
After about a month of weekend development the League of Friends is finally finished.

Usually on games like this, if it has a highscore list you might find yourself at number 3,405,912 and the people at the top of the highscore list are people you've never heard of so what's the point of comparing yourself with them?

Inviting someone by email
On Around The World, you select your own friends for your league. Everyone you invite get an email asking if they want to accept it mutually. If you want to invite someone who isn't already on Around The World, you can type in their email address and complete an email that gets sent to that friend on your behalf from Around The World.

About Peter
Also with this, you can click on any of your travelling friends and get lots more details about their progress. It doesn't reveal anything about how smart or not smart that friend is so you never have to worry about looking stupid because it never reveals with easy questions you accidentally got wrong.

Real-timify Django with SockJS

September 6, 2012
4 comments Django, JavaScript, Tornado

In yesterdays DjangoCon BDFL Keynote Adrian Holovaty called out that Django needs a Real-Time story. Well, here's a response to that: django-sockjs-tornado

Immediately after the keynote I went and found a comfortable chair and wrote this app. It's basically a django app that allows you to run a socketserver with manage.py like this:

python manage.py socketserver

Chat Demo screenshot
Now, you can use all of SockJS to write some really flashy socket apps. In Django! Using Django models and stuff. The example included shows how to write a really simple chat application using Django models. check out the whole demo here

If you're curious about SockJS read the README and here's one of many good threads about the difference between SockJS and socket.io.

The reason I could write this app so quickly was because I have already written a production app using sockjs-tornado so the concepts were familiar. However, this app has (at the time of writing) not been used in any production. So mind you it might still need some more love before you show your mom your django app with WebSockets.

django-mongokit now compatible with Django 1.4

August 11, 2012
0 comments Python

I've finally had time to sort out the django-mongokit code so it's now fully compatible with Django 1.4.

Because I don't personally use the project I've sort of got myself lost in various patches from some awesome contributors who keep it in check.

Also, thanks to Marc Abramowitz who added a tox.ini which I've now updated to also test python 2.7 and Django 1.4

Go forth and build awesome Django apps with MongoKit which is still think is the best wrapper available on PyMongo out there.

US License Plate Spotter (part 2)

August 8, 2012
0 comments JavaScript

screenshot
Last month I built a very basic mobile app using jQuery Mobile. It's still available here.

One flaw I found with jQuery Mobile is that it's a bit slow. Scrolling up and down feels sluggish. It looks pretty though.
This time around I opted instead to use Twitter Bootstrap instead. (inspired by some other blog post with a similar experience)

Also, with this version I've set up a domain name: uslicensespotter.com
The source code is available here and there are some interesting pieces of this that I'd like to delve into deeper.

Optimization

This new app feels faster and scrolling is smoother. There is still some parts where it doesn't feel snappy. The primary part is when you click one of the buttons. It works something like this:



// binding (simplified)
  $('form a.btn').click(function(event) {
    var $el = $(this);
    var id = $el.attr('id');
    if ($el.hasClass('btn-success')) {
      switch_off($el);
      State.remove(id);
    } else {
      switch_on($el, new Date());
      State.add(id);
    }
    return false;
  });


// the switch_on function
  function switch_on($el, timestamp) {
    $el.addClass('btn-success');
    $('i', $el).addClass('icon-white').removeClass('icon-remove').addClass('icon-check');
    $('span', $el).text(timeSince(timestamp));
  }

There are two potentials for making this faster.

  1. Instead of using element.click(...) I can use touch events which supposedly fire better thus starting the actual animation earlier.
  2. Instead of modifying the element (adding a class, adding a class, removing a class, adding a class, changing the text) what I could do is to remove the element from the DOM, manipulate it and then re-insert it back into the DOM. That way the (mobile) browser doesn't have to re-render after each manipulation.

My next task is to apply both of these ideas and try to somehow keep and eye on which makes the biggest impact.

Deployment

One neat new feature with this new code is the deployment script, build.py. The actual code might be a bit of a mess but the way it works for me is great.

What I do is that I work on the app by editing dev.html and when I deploy I run python build.py and it opens dev.html and concatenates and minifies all CSS and Javascript ready for ideal caching. This reduces the static assets down to just three files weighing only 78Kb altogether.

(Note: even more can be done such as switching to ZeptoJS and removing bootstrap stuff I don't need with a custom download)

What the script does is that it parses the dev.html template with lxml and applies whatever transformations it needs to do such as generating the Apple touch images eg. this one

I think a lot of mobile web developers can benefit from this script. Maybe you don't want to copy it verbatim but you might want to copy it and do the transformations you want to do.