Gopher Launch!

One of my most favourite pastimes is playing with different programming languages.

A typical couple of hours tinkering includes writing a few lines, perhaps solving a couple of basic programming problems (you know, the kind some companies make you write on whiteboards at interviews) and downloading the most popular IDE (for the full professional feel).

If I am really enjoying myself, the next steps might include checking out what people are building with it on Github. Any well known projects written in it? What does production-grade code look like? And my favourite - anything that looks super weird?

Checking out some of the more popular idioms is always fun, too. As is then cringing at how easy it is to see that a Java developer wrote my few lines of practice code.

It is usually at this point I will stop, and get back to doing some real work. However during my latest foray into Golang, it didn't stop there.

The next step was discovering the community. Off into Overcast I went, listened to an episode of GoTime and promptly subscribed.

Since then, things have gotten only worse (better). Every time I want to play around with a little weekend project, my go-to language (sorry) has been... you guessed it!

I would like to write a very short intro, describing the top 5 (in no particular order) things I am really enjoying about this language so far, and why.

1. Simplicity.

This is a hard one to explain, and might only really become obvious once you have started to write (and more importantly read!) some Go.

The language really does have a beautiful simplicity about it. It was designed very carefully, which I think that is made obvious by the fact it is a very small language. So small, in fact, it is basically possible to read the spec in one sitting!

2) Multiple function return values.

When I first read some Go code, this went into the "that looks weird" category for me. But I think it's awesome.

func ConvertAmount(fromAmount int) (int, error) {  
    if(fromAmount > 10) {
        return nil, errors.New("Amount too high to convert!")
    }

    return doConversion(fromAmount), nil
}

In the very simple example above, we can see a common use case for this.

As I said, this language oozes simplicity. Rather than creating some kind of object to wrap return results and include the possibility for an error, or some complex exception handling hierarchy, you just return two values - one of them could be an error.

This of course means that throughout Go codebases you see a lot of code similar to the following:

amount, err := ConvertAmount(someAmount)  
if(err != nil) {  
    // handle the error
}

At first the Java developer in me strongly disliked this, but after writing (and reading) more code I realised it was again a decision that put simplicity first.

I have quite a lot more I could say about what I have discovered about error handling in Go, but I will save that for another blog.

3) Functions are friends.

Golang has higher order functions. You can save a function to a variable, pass them in as parameters. Personally, I think a functional style of programming is the programming of the future, so I like languages that treat functions well.

Here is a little example that illustrates this by handling an http request:

func handle(w http.ResponseWriter, r *http.Request) {  
    fmt.Print("I'm handling the request!")
}

http.HandleFunc("/endpoint", handle)  

You might have noticed the scary * preceding the second parameter type. Yes, it is indicating that we are pointing to a value. But unlike C, pointer arithmetic is considered unsafe and disallowed by Go. So you get all the benefits of pointers, without all the risky business!

4) Goroutines.

Goroutines are an incredibly lightweight way to do multi-threading. This again harps on back to the simplicity point in a way, but being able to do the following with such brevity is really nice.

func main() {  
    // blocking
    someFunc()

    // async goroutine
    go someFunc()

    // async anonymous func 
    go func(someParam string) {
        fmt.Print(someParam)
    } ("param")
}

5) Channels.

It has been said that using channels too extensively is an anti-pattern. Also that beginners to Go tend to be some of the worst offenders. Honestly, I agree and fully understand why this is the case - channels are fun!

So, what is a channel? Channels are a way for different go routines to communicate. Think of it as a pipe you can push something into, and wherever that pipe leads to, gets that value.

Here is a simple example:

package main

import "fmt"

func main() {  
    messages := make(chan string)

    go func() {
        messages <- "Message from Goroutine!"
    }()

    msg := <- messages
    fmt.Print(msg)
}

Cool, right? The Goroutine pushes the message into the channel, and we can wait, receive and then print out this value in our main program thread.

Although I can completely understand how this gets misused, I also think having such concurrency oriented functionality baked in at the core language level is great. Go and concurrency really are meant for each other.

Lots of hits, but any misses?

There is a lot of cool stuff in Go. It is fun to use, and honestly (at least for side projects and playing about at weekends) Go is really a language built with productivity in mind. I have heard it called the "get shit done" language more than once before, and I am inclined to concur with this eloquent assessment.

That said, there are a couple of things that give me cause for a little more concern - and these are concerns shared by pretty much everybody, so I will not go into too much detail. Briefly, the main two points for me are:

  • Lack of official dependency management system. There are unofficial ones, but I believe it would be useful to have this standardised.

  • Generics. I know, I know, this is an old and still as much as ever a controversial story. Honestly, though, I would like to see this as part of the language.

Bringing it together.

I can't stress enough just how much I find Go a fun language to work with. Like any tool, it will excel in some places more than others, and careful consideration of requirements should be taken before using any tool in production.

But at least for fun, I say there is no reason not to give Go a go. And, if you decide to, or already have, tweet me and let me know what you think :)

Oh, and one more thing - perhaps the most important. The mascot is the best!

Gopher!