Note: This the long version of a talk I was giving on Sept 15
at Meet-the-Meetups 2017 in
Graz about why I’m focusing on Go and what the language and ecosystem has to
offer that makes it so special for me.

The special mix

Up until about 4 years ago, Python and NodeJS were my main working
environments. For everything where I needed a bit more speed I went with NodeJS
while I used Python as my go-to language for most automation tasks. Since I was
mostly doing web-based projects I could usually solve pretty much anything I
came across with either of those.

Then I started to learn Go and simply fell in love. If you look at Go from a
language-feature perspective, it doesn’t appear to be all that modern. Instead,
the focus during its design phase was on being pragmatic and easy to
learn, something many other and perhaps more modern languages are clearly
lacking. For me, though, these two were just part of the reason that got me
hooks. Let’s look at the others:

Go’s approach to concurrency

While languages like C, Rust, Erlang et al. offer means to somehow easily work
with threads and multiple
processes, go-routines
and channels as well as
what is in the sync package of the Go
standard-library makes concurrent solutions for your problems even easier.

Go-routines abstract just enough of the underlying implementation away that you
normally just have to think about how your application-threads should
communicate. You can either use channels or go with some of the gems in the sync
package like sync.WaitGroup and sync.RWMutex.

A powerful standard library

But sync is just one example for a great package inside the
standard-library. You will also find these (among many many other modules):

a bare-bone logging implementation

a H2-enabled HTTP server and client module

a JSON parser

a simple commandline-argument parser

an abstraction for relational databases

…and so much more

Let’s look at a small example: How to decode a simple JSON document like this:

{
"name": "Horst",
"favorite_color": "blue"
}

We first have to define a type into which this JSON object should be parsed into
followed by using the json package to do the actual parsing:

Interfaces

While in other languages, interfaces are something that your implementation has
to explicitly reference, in Go they are implicit. This removes the
additional coupling between the two without removing any of its benefits.

They are also used through the standard library for common operations like
copying data from an io.Reader into an io.Writer.

Platform-specific files

You can also provide platform-specific implementations by just following the
simple naming pattern:

# Common parts
main.go
# Include only on Linux
main_linux.go
# Include only on OSX
main_darwin.go

And that’s just the beginning as you can assign build-tags to each file and
build only those that match a certain tag-selection.

Standard code formatting

Go has rather quickly put an end to age-old discussions like “tabs vs. spaces”
thanks to providing a community standard for how Go code should look like and
backing it with a tool to automatically normalise your source code
accordingly.

# Formats all files in the current package:
$ go fmt .

Testing with go test

While languages like Java heavily rely on the community to provide testing
frameworks (e.g. JUnit), the Go comes with a basic yet powerful testing-harness
built-in. Simply name your files containing tests with the suffix “_test”
(e.g. store_test.go) and run go test ./... to execute the tests in the
current and all nested packages (except for the vendor-folder since Go 1.9).

Documentation through godoc

Using go doc you can browse source level documentation of anything that is
available on your $GOPATH. You can even start a little HTTP server to have
that experience in the browser:

Community tooling

goimports

Based on go
fmtgoimports also tries
to resolve missing imports and sorts your imports:

package main
func main() {
fmt.Println("hello world")
}

becomes

package main
import "fmt"
func main() {
fmt.Println("hello world")
}

gomodifytags

Going back to the JSON example from above, writing all these tags and changing
them afterwards can be rather tedious, esp. for larger structs. Writing tags is
also quite error-prone as their syntax is not enforced during compile-time.

Just a few examples

These are just a few examples for the great tool-ecosystem that exists for
Go. Some of this has definitely benefitted from Go’s standard library coming
with modules for parsing Go source files into ASTs but also printers for ASTs
into output files. This has made creating source code generators, for instance,
much simpler.

In the following example we rewrite that very same program not replace the
function “lala” with “dummy”: