Use canonical import paths for repositories with aliases
Some Go packages have repositories on standard hosts (for example, Bitbucket, GitHub, Google Code, and Launchpad) but also have an aliased path, such as rsc.io/pdf
for https://github.com/rsc/pdf
. The aliased path improves the stability of go get
for the case where the repository is moved to a different host; the aliased site serves HTML meta tags pointing to the current repository.
That introduces two potential problems for imports of Go code. An import for the current actual repository may break in the future, and the package may be imported twice from different paths.
To fix this problem, Go has a canonical import path declaration comment:
package pdf // import "rsc.io/pdf"
Once such a comment appears in at least one source file in the package, go get
will fail on any other import path.
Vet your Go programs
Many languages have one or more lint tools to provide static code checking in addition to that provided by the compiler. Go has vet
, which examines Go source code and reports suspicious constructs. vet
can be used in three ways:
$ go vet package/path/name
This checks the code in a named package.
$ go tool vet source/directory/*.go
This vets the files named, all of which must be in the same package.
$ go tool vet source/directory
This recursively descends the directory, vetting each package it finds.
The example below shows the third form applied to the gocode
tool's source code. By default, all non-experimental checks are run.
Trace your Go programs
Trace and profiling facilities are essential to understanding what's actually going as your code executes. Without them, you'd have to write a whole lot of fmt.Printf
statements, which falls into the category of "a real programmer can write Fortran in any language."
The Go language has three ways to generate trace files: running the go test -trace
command, using the runtime/trace
package in your code, and using the net/http/pprof
package in your code. To view trace files, use the go tool trace
command.
As shown in this presentation by Google's Dmitry Vyukov, the Go trace tools can generate a graphical display that will give you a good feel for the behavior of your code. Options include viewing the trace in a web browser and generating a pprof
-like profile from the trace, using any of four profile types.
Use the race detector
Race conditions, where the output is dependent on the sequence or timing of other uncontrollable events, are the bane of programmers who use concurrency—and concurrency is the rule rather than the exception for Go programs. Enter the data race detector.
You can enable the race detector by adding the -race
flag to any of the go
commands:
$ go test -race mypkg // test the package
$ go run -race mysrc.go // compile and run the program
$ go build -race mycmd // build the command
$ go install -race mypkg // install the package
Unfortunately, there's a cost to enabling the race detector. Execution time can be increased by an order of magnitude, so you may only want to use it in tests or in one instance among many production instances. In addition, the race detector only finds races that happen at runtime, so it can't find races in code paths that are not executed. Nevertheless, the race detector is useful enough that the Go authors have incorporated it into their continuous integration process.
You can use the GORACE
environment variable to set the log path and other variables for programs built with the -race
flag.
Use arbitrary precision Float types (in math/big
)
Sometimes you need to do floating-point calculations to more precision than is available from IEEE-standard Float64 arithmetic. The Go language math/big
package can give you what you need, as shown in the example below for calculating the square root of 2 to 200 bits of precision using Newton's method.
Is that slower than simply taking math.Sqrt(2.0)
or using the constant math.Sqrt2
(1.4142135623730951)? Of course. But when you need more precision, it's certainly worth the extra time and code to get it.
Use sort.Stable
to preserve input order of equal values
Sort stability is when two objects with equal keys appear in the same order in sorted output as they appear in the input unsorted array. Some sorting algorithms, such as insertion and bubble sort, are inherently stable. Others, such as heap and quick sort, are not.
You often care about the stability of a sort operation if it is one of a sequence of sorts—for example, sorting rows of a table by multiple columns. Otherwise, you may not care.
The Go sort.Sort
function is not guaranteed to be stable, but it's fast: It makes one call to data.Len
to determine n, and O(n*log(n)) calls to data.Less
and data.Swap
. By contrast, the Go sort.Stable
function sorts while keeping the original order of equal elements. It's slower, however, making one call to data.Len
to determine n, O(n*log(n)) calls to data.Less
, and O(n*log(n)*log(n)) calls to data.Swap
.
Keep going with Go
As we've seen, the Go language embodies a rather opinionated set of capabilities that fixes many of the problems that experienced programmers have with other languages, such as long build times, arcane toolchains, and baroque inheritance schemes. In fact, the Go language authors point it out in their FAQ:
- It is possible to compile a large Go program in a few seconds on a single computer.
- Go provides a model for software construction that makes dependency analysis easy and avoids much of the overhead of C-style include files and libraries.
- Go's type system has no hierarchy, so no time is spent defining the relationships between types. Also, although Go has static types the language attempts to make types feel lighter weight than in typical OO languages.
- Go is fully garbage-collected and provides fundamental support for concurrent execution and communication.
- By its design, Go proposes an approach for the construction of system software on multicore machines.
The resources and walkthroughs that follow should help you grok the Go language. Go forth and code.
- Go language home page
- Go language documentation
- Interactive tour of the Go language
- Quick setup video for Go programming
- The Go Programming Language Specification
- Go packages
- Effective Go programming
- Go Concurrency Patterns with Rob Pike
- Advanced Go Concurrency Patterns
- Codewalk: First-Class Functions in Go—Illustrates a "Pig" game simulator implemented in functional programming style
- Codewalk: Generating arbitrary text: a Markov chain algorithm—Based on the program presented in the "Design and Implementation" chapter of "The Practice of Programming" (Kernighan and Pike, Addison-Wesley 1999)
- Codewalk: Share Memory By Communicating—Illustrates Go's approach to concurrency
- Writing Web Applications—Demonstrates how to implement a wiki in Go