Go: a simple programming environment 9 Nov 2012 # Go is a general-purpose language that bridges the gap between efficient # statically typed languages and productive dynamic language. But it’s not just # the language that makes Go special – Go has broad and consistent standard # libraries and powerful but simple tools. # # This talk gives an introduction to Go, followed by a tour of some real # programs that demonstrate the power, scope, and simplicity of the Go # programming environment. Andrew Gerrand Google Inc. @enneff adg@golang.org https://go.dev * Video A video of this talk was recorded at Øredev in Malmö, Sweden in November 2012. .link http://vimeo.com/53221558 Watch the talk on Vimeo * Background * Why a new language? Motivated by our needs at Google. We need: - Efficiency - Safety - Concurrency - Scalability - Fast development cycle - No surprises - A cute mascot * Design "Consensus drove the design. Nothing went into the language until [Ken Thompson, Robert Griesemer, and myself] all agreed that it was right. Some features didn’t get resolved until after a year or more of discussion." - Rob Pike Go is: - Lightweight, avoids unnecessary repetition - Object Oriented, but not in the usual way - Concurrent, in a way that keeps you sane - Designed for working programmers * Go 1 Released in March 2012 A specification of the language and libraries that will be supported for years. The guarantee: code written for Go 1.0 will build and run with Go 1.x. Best thing we ever did. * The gopher .image simple/gopher.jpg * Hello, go .play simple/hello.go * Standard library * Packages Go code lives in packages. Packages contain type, function, variable, and constant declarations. Packages can be very small (package `errors` has just one declaration) or very large (package `net/http` has >100 declarations). Most are somewhere in between. Case determines visibility: `Foo` is exported, `foo` is not * io The `io` package provides fundamental I/O interfaces that are used throughout most Go code. The most ubiquitous are the `Reader` and `Writer` types, which describe streams of data. .code simple/io/io.go `Reader` and `Writer` implementations include files, sockets, (de)compressors, image and JSON codecs, and many more. * Chaining io.Readers .play simple/reader.go * net/http The `net/http` package implements an HTTP server and client. .play simple/hello-web.go * encoding/json The `encoding/json` package converts JSON-encoded data to and from native Go data structures. .play simple/json.go /const/,$ * time The `time` package provides a representation of time and duration, and other time-related functions. .play simple/time.go /START/,/END/ .play simple/time2.go /START/,/END/ `time.Time` values also contain a `time.Location` (for display only): .play simple/time3.go /START/,/END/ * flag The `flag` package provides a simple API for parsing command-line flags. .play simple/flag.go $ flag -message 'Hold on...' -delay 5m * Tools * The go tool The `go` tool is the de facto standard for building and installing Go code. Compile and run a single-file program: $ go run hello.go Build and install the package in the current directory (and its dependencies): $ go install Build and install the `fmt` package (and its dependencies): $ go install fmt This tool also acts as an interface for most of the Go tools. * Import paths The `go` tool is a "zero configuration" tool. No Makefiles or scripts. Just Go code. Your build schema and code are always in sync; they are one and the same. Package import paths mirror the code's location in the file system: src/ github.com/nf/ gosynth/ main.go note.go osc.go wav/ writer.go The `gosynth` program imports the `wav` package: import "github.com/nf/wav" Installing `gosynth` will automatically install the `wav` package: $ go install github.com/nf/gosynth * Remote dependencies The `go` tool also fetches Go code from remote repositories. Import paths can be URLs: import "golang.org/x/net/websocket" To fetch, build and install a package: $ go get code.google.com/p/go.net/websocket To fetch, build, and install `gosynth` and its dependencies: $ go get github.com/nf/gosynth This simple design leads to other cool tools: .link http://go.pkgdoc.org * Godoc Godoc extracts documentation from Go code and presents it in a variety of forms. Comments need no special format, they just need to precede what they document. // Split slices s into all substrings separated by sep and returns a slice of // the substrings between those separators. // If sep is empty, Split splits after each UTF-8 sequence. // It is equivalent to SplitN with a count of -1. func Split(s, sep string) []string { .image simple/split.png Documentation that lives with code is easy to keep up-to-date. * Gofmt The `gofmt` tool is a pretty-printer for Go source code. All Go code in the core is gofmt'd, as is ~70% of open source Go code. Ends boring formatting discussions. Improves readability. Improves writability. Saves a _huge_ amount of time. * Tests: writing The `go` tool and the `testing` package provide a lightweight test framework. .code simple/test/string_test.go /func TestIndex/,/^}/ * Tests: running The go tool runs tests. $ go test PASS $ go test -v === RUN TestIndex --- PASS: TestIndex (0.00 seconds) PASS To run the tests for all my projects: $ go test github.com/nf/... * Tests: benchmarks The `testing` package also supports benchmarks. A sample benchmark function: .code simple/test/string_test.go /func BenchmarkIndex/,/^}/ The benchmark package will vary `b.N` until the benchmark function lasts long enough to be timed reliably. $ go test -test.bench=Index PASS BenchmarkIndex 50000000 37.3 ns/op * Tests: doc examples The `testing` package also supports testable examples. .code simple/test/string_test.go /func ExampleIndex/,/^}/ Examples and built and run as part of the normal test suite: $ go test -v === RUN: ExampleIndex --- PASS: ExampleIndex (0.00 seconds) PASS The example is displayed in `godoc` alongside the thing it demonstrates: .link /pkg/strings/#Index go.dev/pkg/strings/#Index * And there's more - `vet`: checks code for common programmer mistakes - `pprof`: CPU and memory profiling - `fix`: automatically migrate code as APIs change - GDB support - Editor support: Vim, Emacs, Eclipse, Sublime Text * An example * Webfront `Webfront` is an HTTP server and reverse proxy. It reads a JSON-formatted rule file like this: .code simple/webfront/main.go /^\[/,/\]/ For all requests to the host `example.com` (or any name ending in `".example.com"`) it serves files from the `/var/www` directory. For requests to `example.org`, it forwards the request to the HTTP server listening on localhost port 8080. * The Rule type A `Rule` value specifies what to do for a request to a specific host. .code simple/webfront/main.go /Rule represents/,/^}/ It corresponds directly with the entries in the JSON configuration file. .code simple/webfront/main.go /^\[/,/\]/ * Rule methods .code simple/webfront/main.go /Match returns/,/^}/ .code simple/webfront/main.go /Handler returns/,/^}/ * The Server type The `Server` type is responsible for loading (and refreshing) the rules from the rule file and serving HTTP requests with the appropriate handler. .code simple/webfront/main.go /Server implements/,/^}/ .code simple/webfront/main.go /ServeHTTP matches/,/^}/ * The handler method .code simple/webfront/main.go /handler returns/,/^}/ * Parsing rules The `parseRules` function uses the `encoding/json` package to read the rule file into a Go data structure. .code simple/webfront/main.go /parseRules reads/,/^}/ * The loadRules method .code simple/webfront/main.go /loadRules tests/,/^}/ * Constructing the server .code simple/webfront/main.go /NewServer constructs/,/^}/ This constructor function launches a goroutine running the `refreshRules` method. * Refreshing the rules .code simple/webfront/main.go /refreshRules polls/,/^}/ * Bringing it all together The main function parses command-line flags, constructs a `Server`, and launches an HTTP server that serves all requests with the `Server`. .code simple/webfront/main.go /^var/,/^}/ * Demo * Testing (1/3) The `Server` integration test uses the `httptest` package to construct a dummy HTTP server, synthesizes a set of rules, and constructs a `Server` instance that uses those rules. .code simple/webfront/server_test.go /^func testHandler/,/STOP/ * Testing (2/3) Each test case in the table specifies a request URL and the expected response code and body. .code simple/webfront/server_test.go /TESTS START/,/STOP/ * Testing (3/3) For each test case, construct an `http.Request` for the url and an `httptest.ResponseRecorder` to capture the response, and pass them to the `Server.ServeHTTP` method. Then check that the response matches the test case. .code simple/webfront/server_test.go /RANGE START/,/^}/ * Demo * Conclusions * Further reading All about Go: .link / go.dev The slides for this talk: .link /talks/2012/simple.slide go.dev/talks/2012/simple.slide webfront: .link https://github.com/nf/webfront