plinky - A bit like Bitly

I recently got frustrated with Bitly as a url shorter and decided to write my own simple alternative.

The result is a very small (and prety dumb) Python web app that will allow short url to be redirected to other (longer) urls, and will capture some stats about how often those links are being used.

That web app is called plinky, and you can find the source code on GitHub.com:

https://github.com/martinpeck/plinky

The Problem with Bitly

On Bitly you can set up custom domains. These allow you to replace the bit.ly part of any short link with your own short domain name.

Each short link on Bitly is made up of the domain plus a hash. The hash is autogenerated by Bitly when you ask them to shorten the link.

For example, in the short link…

http://bit.ly/1X5IvtX

… (a link to this blog) the domain is bit.ly and the text 1X5IvtX is the hash.

If you want, you can then customize your short links to make the hash easier to read/type.

For example, I’ve customized the previous short link to be:

http://bit.ly/martinpeck

So, with a custom domain, you are essentially replacing the bit.ly domain with your own.

However, even with a custom domains, all hashes must be globally unique across the whole of Bitly. This means that if someone has already used the hash martinpeck for a short url. That sounds fair enough, but this rule is enforced across custom domains too. So, regardless of whether the domain would make the short url look unique, the hash must be globally unique across all of Bitly and all of the custom domains.

The result is that you end up spending a lot of time trying to find useful hashes and, in many cases, the hashes get very long which defeats the purpose of using a link shortener.

The other problem with Bitly is that you can’t ever change the final location of a short url. Once created, you can never edit the short url to direct users to a different resource. This is a real problem if you’ve printed the short url on posters or leaflets, or if the destination url changes for reasons you can’t control. I’m sure there are very good reasons why changing the redirects for short urls is a bad idea but, combined with the difficulty in finding unique hashes in the first place it’s sometimes desirable to update one.

The Solution - Write Your Own

My solution to this was to stop using Bitly, to say to myself “it can’t be that hard to redirect web requests”, and to write my own.

Now…I’ve not written anything nearly as complicated or feature rich as Bitly. I’ve written the stupidest thing that does what I need:

  1. accept an HTTP request
  2. look up the destination
  3. respond with an HTTP 301 redirect to the final destination.
  4. track all such requests
  5. respond with a default redirect if the lookup fails

Plinky is written in Python, and uses the flask micro-framework. I picked flask because I’d not really played much with flask. I’ve used Sinatra (with Ruby), but hadn’t tried flask. Plinky is hardly the most complicated example of a flask app, but I certainly found it simple to set up and get working.

At the heart of Plinky is a YAML file that contains a list of hashes with the intended destinations. If you look at the example YAML file in Github you’ll see it looks like this…

# default, if other shorturls can't be found
default: https://github.com/martinpeck/plinky

# some github short urls for testing
me: https://github.com/martinpeck
issues: https://github.com/issues/assigned
stars: https://github.com/stars

The default hash is used any time that a hash lookup fails. The other name/value pairs are short url hashes and their redirect destinations.

Plinky just sits there looking up hashes and issuing HTTP 301 redirects. If you look at the code you can see that there’s not much to it really.

plinky.py is the main entry point for HTTP requests. It sets up a handful of routes (some of which are a work in progress) but the main one is this…

@app.route("/<path:shorturl>", methods=['GET'])
def redirect_to_short_url(shorturl=""):
  tracking.track_redirect(shorturl)
  return redirect(shortcuts.lookup_shorturl(shorturl), 301)

This route tracks the redirect event using some code in tracking.py and then performs the HTTP 301 redirect using some code in shortcuts.py

Plinky uses Segment to track how many times a given hash is used for redirect. This is optional, and controlled by the existance of an environemnt variable holding the key that Segment requires.

Segment is a service that takes events and then hands them off to 1 or more other analytics services. So, you can send a single event to Segment and have Segment issue an analytics event to Google Analytics, MixPanel or a whole host of other analytics endpoints. This makes it super easy to add and replace the services you use for analytics.

And that’s about it. If you deploy Plinky to Heroku it’ll sit there and preform redirects for you.

Another Use for Plinky

At the place I work we recently deprecated one of our domains and wanted to set up redirects to the new domain and new URL structure. Plinky was perfect for this.

Plinky just needs name/value pairs in the configured YAML file, and it really doesn’t care in the name is more complex than a few characters. So, if you set up the short urls like this…

old/url/structure: https://www.some-new-domain.com/new/url/structure
old/url/structure/example1.html: https://www.some-new-domain.com/new/url/structure/example-one
old/url/structure/example2.html: https://www.some-new-domain.com/new/url/structure/example-two

… and then configure a Plinky instance, via DNS, to sit on your old domain, then it can sit there and redirect your users to the new domain and new url strucutre, and if you’re using the tracking feature you can see whether this traffic slowly migrates over to your new domain.

Again, I’m sure there are better ways to do this, but this one got me and my team out of a hole and worked really well.

TODO

There are some things I want to improve with Plinky. For example, I want to add some stats and info pages to the service so that it’s easier to see how the short urls are set up. If you have any suggestions, or see any problems, please log an issue in the GitHub Issues database for this project.

First things First

One of the things I find, when volunteering at the school where I run a Code Club, is that the kids always want to spend lots of time drawing backgrounds for their Scratch games, or creating awesome sprites. Sometimes they spend more time doing this than actually writing code.

So, for this week, I thought I’d try showing them how I go about designing a Scratch game and how I try and get the logic of the game working first, and make it look pretty later. We’re building Viking themed quiz games (a little like Code Club’s Brain Game project).

First, I showed them this sketch that I’d made to help me think about the game. It’s deliberately “scrappy” in nature, with some simple bullet point notes about what I want to happen in the game…

Scratch game sketch

Next, I showed them how I took my scrappy sketch and built a game with equally scrappy graphics…

Initial Scratch Game

You can see this project here: https://scratch.mit.edu/projects/95911754/#player

As you can see, I’ve kept my poor quality graphics and concentrated on getting my Scratch code working.

I then explained that, once the game was working, I went back and make it look better by adding better images and enhancing the game with some animations. Here’s the final game that I showed them…

Final Scratch Game

You can see this project here: https://scratch.mit.edu/projects/95721352/#player

My hope, in all of this, was that by showing them this progression…

  1. plan what you’re going to build
  2. write a game that works, without worrying about the graphics
  3. add better graphics and animation to your final game

… that they would focus on getting their games working before they then spent a lot of time making them look nice.

Did it work?

No…not really.

They did take some time to plan out their games on paper. However, as soon as they moved to the computers the lure of the sprite and background editors was too much for them. To be honest, I can’t blame them - it’s the bit that’s most fun.

Perhaps my mistake was showing them my final/finished project. Maybe I should have held back the finished project for another week. I’ll try this next time.

Volunteering for Code Club

I joined Code Club in Jan 2015 to head up their engineering team. However, way before this I was already voluneering for Code Club.

Here’s why I started volunteering and what I get out of it…

What is a Code Club?

Code Club is an organisation that helps set up after school coding clubs for kids, aged 9 to 11. The clubs are generally run by a teacher, and a volunteer. Most clubs run after school, but not all of them…mine runs once a week at lunchtime.

At the club we use the Code Club lesson materials, which can be found at https://www.codeclubprojects.org/, and the kids work through these projects each week.

As a volunteer, I’m there to help explain some of the concepts they’re learning, to help them when they get stuck etc. There’s a teacher with me too, who also helps the kids with the lesson but is also in charge of “crowd control”.

The idea is to introduce the kids to coding, but also to other concepts such as computational thinking, problem solving, planning, designing and collaboration.

Why did I start volunteering?

I started volunteering for Code Club back in April 2013. My son brought home a news letter from his school, in which they were asking for someone to help start a Code Club. I jumped at the chance, got myself registered with Code Club, and soon had the club up and running.

Is it hard to volunteer?

It’s 1 hour a week, during term time. The school I volunteer at is just around the corner from my house so it’s not a big deal in terms of time.

The projects that Code Club provide are really well structured. For the first few sessions you’ll probably want to read through the project and the volunteer notes before you turn up (which might mean you spend an hour, one evening, doing the lesson yourself). However, you soon get into the swing of things and that preparation time goes away.

I suspect that most people who work with computers during the day (not just programmers), who have a methodical approach to things (i.e. can read and follow instructions), and who are willing to learn new stuff could successfully volunteer at a Code Club.

What’s the best bit about volunteering?

For 1 hour each week I get to work with a group of programmers who are super keen and really interested in learning to code. It doesn’t matter how crappy my week has been, at the end of that hour I’m buzzing from the enthusiasm and energy that the kids have. They want to learn, and they really appreciate the help I’m giving them.

My advice to anyone considering volunteering for Code Club is do it! I was really nervous before my first club session (“What if the kids don’t like me?”, “What if they know more than I do?”) but after that first session I realised that I had nothing to worry about. Even if it’s just for a term, give it a go and help some kids learn to code.

https://www.codeclub.org.uk/register

Creating Github Issue Labels

If you use GitHub Issues for tracking work and bugs, then you probably also use labels for categorizing or highlighting those issues. You might also use labels for applying some sort of workflow, such as highlighting which issues are ready to be worked on, in progress, or blocked.

I have a set of labels that I tend to use in all of my GitHub projects. Creating them by hand is a pain. So, to fix this, I’ve written a python script that does this for me…

https://github.com/martinpeck/gh-issue-label-generator

The definition of what labels I want, and which colour to use for them, is described a definitions.json file. For example, here are the definitions I generally use…

{
  "label" : [
    {"name": "bug", "color": "eb6420"},
    {"name": "enhancement", "color": "eb6420"},
    {"name": "question", "color": "eb6420"},
    {"name": "by design", "color": "fbca04"},
    {"name": "duplicate", "color": "fbca04"},
    {"name": "not repro", "color": "fbca04"},
    {"name": "wont fix", "color": "fbca04"},
    {"name": "low priority", "color": "207de5"},
    {"name": "important", "color": "e11d21"},
    {"name": "help wanted", "color": "159818"},
    {"name": "in progress", "color": "ededed"},
    {"name": "ready", "color": "ededed"},
    {"name": "blocked", "color": "000000"}
  ]
}

The script then does all the hard work for me.

It’s a pretty dumb script at present, taking no account of labels that already exist - it’ll fail to create the label if it already exists, and goes on to the next one. It will also leave any other labels alone. I may get around to changing some of these things…but don’t hold your breath.

Feedback

If you see a problem with the script, or have any suggestions for how it could be improved, then add something to the issues on GitHub.com.

Initial Commit

Finally, after a very long time, I’ve got off my backside and thrown togther the most basic blog possible. I used to have a blog hosted on MSDN from my Microsoft days. That’s been untouched for some time now, but it still has one or two almost-interesting things on it (to me, at least). It’s here if you want to see it: http://blogs.msdn.com/b/mpeck/

I’ve picked Jekyll to build my blog partly because I’m using it in my day job, but mostly because I love the way it works. Working in markdown, and building a static site from that content, makes a lot of sense to me. I’d much rather edit my posts in Sublime Text, and use git to publish them, than deal with a CMS. Jekyll also appears to be the tool of choice for a number of major blogs too, including the StackOverflow blog which has just moved acrosss from Wordpress, so I’m in good company.

Anyway, I’ll try and update this site with something new once a week. I can’t always promise it’ll be useful or interesting.

There’s plently for me to do here. I need to apply some styles, get some analytics hooked up, and make this place feel more like home…

… I’l let you know how that goes.

}