The Run Time Predictor was actually the first thing on Sconewrong and what caused the site that became this blog to be setup. It started when I was playing about in developing website backends using Python, fusing with my running hobby.
I'd been experimenting with Django, and while it's a really powerful framework I was frustrated how apparently difficult it was to do the basic stuff (without databases, migrations, admin panels etc). This led me to Bottle, which is what the predictor was originally written in - but then I realised Bottle was just trying to be a simpler Flask, which turned out to be the framework I really wanted. What a rollercoaster.
I wanted the predictor to do exactly what it said on the tin, keeping it as basic as possible. I wanted it all in the backend, with no Javascript calls, no cookies/analytics, just a super clean experience.

The idea of a time predictor based on pace and distance doesn't at first glance come across as the most complicated thing in the world - but hey, its hard to do in your head at least. Why? Well the distance input is a simple multiply, but the pace is in this awkward minutes and seconds format. Also, what about the conversion between imperial and metric if the distance and pace inputs are different?
It started all in a single Python file, both the Flask web backend code and the time prediction code - but this got messy fast. I decided to break the prediction code out into its own module with associated tests (using PyTest) and this let me really focus on getting the functionality correct (although this happened way after the first working version of the time prediction web app).
I started with a pace class that you initialise with a given pace in terms of minutes and seconds, and a distance class that you initialise with the relevant distance. I also capture in these classes whether the object represents an imperial or metric measurement. Initialised pace and distance objects are then passed as arguments to a 'get duration' function, which first checks the system (metric/imperial) used on each and makes appropriate conversions. There is a trick here to maximise the accuracy of the result: we don't simply convert to either metric/imperial based on our preference - we should always preserve the pace as this is quantised to seconds, and do any conversion on the floating point distance value. The logic is simplified by a method in the pace class to spit out an absolute value in seconds, and the duration class has a class method to additionally initialise based on an absolute seconds value. As we are dealing with formatted strings from the web app, the pace and duration classes also have class methods to initialise from a string which is then parsed.
The web backend is very straight-forward. In Flask terminology we have a single 'route', which is split based on whether the request is a POST or GET. The GET method displays the form, with values optionally pre-filled from URL parameters - used for providing 'last time' defaults for when the form is loaded again. The POST method processes the form: if there are any errors it displays the form again with erroneous areas highlighted, else it sends the values over the the time predict module discussed above and then displays the answer using a separate template. The front end was enabled by a lightweight CSS boiler plate called skeleton.css (with some modifications on top of course), and the form processing was made a lot easier with the help from Flask-WTF.
What the Run Time Predictor achieves in real-terms may be modest, but it was an enjoyable little project that brought together my front-end and back-end programming for the first time in years. For me at least it is a quick little utility for working out what time I might achieve at a different distance keeping the same pace, and yes the Pace Predictor for a given time and distance is of course in the works.
Top ^