Getting started with Golang on Mac OS X

Posted by Joost Faassen on 2015-12-06

Installation

Installation through homebrew

To install go through homebrew (or to update it to the latest version), run:

brew update
brew install go # if go is not yet installed - and/or - 
brew upgrade go # update an existing go installation

Check that you have the latest version:

go version

Setting up the environment

You'll need to create a local directory that will be used as the 'Go Workspace'. This workspace will be shared between all of your projects, so generally you'll need only one.

For example:

mkdir ~/go

Then setup these environment variables, ideally in your ~/.bashrc file.

export GOPATH=$HOME/go
export GOROOT=/usr/local/opt/go/libexec
export PATH=$PATH:$GOPATH/bin
export PATH=$PATH:$GOROOT/bin

Setup atom plugin

Install the go-plus plugin. On startup, it will do some sanity checks to make sure everything is set up correctly. In case of errors, double check that you've set up your environment variables correctly in the current (atom) session. To make sure, start a new bash session, and run atom from there.

This plugin will:

Creating your first project

Go is pretty opinionated about where it wants your code to be located. Your code is expected to be stored in $GOPATH/src/github.com/your-username/your-projectname.

The idea is that any project/package you write is easily shareable. Instead of the github.com format, there are a few others like bitbucket, mercurial, etc (Read more about Package Publishing)

mkdir -p $GOPATH/src/github.com/your-username
mkdir $GOPATH/src/github.com/your-username/your-projectname

Simple console application with flags

Start with a simple file, for example:

package main

import (
    "flag"
    "fmt"
)

var greetingFlag string

func init() {
    flag.StringVar(&greetingFlag, "greeting", "Hello", "Type of greeting")
}

func main() {
    flag.Parse()
    fmt.Println(fmt.Sprintf("%s, go!", greetingFlag))
}

Build your application like this:

go build

You can now run your built executable:

./go-test  -greeting="What's up"

Web-enabling your app

With some small updates, you can turn your console application into a web application:

package main

import (
    "flag"
    "fmt"
    "net/http"
)

var greetingFlag string

func init() {
    flag.StringVar(&greetingFlag, "greeting", "Hello", "Type of greeting")
}

func main() {
    flag.Parse()
    fmt.Println(fmt.Sprintf("%s, go!!", greetingFlag))

    http.HandleFunc("/", hello)
    http.ListenAndServe(":8080", nil)

}

func hello(w http.ResponseWriter, r *http.Request) {
    w.Write([]byte(fmt.Sprintf("%s, go!!", greetingFlag)))
}

Package management / vendor

The $GOPATH design is a bit weird when coming from package managed languages like php/composer, nodejs/npm, etc. In Go 1.5 there is a development experiment to support a vendor/ directory, like these other package managers.

Read more about it here. It is based on Glide

To use it, you'll need to set the environment variable GO15VENDOREXPERIMENT to 1 and install glide:

export GO15VENDOREXPERIMENT=1
brew install glide

In your project directory, use glide like this:

glide create # creates your glide.yaml if it does not exist

Now edit your newly created glide.yaml file to list your dependencies, for example:

package: main

# Declare your project's dependencies.
import:
  - package: github.com/Masterminds/cookoo
    repo: git@github.com:Masterminds/cookoo.git
    ref: 1.1.0
    vcs: git

Note how you can specify repository locations, and most importantly: explicit versions.

Now install these dependencies in vendor/ with the following command:

glide install

you can build your package as usual:

go build

Because of the environment flag, it will try to locate your dependencies in the vendor/ directory.

Debugging

Printf

Most recommendations so far suggest to simply output data using fmt.Printf. As Go is making heavy usage of struct, you'll often want to output all fields of a struct. A simple way to do this:

fmt.Printf("%+v\n", someData)

Logrus

You could use a nice logger like logrus for logging messages, augmented with custom fields.

Import it like this:

import log "github.com/Sirupsen/logrus"

Then log a message like this:

log.WithFields(log.Fields{
    "animal": "walrus",
}).Info("A walrus appears")

You can tweak the logrus settings in init:

func init() {
  // Log as JSON instead of the default ASCII formatter.
  log.SetFormatter(&log.JSONFormatter{})

  // Output to stderr instead of stdout, could also be a file.
  log.SetOutput(os.Stderr)

  // Only log the warning severity or above.
  log.SetLevel(log.WarnLevel)
}

godebug

For lower level debugging you can use Mailgun's godebug

Install godebug:

go get github.com/mailgun/godebug

Then add breakpoints to your code like this:

_ = "breakpoint"

To run your app, simply:

godebug run hello.go

Your app will run normally, until it hits the breakpoint. There you can use a few basic commands to list context, and print variables (including structs) in their current state.

Spew

Think of this as Go's equivelant of var_dump. Add it to your imports like this:

import spew "github.com/davecgh/go-spew/spew"

Then whatever variable (including structs) you want to output, simply use:

spew.Dump(v) // output to console directly
fmt.Printf(spew.Sdump(v)) // create a string

Reloading

When working on web-apps and servers, you generally don't want to manually recompile and restart your app every time you change a line of code. This is where reloading comes in.

On Mac OS X you will get a popup from the firewall, asking if your newly built app is allowed to open incoming connections. It does this every time your app changes (new binary file content hash). This is obviously very annoying during development. To solve it, always make sure that your web app is listening to the local host ip (127.0.0.1) only, and not any public or catch-all addresses.

Gin

The gin app is a simple proxy server that rebuilds your app when .go files changes, and restarts a server.

Install it using go get github.com/codegangsta/gin, and use gin -h to read about the options. In general, this is all you need to get started:

gin -a "8080" run

Now you can simply open up this url in your browser to view your app: http://127.0.0.1:3000 (note: not the port specified with -a!)

Gin will monitor the current directory for changes. If a .go file is changed, a go run is executed, and the app is stopped/started. The proxy is forwarding requests to port 3001 by default, which you can override with -a.

Note that this is a very ungraceful restart only suitable for development. In production you'll need to work with loadbalancers.

Gulp

Here's a blog post about reloading code through gulp. That would require mixing node in the project, so gin would be a cleaner solution.