Developer's Perception

Odd thoughts from a developer.

Getting Started With Go

| Comments

In late 2007 Google started an open source initiative to develop a new programming language named Go. The goal of the language was to make it as efficient as statically compiled languages, but as easy to use as dynamic languages.

Furthermore, the language aims to solve the challenges of concurrent programming in an intuitive way. This makes a lot of sense as computers are getting more and more CPUs with more and more cores. A lot of current programming initiatives are actually focused on enabling us to easier write concurrent programs.

Node as an example does have some tools for concurrent programs, but its main focus by using the event loop is actually an approach of strictly single threaded programming, instead focusing on reducing the blocking IO. There has been a lot of discussions going around with people claiming this approach to be either ingenious or insane. My personal experience is that it is possible to write very efficient servers in Node working with the single threaded model.

In contrast to Node, Microsoft released the async and await keywords in C# that makes implementing asynchronous code in C# a lot easier – simply by taking away most of the work of writing such code, but it does not change how the programming model works.

As a language Go is mostly related to the C family of languages in my opinion. Both with regards to features and syntax it more or less feels like a cleaned up version of JAVA or C# with some cruft removed and some parts made explicit that is implicit in those language. Not surprisingly Go seems to go in the opposite direction of Node (like most languages do) and has a concurrent model at the forefront of the language focus. The intriguing thing is that Go manages to this in a fairly elegant way.

What Go promises is speed close to that of C and C++, a slim and elegant language that is as easy to use as Node (it is as easy to get a simple http server running), and powerful features for doing concurrent programming.

Initial thoughts

With my usual curiosity I have followed the development of the language from the sideline for a while, but when I saw a very impressive demonstration of building a chat server in Go at the Oredev conference last year I decided I had to take a closer look and do some development on my own. This is my initial experiments with it and thoughts about the language.

Like I mentioned above the language feels like a slim and more elegant version of the languages in the C family. This meant it was fairly easy for me to get started and following the great online tutorial (http://tour.golang.org/#1) I was quickly able to produce code.

Clean Code

I cannot recall how many hours I have wasted looking at code where half of the lines are pure cruft. Functions that are never called, variables that are never used, and so forth. Therefore, I am really excited about the way the Go compiler handles this.

To illustrate this we can do a very small example. I will not go over the details (read that tutorial!), but the key is that 2 integers ‘a’ and ‘b’ are declared and assigned.

1
2
3
4
5
6
7
8
9
10
11
package main

import (
  "fmt"
)

func main() {
  a := 1
  b := 2
  fmt.Println(a)
}

This example will simply not compile! The integer ‘b’ is never used for anything and thus should be removed. The following will compile:

1
2
3
4
5
6
7
8
9
10
package main

import (
  "fmt"
)

func main() {
  a := 1
  fmt.Println(a)
}

I have seen some people argue that this is actually annoying when you are experimenting with the code as stuff might not get used in the beginning while developing and it then has to be commented out. I believe the pros clearly outweighs the cons:

  • The production code is cleaner.
  • It seems to me that if you are adding code that is not used yet and compiling you might be in a YAGNI situation? Do not write the code until you need it.
  • The workaround is dead simple – just comment it out. Then if it turns out you are not going to need it someone will eventually delete that comment.

Interfaces

Go does not have classes. It has structs and functions can be added to them. As such there is no inheritance, which means as a language Go favors composition over inheritance since the later is not even possible. I really like this design as composition is to be preferred over inheritance in most scenarios in my opinion (99%?) even in a language that support inheritance. This also means that the way interfaces are implemented are different from for instance C#.

Interfaces are implemented implicitly, which in my mind almost feels like duke typing (except checked at compile time). Thus, if an object satisfies an interface (has the required functions) it will compile. This means that interfaces can easily be added for existing code even the main library.

Imagine what I could have done with ASP.Net HttpContext if it worked this way in C# (check my last blog post). Invent a new interface matching the few bits of HttpContext that was being used and simply pass HttpContext along. A lot more elegant that what can be done in C#.

Http Server

To be honest I have not yet worked very much with Go as an Http Server, but since it is one of the things I usually end up using extensively in a language I thought I would include an example anyways.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
package main

import (
  "fmt"
  "net/http"
)

type User struct {
  Name string
    Password string
    FavoriteColor string
}

func (u User) ServeHTTP(w http.ResponseWriter, r *http.Request) {
  fmt.Fprintf(w, "%s, %s, %s", u.Name, u.Password, u.FavoriteColor)
}

func main() {
  http.Handle("/user", &User{"MyUserName", "OhSoSecret", "green"})
  http.ListenAndServe("localhost:4000", nil)
}

I do not think that is too bad. Almost simpler than doing the same in Node, but still to early for me to say how easy it will be to implement a realistic server.

Concurrency

One of the most important features of Go is the way you write concurrent code. It consists of 2 main components being goroutines and channels. A goroutine is a lightweight thread and a channel is a way to communicate between threads.

A fairly common scenario will be goroutine(s) doing some calculation (or reading data) and another goroutine that then does some further manipulation like in this example.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
package main

import (
  "fmt"
)

func getdata(resCh chan<- int) {
  i := 0
  for {
      resCh <- i
      i++
  }
}

func printer(resCh <-chan int) {
  for {
      res := <- resCh
      fmt.Println(res)
  }
}

func main() {
  resCh := make(chan int, 100)
  go getdata(resCh)
  go printer(resCh)
  var input string
  fmt.Scanln(&input)
}

A dumb example I agree, as there are easier ways of printing sequential integers to the console. The point was to showcase the way functions can be started in goroutines and use channels to communicate.

I find this a quite elegant way of doing concurrent programming, and if you want to see a slightly less contrived example take the tutorial of Go and solve the last exercise (you can find mine at my github account: https://github.com/elgsdyret/go_playground/blob/master/fetcher_2.go).

Wrap Up

With the limited experiments I have done so far I think Go has a lot going for it. Which is also why more and more companies are showing of stuff implemented in Go. For instance Mozilla just released a beta on Heka, a quite interesting project, which is written in Go (http://blog.mozilla.org/services/2013/04/30/introducing-heka/).

Next step is to play around with more areas of Go. How to write unit tests? How hard is it to write more advanced web servers?

Comments