# Should You Go? #### Presented at mondo ### Kevin Collas-Arundell #### [@kcollasarundell](https://twitter.com/) #### 05 Dec 2018
## What is Go? - Released in 2009 - Developed with the Google service workload in mind - Big focus on Concurrency - Statically typed !section ## Useful bits? - Developed for Google * - Easy Concurrency * - Quick to learn * - Built to be read * - Error handling. There are no exceptions * - Opinionated * - Statically compiled * - Gopath! * - go fmt \* Buyer beware <!-- .element: class="fragment" --> note: Everything with a * has caveats !section ## You could also say - Boring - Old Fashioned - No Package tools - No generics - Worse concurrency that erlang - Built for organisations much larger than you - Inflexible - No generics - [Made for "mediocre" programers](https://news.ycombinator.com/item?id=9266184) !section # YMMV A larger list can be found at [github.com/ksimka/go-is-not-good](https://github.com/ksimka/go-is-not-good) !section ### Why Should you go? - Simple and boring - Concurrent - Testing - Excellent cross compilation - Simple deployment process - Operation tooling !section ### Boring - Go is no longer exciting - Compatibility guarantees that hold - Error checking is painful but less painful than errors - Old enough that language rants are no longer hosted Note: in the 6 years since go1.0 came out there has been one edge case clarified in 1.1, 1 float rounding change and a few changes that break erroneous behaviours such as calling a method on a double dereference. There are also two implementations of the go compiler toolchain so that's kinda nice !section ### Simple #### Mandatory Hello World ```go package main import "fmt" func main() { fmt.Println("Hello, 世界") } ``` !section ### Artificial example ```go func echoConn(conn net.Conn) { defer conn.Close() for { buf := make([]byte, 1024) size, err := conn.Read(buf) if err != nil { return } data := buf[:size] conn.Write(data) } } ``` !section ```go func main() { l, err := net.Listen("tcp", ":8081") if err != nil { panic(err) } defer l.Close() for { conn, err := l.Accept() if err != nil { panic(err) } echoConn(conn) } } ``` !section ### Concurrency ![Gophers doing things concurrently and in parallel](/talks/go/gopherconcurrency.jpg) !section ```go func main() { l, err := net.Listen("tcp", ":8081") if err != nil { panic(err) } defer l.Close() for { conn, err := l.Accept() if err != nil { panic(err) } go echoConn(conn) } } ``` Note: But this is an artificial example right? What does a real thing look like? Well we run something that looks like this with a bit more error handling and env details (TLS config) It pretty much boils down to this with flags and logging. !section #### Racy behaviour ![Go's race detector is awesome](/talks/go/race.gif) !section ```shell go test -race ./... go run -race main.go ``` !section #### Testing ![Testing is table stakes. You can't get away for long without it. picture is dogs playing poker](/talks/go/tablestakes.png) !section ```go func Fib(n int) int { if n < 2 { return n } return Fib(n-1) + Fib(n-2) } ``` !section ```go func TestFib(t *testing.T) { tests := []struct { name string arg int want int }{ // TODO: Add test cases. } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { if got := Fib(tt.args.n); got != tt.want { t.Errorf("Fib() = %v, want %v", got, tt.want) } }) } } ``` !section ```go func benchmarkFib(i int, b *testing.B) { for n := 0; n < b.N; n++ { Fib(i) } } ... func BenchmarkFib20(b *testing.B) { benchmarkFib(20, b) } func BenchmarkFib40(b *testing.B) { benchmarkFib(40, b) } ``` !section ```shell $ go test -bench=. -benchmem goos: windows goarch: amd64 pkg: github.com/kcollasarundell/austnet/mondo/fib BenchmarkFib1-4 1000000000 2.32 ns/op 0 B/op 0 allocs/op BenchmarkFib2-4 200000000 6.66 ns/op 0 B/op 0 allocs/op BenchmarkFib3-4 100000000 11.0 ns/op 0 B/op 0 allocs/op BenchmarkFib20-4 30000 48133 ns/op 0 B/op 0 allocs/op BenchmarkFib40-4 2 725500700 ns/op 0 B/op 0 allocs/op BenchmarkFib10-4 5000000 378 ns/op 0 B/op 0 allocs/op PASS ok github.com/kcollasarundell/austnet/mondo/fib 12.314s ``` !section ```bash $ benchcmp old.txt new.txt benchmark old ns/op new ns/op delta BenchmarkConcat 523 68.6 -86.88% benchmark old allocs new allocs delta BenchmarkConcat 3 1 -66.67% benchmark old bytes new bytes delta BenchmarkConcat 80 48 -40.00% ``` !section ```go package fib_test import ( "fmt" "github.com/kcollasarundell/hugo/tmpfiles/fib" ) func exampleFib() { fmt.Println(fib.Fib(10)) // Output: 55 } ``` !section ```shell % go test . -v === RUN TestFib --- PASS: TestFib (0.00s) === RUN ExampleFib --- PASS: ExampleFib (0.00s) PASS ok github.com/kcollasarundell/hugo/tmpfiles/fib 0.010s ``` !section ### Cross compilation ![cross eyed cat](/talks/go/cross.jpg) !section ```bash CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -o linux_amd64_binary CGO_ENABLED=0 GOOS=linux GOARCH=arm64 go build -o linux_arm64_binary CGO_ENABLED=0 GOOS=darwin GOARCH=amd64 go build -o osx_amd64_binary CGO_ENABLED=0 GOOS=windows GOARCH=amd64 go build -o windows_amd64_binary ``` !section #### Simple deployment process ![dog delivering parcel](/talks/go/deployment.jpg) !section ```go FROM golang:latest AS builder # Copy the code from the host and compile it WORKDIR $GOPATH/src/github.com/username/repo COPY . ./ RUN CGO_ENABLED=0 GOOS=linux go build -a -installsuffix nocgo -o /descriptiveName . FROM scratch COPY --from=builder /descriptiveName ./ COPY --from=builder /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/ca-certificates.crt ENTRYPOINT ["./descriptiveName"] ``` !section ```go package main import ( "net/http" "github.com/gobuffalo/packr" ) func main() { box := packr.NewBox("./templates") http.Handle("/", http.FileServer(box)) http.ListenAndServe(":3000", nil) } ``` ```shell packr && go build ``` !section ### Operation tooling ![Cat performing operations](/talks/go/operation.jpg) !section ![Always include pprof you never know when you're going to need](/talks/go/pprof.png) !section #### this was a demo of the capabilities of go tool pprof and a walk through of how useful it is !section ### What's next - Do the [tour.golang.org](https://tour.golang.org/) - [gobyexample.com](https://gobyexample.com/) - [exercism.io has a go track](https://exercism.io/tracks/go) - [gopl.io the Go Programming Language book](http://www.gopl.io/) - [Just for Func on Youtube](https://www.youtube.com/channel/UC_BzFbxG2za3bp5NRRRXJSw) !section ### References - [How to complain about go](https://divan.github.io/posts/go_complain_howto/) - [Choose Boring Technology](http://boringtechnology.club/) - [Go's work-stealing scheduler](https://rakyll.org/scheduler/) by Jaana Dogan ([@Rakyll](https://twitter.com/rakyll)) - [Scheduling in Go part 1](https://www.ardanlabs.com/blog/2018/08/scheduling-in-go-part1.html) - [Scheduling in Go part 2](https://www.ardanlabs.com/blog/2018/08/scheduling-in-go-part2.html)