Skip to content

Instantly share code, notes, and snippets.

@gspivey
Last active February 1, 2018 21:48
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save gspivey/a2c304001dfd66a3a7392ec5cfc02bd3 to your computer and use it in GitHub Desktop.
Save gspivey/a2c304001dfd66a3a7392ec5cfc02bd3 to your computer and use it in GitHub Desktop.

Tips and Resources for Learning Go

At Nyla, we use a variety of technologies. I recently joined a team that primarily uses go and gave myself a crash course. I’ll talk about some of the materials I used and a collection of eclectic lessons learned.

Recomended Resources

  1. Website: gobyexample.com
    1. Has a list of the most common things you will attempt to do in go accompanied by a quick but practical example.
  2. Website: tour.golang.org
    1. This is a quick go intro site. Navigating the site is bit odd (Click on the hamburger in the top right corner and then a header to the section outline). What’s most useful is you can edit the example resented directly within the browser and run it to see the result. A good compliment to gobyexample.
  3. Book: The Go programming Language – Donovan & Kernighan
    1. This book has great pacing if you have previous programming experience. Chapter 1 covers all the language basics. Each chapter after that begins to build on that knowledge with explanations of language features, supporting examples and reinforcing exercises. All examples can be pulled into your GOPATH using go get. More on GOPATH in eclectic lesson 1.
  4. SourceCode: Go standard Library
    1. The Standard Library is a great place for code examples as well as a place for understanding feature available to you. To be a proficient go developer you will need to spend plenty of time making packages here common knowledge.
  5. IDE: GoLand IDE (https://www.jetbrains.com/go/) GoLand
    1. There are a number of tools you can use to aid in go development (vim-go, vscode-go). I settled on GoLand. I would not put too much stock into this choice as this is a rapidly changing space. All of the tools are improving at a rapid pace. I chose GoLand due to the code inspection/intellisence capability along with the ability to see code hierarchy from three different paths simultaneously.
      1. Project Root
        1. Whatever directory you open with GoLand
      2. GOROOT
        1. Where your configured version of the go source (standard library) and binary live
      3. GOPATH
        1. Where all retrieved go dependencies live.
    2. NOTE: GoLand is a commercial tool vim-go and vscode-go are both open source
    3. Exploring the standard library from GoLand was a breeze and a very natural process.
  6. Additional Help: google searches for go are a pain. If you need additional resources this wiki is a great place to start Go Wiki
    1. I recommend scanning this site. Lots of useful nuggets. For example, the CodeReviewComments page catalogs some common code review comments.

Go lessons I learned the hard way. Some of these may be obvious to a seasoned go developer however they may not be obvious to a new developer.

Eclectic Lessons

  1. Go is not project based (GOPATH/GOROOT env Variables)
    1. Go's general practice is to install all packages into the same directory on your machine. This location is pointed to by your system enviornment variable GOPATH. Your path that includes your currently used version of Go (the binary) and the associated standard library is held in the environment variable GOROOT. Both of these paths are required in order for software to build and for any of the go tooling to operate correctly. Even an application with versioned decencies stored in the working directory require both GOPATH and GOROOT to build.
  2. Public Private package variables. No keywords just casing
    1. Not really an eclectic lesson. This falls under RTFM (Read The Fun Manual). Package variables should be camel case (Ex: TestVar, testVar). The variable must be capitalized before (Ex: TestVar) use outside the package. The same is true for functions and structs. This is documented in most learning Go materials. Don’t skip over the early sections of the tutorial or book due to them seeming remedial, rather quickly read through them just in case there is an extremely important nugget there.
  3. All variables are initialized … well most of the time
    1. In general Go makes sure you cannot have un-initialized variables. This is referenced in The Go Programmng Language Book as well in basic go tutorials such as A Tour of Go: Zero Values. There is however an intersting case where you can end up with an uninitialized variable. Variables are created a few ways. Long hand var x int Short hand x := 5. Variables are also created when they are input and return values of a function. This interesting case occurs when you use the composite type map and declare it as a return value. Looking at the example below in functions T1 you see that variables are created by being named returned values and using them causes no issues. In T3 we get a panic attempting to access our map. WHen maps are created they generally require the make command. When created as a named return value they need to still have the make command used in order to properly initialize the map as seen in T2. Example Below in the Go Playground
package main

import "fmt"

func T1() (stringName string, intValue int){
	stringName = "Test Name"
	intValue = 100
	return stringName, intValue
}


func T2() (stringMap map[string]int){
        stringMap = make(map[string]int)
	stringMap["Test Name"] = 100
	return stringMap
}

func T3() (stringMap map[string]int){
	stringMap["Test Name"] = 100
	return stringMap
}


func main () {
        s, i := T1()
	fmt.Printf("Output is %s %d\n", s, i)
	fmt.Printf("Output is %v\n", T2())
	fmt.Printf("Output is %v\n", T3())
}

The output is:

Output is Test Name 100
Output is map[Test Name:100]
panic: assignment to entry in nil map

goroutine 1 [running]:
main.T3(...)
	/tmp/sandbox992696065/main.go:19
main.main()
	/tmp/sandbox992696065/main.go:28 +0x200

  1. Goroutines and Channels
    1. Unbuffered channels are required to be ran in a asynchronous channel in order to block on a reciver accessing the channel. This is typically achived by accessing the channel in a goroutine. However goroutines are concurrent operations therefore spawning two goroutines simultaneously to operate on a channel lead to unintended side effects as seen in example T4.
package main

import "fmt"

func chT1() {
	var f = make(chan int)
	//var t  int

	go func() {
		f <- 5
	}()


	go func() {
		//t = <- f
	}()
	fmt.Printf("Values are: %d\n",  <-f)
}


func chT2() {
	var f = make(chan int)
	var t  int
	go func() {f <- 6}()
	t = <- f
	fmt.Printf("Values are: %d\n",  t)
}

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

	go func() { messages <- "ping\n" }()

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

func chT4() {
	var f = make(chan int)
	var t  int
	go func() {f <- 7}()
	go func() {t = <- f}()
	fmt.Printf("Values are: %d\n",  t)
}


func main () {
	chT1()
	chT2()
	chT3()
	chT4()
}

The results are:

Values are: 5
Values are: 6
ping

Values are: 0
  1. Use a Linter https://github.com/alecthomas/gometalinter
    1. As a programmer that strives for good code quality and sticking with the idioms of the language I figured a good linter could help identify potential issues early and often. That’s when the flood gates opened. There are a TON of linters some with overlapping scope others with completely different views. Here comes gometalinter to the rescue. Gometalinter installs a number of linters runs the configured linters and normalizes the output.
  2. How to vendor dependencies https://github.com/Masterminds/glide or https://github.com/tools/godep
    1. The community has settled on godep. This used to be a very fractured and underdeveloped space for the community. GO developers internal to google did not have to deal with this issue and the rest of the community was left to “sort things out”. The community agreed on the issue and at a gophercon (find link and year) decided to tackle the problem with a working group. The outcome of that was godep. Prior to godep existing a number of community tools existed for dependency management and vendoring since the go 1.5 vendoring experiment (link). Glide was a premier community tool that emerged. I recommend godep and glide for vendoring. The only reason to ever use glide over godep is if you need to perform some form of URL mapping of your dependencies. For example, your enterprise cache’s software and git url’s in an artifact repository. Policy dictates you cannot pull build dependencies from the web but use the internal copies. Glide’s URL mapping will satisfy a github.com import from a corporate bitbucket for example. No code changes need to be made to build the software internally or externally. If this feature is not needed stick with godep since the community has already normalized it. Godep can bootstrap from glide configuration files so transitioning from glide to godep in the future should not be problematic.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment