I decided to learn Go (GoLang, Go Language, The Language of GO!) last weekend, so I’ve been busy watching tutorials and coding a bit, with Strava as my playground.
Table of contents
Open Table of contents
Lets Go
The very first thing I did was to get familiar with the Go language, but as I have programmed before I wasn’t interested in watching tutorials for beginners, but I found this nice and almost 4 hour long tutorial from Derek Banas which I watched through to get familiar with the language and basically just absorbed things.
After that there was some brain resistance concerning learning ‘channels’ and ‘concurrency patterns’, but that quickly resolved after watching some more videos
Get the data and parse it
Thanks to EU laws (I assume), all your data on Strava is easily available for download. Since Garmin has decided to be a pain in the **** and not do the same, this was the path of least resistance.
But first you have to find this scary button buried at the bottom of the Settings > My account page:

After you’ve clicked it and found a new less scary button you should receive a mail shortly with a link that downloads your data as a zip archive.
Then all I needed was some ugly noob Go code to parse it all:
// various variables are declared above here
// spawn a new goroutine to use as listener
go func() {
for {
// listen for parser results
newEntry := <-parserChan
// pick up the parsed data and store it in some variables
activityTypes[newEntry.ActivityType]++
runDistance += newEntry.Distance
// this is for making the chart below
if newEntry.ActivityType == "Running" {
grouped[newEntry.Distance]++
}
if firstDate.IsZero() || newEntry.StartTime.Before(firstDate) {
firstDate = newEntry.StartTime
}
if lastDate.IsZero() || newEntry.StartTime.After(lastDate) {
lastDate = newEntry.StartTime
}
}
}()
// a wait group lets us wait for the for loop of goroutines below to complete
var wg sync.WaitGroup
for _, file := range files {
wg.Add(1)
// for each file, spawn a separate goroutine
go func(fInfo FileInfo) {
defer wg.Done()
// read file and extract session data
session, err := fitparser.ReadFitFile(fInfo.file, fInfo.path)
if err != nil {
return
}
// get info from file
info := fitparser.GetFitInfo(*session)
// send it to the parserChan so the listener above can handle it
parserChan <- info
}(FileInfo{path, file})
}
wg.Wait()
Using concurrency like this was a nice exercise, though I would have to run this code quite a few times to get back the time I spent to save 1 second of execution time. Anyhow, it was nice to see that multi threading could reduce it to 1/3 of the original time.
Svelte & D3.js
To actually have some result to put on the web page I decided to use D3.js and get some bar charts. To be able to use dynamic content like D3 in Astro you have to use a library like React, Vue or Svelte, so I went with Svelte since I haven’t used it before.
I’m not sure if React will be the dominant library for forever, and I don’t think it’s a good idea to focus all your time on a library/framework, so one should definitely try new things if one have the opportunity.
Anyway, check it out