44
WHY AND WHAT IS GO Marko Jantke / Christian Speckner, Mayflower GmbH

Why and what is go

Embed Size (px)

Citation preview

WHY ANDWHAT IS GO

Marko Jantke / Christian Speckner, Mayflower GmbH

A BRIEFHISTORY

CONCEIVED 2007 ATGOOGLE

Robert GriesemerRob PikeKen Thomson

...OF BELL LABS / UNIX FAME

...OF PLAN 9 FAME

The worst sci-fi movie everAn experimental OS developed at BellHeritage visible in Go (toolchain!)

SOME DATES

First commit: 03/2008Release 1.0 03/2012Last release 1.7.1: 22 days ago

WHERE ISGO?

POPULAR PROJECTSWRITTEN IN GO

DockerKubernetesetcdCaddyConsulMattermost...

WHY IS GO?

THE AUTHORITATIVEDOCUMENT

Go at Google: Language Design in the Service of SoftwareEngineering.

[https://talks.golang.org/2012/splash.article]

(And you'll be stumbling over Plan 9 more than once)

SOME DESIGN GOALS

Fast compilation cyclesSimple and concise syntax: easy to read, easy to parseFamiliarity for new developersScales well to large code basesPromote robust and maintainable designKeep large codebases robust in face of changeOffer maintainable paradigms for multithreading

INSIDE THEGOPHER

STATICALLY TYPED// Variable declaration var someint int var somestring string var somemap map[string]int // Type inference someint := 10 somestring := "Hello world" somemap := make(map[string]int) // Type definition type Sometype struct { Field1 int Field2 []bool } // Function declaration func Fooinator(param1 int, param2 SomeStruct) string { // Do something }

IMPLICIT INTERFACES,BUT NO CLASSES

package main import ( "fmt" "log" "os" ) type Doc interface {} type DocumentStorage interface { Store(int, Doc) (error) Get(int) (Doc, error) } type MemoryStorage struct { docs map[int]Doc

GARBAGE COLLECTED...type SomeStruct struct { Field1 string Field2 string } func Generator() SomeStruct { return SomeStruct{ Field1: "Hello", Field2: "World", } }

... WITH POINTERS ...type SomeStruct struct { Field1 string Field2 string } func Generator() *SomeStruct { return &SomeStruct{ Field1: "Hello", Field2: "World", } }

... AND CLOSURESfunc FibonacciGenerator() (func() int) { f0 := 0 f1 := 1 return func() { oldF0 := f0 f0 = f1 f1 = oldF0 + f1 return f1 } } // ... f := FibonacciGenerator() fmt.Println(f(), f(), f(), f(), f(), f()) // 1 2 3 5 8 13

LIGHTWEIGHT THREADS-> GOROUTINES

Scheduling (cooperative multithreading with multiplethreads)BlockingCommunication (channels)Races & mutexesEmbed code from golang/samples/interfaces.go

LIGHTWEIGHT THREADS ->GOROUTINES

package main import ( "fmt" "time" ) func saySomething(s string, times int) { for i := 0; i < times; i++ { time.Sleep(100 * time.Millisecond) fmt.Println(s) } } func main() { go saySomething("hello", 3) go saySomething("world", 3) saySomething("!", 3) } // output: world hello ! world hello ! world ! hello

LIGHTWEIGHT THREADS ->GOROUTINES

package main import ( "fmt" ) func sayHello(times int, outputChannel chan<- string) { for i := 0; i < times; i++ { outputChannel <- "Hello" } } func sayWorld(times int, inputChannel <-chan string, outputChannel chan<- string for i := 0; i < times; i++ { output := <- inputChannel + " World!" outputChannel <- output } } func printString(times int, inputChannel <-chan string, outputChannel chan<- bool for i := 0; i < times; i++ { output := <- inputChannel

NO EXCEPTIONHANDLING, BUT...

Errors as valuesMultiple return valuesDefersPanics and recover

NO EXCEPTION HANDLING, BUT... package main import ( "os" "flag" "log" ) func FileSize(path string) (int64, error) { fileInfo, err := os.Stat(path) if err != nil { return 0, err } return fileInfo.Size(), nil } func main() { var filePath string flag.StringVar(&filePath, "filePath", "", "the file to get the size of" flag.Parse()

HUGE STANDARDLIBRARY

—BATTERIES INCLUDED

HTTP SERVERtype handler int func (h *handler) ServeHTTP( response http.ResponseWriter, request *http.Request, ) { response.WriteHeader(http.StatusOK) fmt.Fprintf(response, "this is request #%v\n", *h) *h++ } func main() { i := 0 http.ListenAndServe(":8888", (*handler)(&i)) }

HTTP CLIENTresp, err := http.Get("http://www.mayflower.de") var responseBuffer []byte if err == nil { responseBuffer, err = ioutil.ReadAll(resp.Body) } if err == nil { fmt.Println(string(responseBuffer)) } else { fmt.Printf("ERROR: %v\n", err) }

STREAM COMPRESSIONresp, err := http.Get("http://www.mayflower.de") if err == nil { writer := gzip.NewWriter(os.Stdout) _, err = io.Copy(writer, resp.Body) if err == nil { writer.Close() } } if err != nil { fmt.Fprintf(os.Stderr, "ERROR: %v\n", err) }

AND MUCH, MUCH MORE...

Crypto, hashingMarshalling / Unmarshalling (JSON, Base64, XML, ...)Command line parsingComplex numbersJSON RPCReflectionGolang lexer and parser!

TOOLING

SWISS KNIVE: GOgo as interface to complete toolchaingo getgo build -xgo installgo test -racego test -coverprofile=c.outgo tool cover -html=c.out

TOOLCHAIN

"NATIVE" TOOLCHAINThis is the toolchain referred to in golang releaseRooted in Plan 9 toolchain (assembler, linker)Used to be C, now Golang (converted from C)Produces static binaries (not quite true anymore)OS: Win, Linux, OSX, BSD and friends, Plan 9 (!), ...Arch: x86, x86-64, ARM(v5678), ppcDead simple cross compilation

GOARCH=x86 GOOS=windows go install some/package

GCC FRONTEND

Lags behind native toolchain (currently 1.4 in GCC5)Relies on GCC & friends for optimization, codegeneration and linkingGenerates dynamic binariesSupports anything supported by GCC (MIPS anybody)Cross compilation: PITA

INTERFACING C

Works with CGO: generates glue codeDynamic dependencies: breaks cross compiling badly :(BUT: Lots of native go out there :)

TESTING, PROFILINGAND CODE COVERAGE

[MARCO]Testing files located by convention main.go ->main_test.gogo test -cover -cpuprofile cpu.out -memprofile mem.out

TESTING, PROFILING AND CODECOVERAGE

package main import "testing" func TestDivide(t *testing.T) { v, _ := Divide(10, 5) if v != 2 { t.Error("Expected 2, got:", v) } }

DEPENDENCYMANAGEMENT

import "github.com/googollee/go-socket.io"

DEPENDENCIES CAN BEAUTOMATICALLY IMPORTED

FROM GITHUB?

AWESOME!

AWESOME?Pulls directly from git masterStability?Versioning?API breaks?

REPRODUCIBLE BUILDS?

SOLUTION 1: GOPKG.INimport "gopkg.in/yaml.v1"

$ curl http://gopkg.in/yaml.v1?go-get=1 <html> <head> <meta name="go-import" content="gopkg.in/yaml.v1 git https://gopkg.in/yaml.v1"><meta name="go-source" content="gopkg.in/yaml.v1 _ https://github.com/go-yaml/yaml/tree/v1{/dir} https://github.com/go-yaml/yaml/blob/v1{/dir}/{file}#L{line}"> </head> <body> go get gopkg.in/yaml.v1 </body> </html>

Redirects to fixed tags on githubWorks well for small libraries

SOLUTION 2:VENDORING

Record and pin dependencies in per-package manifestRecursively download deps before buildNeeds external tooling and per-package support :(Popular specimen: glide

GOPHERFODDER

PERFORMANT SERVERSEvent loop AND threadsCompiled and statically typedStandard lib covers most networking stuffCommunity frameworks for services: go-micro, go-kit

DEPENDENCY-LESSUNIX-STYLE CLI TOOLS

Direct access to syscallsHuge standard librarySupports script-like code styleStatic binaries

EASY ACCESSIBLEFast entrance to the languageGreat documentationParallel programming for everyone

NOT SO GOOD FORGOPHERS

GUIEmbedded

THANK YOU FORLISTENINGQUESTIONS?

Christian Speckner <[email protected]>Marco Jantke <[email protected]>