Go: code that grows with grace Andrew Gerrand Google Sydney http://andrewgerrand.com @enneff https://go.dev * Video A video of this talk was recorded at Øredev in Malmö, Sweden in November 2012. .link http://vimeo.com/53221560 Watch the talk on Vimeo * Go You may have heard of Go. It's my favorite language. I think you'll like it, too. * What is Go? An open source (BSD licensed) project: - Language specification, - Small runtime (garbage collector, scheduler, etc), - Two compilers (`gc` and `gccgo`), - 'Batteries included' standard library, - Tools (build, fetch, test, document, profile, format), - Documentation. As of September 2012 we have more than 300 contributors. * Go is about composition Go is Object Oriented, but not in the usual way. - no classes (methods may be declared on any type) - no subtype inheritance - interfaces are satisfied implicitly (structural typing) The result: simple pieces connected by small interfaces. * Go is about concurrency Go provides CSP-like concurrency primitives. - lightweight threads (goroutines) - typed thread-safe communication and synchronization (channels) The result: comprehensible concurrent code. * Go is about gophers .image chat/gophers.jpg * Core values Go is about composition, concurrency, and gophers. Keep that in mind. * Hello, go .play chat/support/hello.go * Hello, net .play chat/support/hello-net.go * Interfaces Hey neato! We just used `Fprintln` to write to a net connection. That's because a `Fprintln` writes to an `io.Writer`, and `net.Conn` is an `io.Writer`. .code chat/support/hello-net.go /Fprintln/ .code chat/support/defs.go /Fprintln/ .code chat/support/defs.go /type.Writer/,/^}/ .code chat/support/defs.go /type.Conn/,/^}/ * An echo server .play chat/support/echo-no-concurrency.go * A closer look at io.Copy .code chat/support/echo-no-concurrency.go /Copy/ .code chat/support/defs.go /Copy/,/func/ .code chat/support/defs.go /type.Conn/,/^}/ .code chat/support/defs.go /type.Writer/,/^}/ .code chat/support/defs.go /type.Reader/,/^}/ * Goroutines Goroutines are lightweight threads that are managed by the Go runtime. To run a function in a new goroutine, just put `"go"` before the function call. .play chat/support/goroutines.go * A concurrent echo server .play chat/support/echo.go * "Chat roulette" In this talk we'll look at a simple program, based on the popular "chat roulette" site. In short: - a user connects, - another user connects, - everything one user types is sent to the other. * Design The chat program is similar to the echo program. With echo, we copy a connection's incoming data back to the same connection. For chat, we must copy the incoming data from one user's connection to another's. Copying the data is easy. As in real life, the hard part is matching one partner with another. * Design diagram .image chat/diagrams.png * Channels Goroutines communicate via channels. A channel is a typed conduit that may be synchronous (unbuffered) or asynchronous (buffered). .play chat/support/chan.go * Select A select statement is like a switch, but it selects over channel operations (and chooses exactly one of them). .play chat/support/select.go * Modifying echo to create chat In the accept loop, we replace the call to `io.Copy`: .code chat/support/echo.go /for {/,/\n }/ with a call to a new function, `match`: .code chat/tcp-simple/chat.go /for {/,/\n }/ * The matcher The `match` function simultaneously tries to send and receive a connection on a channel. - If the send succeeds, the connection has been handed off to another goroutine, so the function exits and the goroutine shuts down. - If the receive succeeds, a connection has been received from another goroutine. The current goroutine then has two connections, so it starts a chat session between them. .code chat/tcp-simple/chat.go /var.partner/,/^}/ * The conversation The chat function sends a greeting to each connection and then copies data from one to the other, and vice versa. Notice that it launches another goroutine so that the copy operations may happen concurrently. .code chat/tcp-simple/chat.go /func.chat/,/^}/ * Demo * Error handling It's important to clean up when the conversation is over. To do this we send the error value from each `io.Copy` call to a channel, log any non-nil errors, and close both connections. .code chat/tcp/chat.go /func.chat/,/^}/ .code chat/tcp/chat.go /func.cp/,/^}/ * Demo * Taking it to the web "Cute program," you say, "But who wants to chat over a raw TCP connection?" Good point. Let's modernize it by turning it a web application. Instead of TCP sockets, we'll use websockets. We'll serve the user interface with Go's standard `net/http` package, and websocket support is provided by the `websocket` package from the `go.net` sub-repository, * Hello, web .play chat/support/hello-web.go * Hello, WebSocket .code chat/support/websocket.js .play chat/support/websocket.go * Using the http and websocket packages .code chat/http/chat.go /package/,/^}/ * Serving the HTML and JavaScript .code chat/http/html.go /import/ .code chat/http/html.go /func/,/