Arrow of time
Arrow of time

Introduction to Go for Python / Django developers

This is a gentle introduction to Go for primarily meant for Django developers. Admittedly, it is in some ways like ...

This is a gentle introduction to Go for primarily meant for Django developers. Admittedly, it is in some ways like comparing apples and oranges. Since Go is a language (with a batteries-included standard library) and Django is a web application framework, this guide will make some choices on how to make Go useful for web application development. There is a very large number of Go libraries, frameworks and micro-frameworks out there, and more are developed every day, so the choices presented here should be periodically re-evaluated, just to see if something better is available among the open source projects.

This guide assumes at least a passing familiarity with Go's syntax, or at least with a C-like language. If you have learned C in university, that is excellent, since it will help you greatly. If not, you are probably familiar with JavaScript (since you work with web apps), and it is better than nothing. I will not explain entirely how Go works here, I will only point out some details which may be useful to someone just starting to learn it. On the other hand, I will assume you know Django fairly well.

And to resolve the issue at the start: why learn Go in addition (or instead of) Django? For me, it's very simple: performance. After working with both, I think developing in Python / Django is faster and more convenient (Django particularly goes to great lengths to simplify web app development - the admin interface itself is a little miracle), while its execution performance, well, is better not mentioned in polite society. Go at least is compiled, and since I have a very long history with C, it's more like coming home. For a compiled language, as you will probably see in this guide, Go is actually very script-like. In particular, there is a lot of reflection data being recorded (and used), and, surprisingly, almost arbitrary data can be added for runtime inspection in struct tags. This, together with other nice features such as the garbage collector makes it a much "softer" language than C or C++. By its nature, Go very much resembles "C with a lot of syntax sugar".

The setup and the "Hello, World"

You should have the latest version of Go installed. Please do not use the version which comes with e.g. Ubuntu 14.04 LTS, since it's like working with Python 2.4 or Django 1.3, i.e. ancient. Unless you have an extremely good reason, you should install (unpack) Go in the default location, which is /usr/local/go for Unix-like systems, and c:\go for Windows (see the docs!). If you have installed Go in the default location, you only need to create the GOPATH environment variable. It will point to your user's Go working directory, aka "workspace", used to download and build third party dependent libraries, etc. It can be an arbitrary directory NOT within the directory where you've installed Go. On Linux it is customary to have it in ~/go. While you could also create your projects in this directory, following the prescribed directory naming strategy, it is not a requirement.

Before proceeding, you need to modify your system's PATH environment variable to include the bin subdirectory of your Go installation and the bin subdirectory of your GOPATH workspace. The first is because you need to use the Go compiler and system tools, and the second is because third party libraries and utilities will sometimes have their own executables.

For the "Hello, World" program, simply make a directory named "helloworld" anywhere, and in it a file named main.go with the following contents:

package main

import (
        "fmt"
        "os"
        "time"
)

var days_of_week = [7]string{"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"}

func main() {
        fmt.Println("Hello, World")
        now := time.Now()
        wday := now.Weekday()
        fmt.Printf("It is %s!\n", days_of_week[wday])
        if wday == time.Friday {
                f, err := os.Create("hello.txt")
                if err != nil {
                        panic("Cannot create file!")
                }
                defer f.Close()
                _, err = f.WriteString("TGIF!\n")
                if err != nil {
                        panic("Cannot write file!")
                }
        }
}

Go is a compiled language, and to create the executable binary, you need to issue the go build command, while in the same directory where main.go is. The result will be an executable file named helloworld, named after the directory where main.go is located. You can start the program with ./helloworld.

The go build command will build all *.go files, and one of them needs to contain the main() function. By convention, this file is named main.go. If you are creating a program (as opposed to a library), you need to put all the top-level code in the package labeled main, and this is what the first line of code does. Somewhat similarly to Python, the "import" statement pulls in external packages. As opposed to Python, the package names are proper strings. Functions are defined with a func keyword, and the single executable line of code calls the Println function in the fmt package.

About Go

I'd like to illustrate some properties of Go on the example code above, which need to be clear for starting any kind of development:

  • Go is case-sensitive, like Python. In fact, Go has a peculiar requirement for cases in one aspect of the code: all things which are to be "exported", i.e. available to other code outside the package they are created in, need to be named starting with an uppercase letter. For example "fmt.Println" is accessible from other packages, while "fmt.println" isn't. One other thing: package names are all lowercase.
  • Go is strongly typed, unlike Python. While type names are not always required, variables always have a type, and the type is unchangeable.
  • In Go, functions can return more then one value, like Python. Not all values are required to be received by the caller, though. You can receive what you need, left-to-right, and the unreceived return values are ignored. The special character "_" (underscore) means a value which is explicitly discarded.
  • In go, there are no exceptions (unfortunately), unlike Python. Errors are returned in a C-like fashion, are of a special type (actually, an interface named "error"), and the receiving variable is most often named err. It needs to be checked after every function call which could fail. Yes, it is tedious.
  • In go, actions can be deferred, differently from Python. The very convenient defer keyword postpones the execution of a function call until the current function exits. In the above example, the f.Close() is guaranteed to be executed in all cases, even when a panic() call happens. Read more about it here. In Python, the try..finally block could be used for a similar effect.
  • Go is garbage collected, like Python. Improvements in GC performance is one of the main reasons why you should run the latest and greatest version of Go.
  • Go is not object-oriented. Or actually, it is object-oriented up to the point where it has a standard way of packing data and code together, and some convenient syntax sugar to make it practically usable, but without inheritance, polymorphism, or other features associated with having "classes." On the other hand, Go supports interfaces a bit like Java does it, and every data type can have methods associated with it. While in Python, an int can have methods because it is an object, Go is similar to C in the fact that almost everything is a "primitive" type, or POD - plain old data, and it doesn't matter as far as attaching methods to it. Constructors and the way methods are bound to data objects work very differently in Go. Read more about it here.

There are a lot of other aspects to Go, and this is only an introductory text. Effective Go is a good high-level overview of the language and its environment, and getting familiar with the standard library is a must.

Picking Django-like libraries

Here's a small selection of libraries which are useful for web development with Go:

To install the libraries, use go get in the following way:

go get goji.io
go get gopkg.in/flosch/pongo2.v3
go get github.com/jinzhu/gorm
go get github.com/gorilla/sessions
go get github.com/gorilla/context
go get github.com/codegangsta/negroni
go get github.com/goincremental/negroni-sessions
go get github.com/goincremental/negroni-sessions/cookiestore

They will be installed in your GOPATH workspace, and you should inspect the directory structure created as a result of the commands. The go get command enables a very distributed way of storing and referencing code. It has a role similar to pip install, though the low-level details are very different.

The reason why there are a lot of libraries to include here is that Go by itself provides only the basic functionalities for writing web applications. While a minimal "hello, world" application could be written using only the standard Go features, it would not support parametric URLs, sessions, or any other real-world requirements.

...to be continued...


comments powered by Disqus