Thursday, February 4, 2016

My experience with golang

I rewrote a big part of Trackprofiler, my online GPS track editor. The web application is still mostly Python, the main difference is that all the GPS tracks manipulations (GPX files) are done in a microservice written in Golang. The main reason is that Python proved to be too slow and memory hungry for big GPX files.

I'll list a few things I learned in the process of rewriting it to Golang:

First, I want to emphasise that learning Golang has a lot less "WTF moments" than learning other languges.

My project has cca 9000 lines of code. I think that equivalent Python code is shorter, but if you write unit tests (you should), a lot of the Python ones will test things which in Golang aren't needed (because because they are caught by the compiler!).

The golang code tend to have more (but shorter) lines because in Golang you don't write things like:
something.DoSomething().DoSomethingElse().ThirdOperation()
Any of the .DoSomething(), DoSomethingElse(), ... calls can "throw" an exception. In many languages you just expect that somebody else will catch those exceptions. In Golang there is no "throw an exception". If there is an error you need to handle it immediately. The result is that you write every operation in a new line, and not cram them all in one.

But that's not necessarily bad, you have more lines, but they are all simple operations and easier to read and understand.

I thought that a big problem would be no DOM-based XML parser, but I love the builtin JSON and XML APIs!

Versioning dependencies sucks.

There are a lot of libraries*, but most are not mature enough. This will probably change with time.

And, yeah, it has no generics.

*If you are interested, here are my own open source libraries and utilities:

typescriptify golang structs

I'm a big fan of Go(lang).

I know, I know, Go don't have generics. I miss them, too. But on the other side -- it's simple, it's fast, vim go is great. Writing code is straightforward, it's readable. Golang is more like a better C (with a more consistent API and a garbage collection) with a feeling of a scripting language. It is not a "better Java".

Another language I (started to) like is Typescript. Not because I especially like the language or its syntax. It's because it is:
  • typesafe,
  • compiled to Javascript and the resulting code is similar (almost line-to-line) to the original Typescript code (making debugging very easy).
In my latest side project I decided to go the Go+Typescript way. There was only one thing missing. It is a web application with a lot of Javascript (i.e. Typescript code), but the data used in Typescript was not typesafe. On the server, the data is represented with Golang structs, but Typescript receives only their JSON representation. 

I solved the problem by writing a library which converts Golang structs to Typescript classes: github.com/tkrajina/typescriptify-golang-structs. 

It's simple, you just:
tscriptify -package=package/with/your/models -target=target_ts_file.ts Model1 Model2
....and then include target_ts_file.ts in your TypeScript scripts.

Make this step part of your bild process and... Now, if you change a field name in Golang -- the javascript/TypeScript compile will fail!

Wednesday, January 6, 2016

Golang GPX library

My golang port of gpxpy is finished, it's called (guess, guess...) gpxgo.

The first version of the port was done by Peter Vasil and I decided to continue from there. But my main aim was to implement a complete GPX 1.0 and GPX 1.1 specification. But, since his library was based on an older version of gpxpy, it was difficult to "reconcile" the different object models --so, I decided to change the library API. And this is how a new library is born.

Usage example:

import (
    ...
    "github.com/tkrajina/gpxgo/gpx"
    ...
)

gpxBytes := ...
gpxFile, err := gpx.ParseBytes(gpxBytes)
if err != nil {
    ...
}

// Analyize/manipulate your track data here...
for _, track := range gpxFile.Tracks {
    for _, segment := range track.Segments {
        for _, point := range segment.Points {
            fmt.Print(point)
        }
    }
}

// (Check the API for GPX manipulation and analyzing utility methods)

// When ready, you can write the resulting GPX file:
xmlBytes, err := gpxFile.ToXml(gpx.ToXmlParams{Version: "1.1", Indent: true})
...
Like gpxpy, gpxgo includes a command line utility to get some basic stats from .gpx files:

$ gpxinfo Mojstrovka.gpx
File: /Users/puzz/golang/src/github.com/tkrajina/gpxgo/test_files/Mojstrovka.gpx
GPX name:
GPX desctiption:
GPX version: 1.0
Author:
Email:


Global stats:
 Points: 184
 Length 2D: 2.6958067369682577
 Length 3D: 3.00439590990862
 Bounds: 46.430350, 46.435641, 13.738842, 13.748333
 Moving time: 0
 Stopped time: 0
 Max speed: 0.000000m/s = 0.000000km/h
 Total uphill: 446.4893280000001
 Total downhill: 417.65524800000026
 Started: 1901-12-13 20:45:52 +0000 UTC
 Ended: 1901-12-13 20:45:52 +0000 UTC


Track #1:
     Points: 184
     Length 2D: 2.6958067369682577
     Length 3D: 3.00439590990862
     Bounds: 46.430350, 46.435641, 13.738842, 13.748333
     Moving time: 0
     Stopped time: 0
     Max speed: 0.000000m/s = 0.000000km/h
     Total uphill: 446.4893280000001
...etc...

Sunday, January 3, 2016

Cartesius: Simple python coordinate system graphing library

Cartesius is a simple python library for writing coordinate system images. The main reason why I started it was that existing libraries depended on C/C++ modules which are not available on google appengine python SDK. Cartesius has only one dependency -- PIL.

Example usage:

import cartesius.main as cartesius
import cartesius.elements as elements
import cartesius.charts as charts

coordinate_system = cartesius.CoordinateSystem()

# list or tuple of two-element tuples (value, label):
piechart_data = (
    charts.data('abc', 1),
    charts.data('cde', 2),
    charts.data('efg', 4),
    charts.data('ijk', 1),
    charts.data('lmn', 5),
    charts.data('opq', 5),
    charts.data('xyz', 3),
)
piechart = charts.PieChart(data=piechart_data, color=(0, 0, 0))
coordinate_system.add(piechart)

# No need for axes:
coordinate_system.add(elements.Axis(horizontal=True, hide=True))
coordinate_system.add(elements.Axis(vertical=True, hide=True))
The result is:
More examples in the README.

Sunday, October 4, 2015

gpxpy 1.0

It's long overdue, but the 1.0 version of my python library for parsing/manipulation of GPX files (gpxpy) is out. It contains too many changes to list them here, but it can be summarised as: gpxpy now supports both GPX 1.0 and 1.1. formats.

The 0.* version started as a utility scripts for me, it supported only some fields GPX 1.0 and I was adding more as users requested. But with time, as GPX 1.1 started to be used more, it became difficult to follow what's exactly missing in the library. People requested featured from different versions of GPX but the library nominally supported only 1.0.

After a couple of months of complete refactoring of the code to parse/serialize GPX file the new version is out. There is only one thing missing -- support for GPX 1.1. extensions. This will (probably) come later.

Thursday, July 9, 2015

git plus

Just released: Git plus is my utility "plugin" for git. It consists of:
  • git multi a utility to execute a git command on multiple git repository
  • git relation to show the relation between two branches/commits
  • git old-branches to detect old/unused branches
  • git recent to list recently used or last-used branches
If you are using OSX and brew, it's available there, too.

Monday, March 2, 2015

git relation

Two different branches in a git repository can be related in one of the following two ways:
  1. Branch A is ahead of branch B
  2. Branch A and branch B diverged.
But, I always wondered how to get more information about that relationship. For example, if A is ahead of B -- by how many commits? Or if they diverged -- how many commits ago (from A, and from B). And what exactly commits are those?

So, I just wrote a simple python script which will find the response.

Examples:

$ git relation master test-branch
master is AHEAD of test-branch

Commits from test-branch to master:
  2176e45 Tomo Krajina git-multi in README, 18 hours ago
  50b2f79 Tomo Krajina + README, 18 hours ago
...or...

$ git relation branch-1 branch-2
branch-1 and branch-2 DIVERGED, common point is 7e0bb439dd2aef4ff0262afec0a98461489becae

Commits from 7e0bb439dd2aef4ff0262afec0a98461489becae to branch-1:
  3d0246b Tomo Krajina js namespace, 3 weeks ago
  60215aa Tomo Krajina Merge branch 'new-path-editor' into new-path-editor--js-namespace, 3 weeks ago
  1e76deb Tomo Krajina js namespace, 5 weeks ago

Commits from 7e0bb439dd2aef4ff0262afec0a98461489becae to branch-2:
  359eff6 Tomo Krajina form event functions, 5 hours ago
  a99b5f8 Tomo Krajina ..., 3 weeks ago
  1d3b97c Tomo Krajina Preparations for marker handler, 3 weeks ago
  9546769 Tomo Krajina Removed all subscription stuff, 3 months ago
Git relation is part of my git-plus repository: https://github.com/tkrajina/git-plus.