Slide 1

Slide 1 text

‹#› @tpryan Terry Ryan Developer Advocate Go for PHP Developers

Slide 2

Slide 2 text

‹#› @tpryan Who are you?

Slide 3

Slide 3 text

‹#› @tpryan Go is just another tool

Slide 4

Slide 4 text

‹#› @tpryan 01 Introduction What is Go?

Slide 5

Slide 5 text

‹#› @tpryan • Developed at Google • Open Source • Compiled Go is a programming language

Slide 6

Slide 6 text

‹#› @tpryan Wait! What the hell is that thing?


Slide 7

Slide 7 text

‹#› @tpryan The Gopher https://blog.golang.org/gopher

Slide 8

Slide 8 text

‹#› @tpryan • Compiled • Garbage collected • Strongly typed • Statically typed • C syntax • Simple • Built to use multiple processors • Tools design for remote packages • Testing built in Language focused on Software engineering Go features

Slide 9

Slide 9 text

‹#› @tpryan 02 Simple CLI Let’s see some code already.

Slide 10

Slide 10 text

‹#› @tpryan package main func main() { println("Hello World") } Hello World main.go

Slide 11

Slide 11 text

‹#› @tpryan package main import "fmt" func main() { var s string = "Hello World" fmt.Printf("%s\n", s) } Hello World main.go

Slide 12

Slide 12 text

‹#› @tpryan go run main.go Hello World

Slide 13

Slide 13 text

‹#› @tpryan var s string = "Hello World” s := "Hello World" Type inference

Slide 14

Slide 14 text

‹#› @tpryan package main import "fmt" func main() { s := "Hello World" fmt.Printf("%s\n", s) } Hello World main.go

Slide 15

Slide 15 text

‹#› @tpryan Types • bool • string • int int8 int16 int32 int64 • uint uint8 uint16 uint32 uinint 64 uintptr • byte (uint8) • rune (int32) • float32 float 64 • complex64 complex128 • array, slice, map

Slide 16

Slide 16 text

‹#› @tpryan Go Arrays vs Slices • Array - finite, ordered collection of elements - users := [4]string • Slice - points to an array, allows for more dynamic operations - users :=[]strings abc abc abc abc abc abc abc abc abc

Slide 17

Slide 17 text

‹#› @tpryan greetings := [5]string{“你好世界", "Hello wereld", "Hello world", "Bonjour monde", "Hallo Welt"} Array

Slide 18

Slide 18 text

‹#› @tpryan greetings := []string{“你好世界", "Hello wereld", "Hello world", "Bonjour monde", "Hallo Welt”} greetings = greetings.append("γειά σου κόσμος") Slice

Slide 19

Slide 19 text

‹#› @tpryan If you aren’t sure, just use a slice.

Slide 20

Slide 20 text

‹#› @tpryan greetings := []string{"你好世界", "Hello wereld", "Hello world", "Bonjour monde", "Hallo Welt", "γειά σου κόσμος", "Ciao mondo", "こんにちは世界", "ৈࠁࣁਃ ࣁ҅", "Olá mundo", "Здравствулте мир", "Hola mundo"} Hello World

Slide 21

Slide 21 text

‹#› @tpryan package main import ( "fmt" "math/rand" "time" ) func main() { g := []string{"你好世界", … } rand.Seed(time.Now().UnixNano()) l := len(g) i := rand.Intn(l - 1) fmt.Printf("%s\n", greetings[i]) } Hello World

Slide 22

Slide 22 text

‹#› @tpryan Input Give our code something to respond to

Slide 23

Slide 23 text

‹#› @tpryan go run main.go -lang 2
 Hello World

Slide 24

Slide 24 text

‹#› @tpryan package main import ( "flag" "fmt" "log" "os" "strconv" ) func main() { i := flag.Int("lang", 0, " a number between 0 and 11") flag.Parse() a := []string{"你好世界", … } fmt.Printf("%s\n", a[*i]) } Hello World

Slide 25

Slide 25 text

‹#› @tpryan i := flag.Int("lang", 0, " a number between 0 and 11") flag.Parse() … *i Flags

Slide 26

Slide 26 text

‹#› @tpryan Pointers • Pointer is a link to the variables address in memory • Allows us to pass by reference not by value • In dealing with then you will see • * • &

Slide 27

Slide 27 text

‹#› @tpryan p := Person{"Steve", 28} // p is Person p := &Person{"Steve", 28} // p is a reference to a Person PrintPerson(*p) // pass a Person PrintPerson(&p) // pass a reference to a Person func PrintPerson(p Person) // function ONLY takes a Person func PrintPerson(p *Person) // function ONLY takes a reference to a Person Examples of pointers From https://gist.github.com/josephspurrier/7686b139f29601c3b370

Slide 28

Slide 28 text

‹#› @tpryan if *i < 0 || *i >= len(g) { log.Fatalf("%d is not valid, please choose between 0 - %d", *i, len(g)-1) } Handle errors

Slide 29

Slide 29 text

‹#› @tpryan go run main.go -lang 2
 Hello World

Slide 30

Slide 30 text

‹#› @tpryan Finishing up the Program

Slide 31

Slide 31 text

‹#› @tpryan go run main.go -lang English
 Hello World

Slide 32

Slide 32 text

‹#› @tpryan greetings := map[string]string{ "Chinese": "你好世界", "Dutch": "Hello wereld", "English": "Hello world", "French": "Bonjour monde", "German": "Hallo Welt", "Greek": "γειά σου κόσμος", "Italian": "Ciao mondo", "Japanese": "こんにちは世界", "Korean": "ৈࠁࣁਃ ࣁ҅", "Portuguese": "Olá mundo", "Russian": "Здравствулте мир", “Spanish": "Hola mundo", } Hello World

Slide 33

Slide 33 text

‹#› @tpryan newMap := map[keyType]valueType{} newMap := make(map[keyType]valueType) Maps

Slide 34

Slide 34 text

‹#› @tpryan func main() { l := flag.String("lang", "English", "a language in which to get greeting.") flag.Parse() g := map[string]string{"Chinese":"你好世界", … } if r, ok := g[*l]; ok { fmt.Printf("%s\n", r) } else { fmt.Printf("The language you selected is not valid.\n") } } Hello World Wait! What the hell is that thing?

Slide 35

Slide 35 text

‹#› @tpryan

Slide 36

Slide 36 text

‹#› @tpryan func main() { l := flag.String("lang", "English", "a language in which to get greeting.") flag.Parse() g := map[string]string{"Chinese":"你好世界", … } if r, ok := g[*l]; ok { fmt.Printf("%s\n", r) } else { fmt.Printf("The language you selected is not valid.\n") } } Hello World

Slide 37

Slide 37 text

‹#› @tpryan if r, ok := g[*l]; ok { fmt.Printf("%s\n", r) } else { fmt.Printf("The language you selected is not valid.\n") } Hello World

Slide 38

Slide 38 text

‹#› @tpryan r, ok := g[*l] if ok { fmt.Printf("%s\n", r) } else { fmt.Printf("The language you selected is not valid.\n") } Hello World

Slide 39

Slide 39 text

‹#› @tpryan result, keyexists? := greeting[*language] if keyexists? { fmt.Printf("%s\n", result) } else { fmt.Printf("The language you selected is not valid.\n")} Hello World

Slide 40

Slide 40 text

‹#› @tpryan if result, keyexists? := greeting[*language]; keyexists? { fmt.Printf("%s\n", result) } else { fmt.Printf("The language you selected is not valid.\n”) } Hello World

Slide 41

Slide 41 text

‹#› @tpryan if r, ok := g[*l]; ok { fmt.Printf("%s\n", r) } else { fmt.Printf("The language you selected is not valid.\n") } Hello World

Slide 42

Slide 42 text

‹#› @tpryan func main() { l := flag.String("lang", "English", "a language in which to get greeting.") flag.Parse() g := map[string]string{"Chinese":"你好世界", … } if r, ok := g[*l]; ok { fmt.Printf("%s\n", r) } else { fmt.Printf("The language you selected is not valid.\n") } } Hello World

Slide 43

Slide 43 text

‹#› @tpryan Why are go variables so short?

Slide 44

Slide 44 text

‹#› @tpryan We hate you and we hate things that are good. - Creators of Go

Slide 45

Slide 45 text

‹#› @tpryan Variable names in Go should be short rather than long. This is especially true for local variables with limited scope. Prefer c to lineCount. Prefer i to sliceIndex. https://github.com/golang/go/wiki/CodeReviewComments#variable-names

Slide 46

Slide 46 text

‹#› @tpryan @tpryan PHP dog Go d Java PuppyWithASadFaceFactoryBean

Slide 47

Slide 47 text

‹#› @tpryan Variable Length • As short as can be while still being descriptive • The further away from which they are used, the longer they can be. • Local variable - r • Package public variable - rate

Slide 48

Slide 48 text

‹#› @tpryan Variable names Conventions i Index c count or context r,w reader, writer req, res request, response err error buf buffer f file ok assertion result

Slide 49

Slide 49 text

‹#› @tpryan 03 Package Writing code to be shared

Slide 50

Slide 50 text

‹#› @tpryan package helloworld import "errors" var greetings = map[string]string{"Chinese": "你好世界", … } func Greet(language string) (string, error) { if r, ok := greetings[language]; ok { return r, nil } else { return "", errors.New("The language you selected is not valid.") } } Hello World

Slide 51

Slide 51 text

‹#› @tpryan • Local (unexported) - First letter is lowercase • Global (exported) - First letter is Uppercase Access (Public/Private)

Slide 52

Slide 52 text

‹#› @tpryan package helloworld import "errors" var greetings = map[string]string{"Chinese": "你好世界", … } func Greet(language string) (string, error) {…} func helper(language string) (int) {…} Hello World

Slide 53

Slide 53 text

‹#› @tpryan Error Handling

Slide 54

Slide 54 text

‹#› @tpryan func Greet(language string) (string, error) { if r, ok := greetings[language]; ok { return r, nil } else { return "", errors.New("the language you selected is not valid") } } Error Handling

Slide 55

Slide 55 text

‹#› @tpryan var ErrNotFound = errors.New("the language you selected is not valid") func Greet(language string) (string, error) { if r, ok := greetings[language]; ok { return r, nil } else { return "", ErrNotFound } } Error Handling

Slide 56

Slide 56 text

‹#› @tpryan func main() { l := flag.String("lang", "English", "a language in which to get greeting.") flag.Parse() greet, err := helloworld.Greet(*l) if err != nil { log.Fatal(err.Error()) } fmt.Printf("%s\n", greet) } Error Handling

Slide 57

Slide 57 text

‹#› @tpryan func main() { l := flag.String("lang", "English", "a language in which to get greeting.") flag.Parse() greet, err := helloworld.Greet(*l) if err != nil { if err == helloworld.ErrNotFound { listLanguages() return } else { log.Fatal(fmt.Errorf("could not get greeting: %v\n”, err)) } } fmt.Printf("%s\n", greet) } Error Handling

Slide 58

Slide 58 text

‹#› @tpryan package helloworld import "errors" var greetings = map[string]string{"Chinese": "你好世界", … } var ErrNotFound = errors.New("the language you selected is not valid") func Greet(language string) (string, error) {…} func helper(language string) (int) {…} Hello World

Slide 59

Slide 59 text

‹#› @tpryan package main import ( "fmt" "log" "os" "github.com/tpryan/gosamples/helloworld" ) Hello World

Slide 60

Slide 60 text

‹#› @tpryan Object Oriented Sorta

Slide 61

Slide 61 text

‹#› @tpryan type Greeting struct { Text string } Custom Types

Slide 62

Slide 62 text

‹#› @tpryan type Greeting struct { Text string } func (g Greeting) Address() string{ return g.Text + ", Human!" } Custom Types - public methods

Slide 63

Slide 63 text

‹#› @tpryan type Greeting struct { Text string } func (g Greeting) Address() string { return g.Text + ", Human!" } func (g Greeting) threat() string { return g.Text + ", Human! Hah, we will crush them." } Custom Types - private methods

Slide 64

Slide 64 text

‹#› @tpryan type Greeting struct { Text string secret string } func (g Greeting) Address() string { return g.Text + ", Human!" } func (g Greeting) threat() string { return g.Text + ", Human! Hah, we will crush them." } Custom Types - private field

Slide 65

Slide 65 text

‹#› @tpryan Package, Type, and Method Names • Be descriptive, but concise • No: package l • No: package logFileWriter • Yes: package log • Don’t repeat yourself • No: log.LogFileWrite • No: log.LogFileRead • Better: log.Write(dest File) • Better: log.Read(src File) • Best: log.Write(dest io.Writer) • Best: log.Read(src io.Reader)

Slide 66

Slide 66 text

‹#› @tpryan 04 Web application Cause we didn’t come here to build CLIs

Slide 67

Slide 67 text

‹#› @tpryan package helloworld import "errors" var greetings = map[string]string{"Chinese": "你好世界", … } var ErrNotFound = errors.New("the language you selected is not valid") func Greet(language string) (string, error) {…} func Langauges() []string Web app - base package

Slide 68

Slide 68 text

‹#› @tpryan package main import ( "encoding/json" "fmt" "log" "net/http" "github.com/tpryan/gosamples/helloworld" ) func main() { http.HandleFunc("/get", HandleGet) http.HandleFunc("/list", HandleList) http.ListenAndServe(":8080", nil) } Web app - main

Slide 69

Slide 69 text

‹#› @tpryan func main() { http.HandleFunc("/get", HandleGet) http.HandleFunc("/list", HandleList) http.ListenAndServe(":8080", nil) } Web app - wire up routing

Slide 70

Slide 70 text

‹#› @tpryan func HandleList(w http.ResponseWriter, r *http.Request) { list := helloworld.Langauges() json, err := json.Marshal(list) if err != nil { handleError(w, err) return } sendJSON(w, string(json), http.StatusOK) } Web app - list handler

Slide 71

Slide 71 text

‹#› @tpryan func HandleGet(w http.ResponseWriter, r *http.Request) { lang := r.FormValue("language") greet, err := helloworld.Greet(lang) if err != nil { handleError(w, err) return } sendJSON(w, greet, http.StatusOK) } Web app - get handler

Slide 72

Slide 72 text

‹#› @tpryan func handleError(w http.ResponseWriter, err error) { msg := fmt.Sprintf("{\"error\":\"%s\"}", err.Error()) sendJSON(w, msg, http.StatusInternalServerError) log.Print(err) } func sendJSON(w http.ResponseWriter, content string, status int) { w.Header().Set("Content-Type", "application/json") w.WriteHeader(status) fmt.Fprint(w, content) } Web app - responders

Slide 73

Slide 73 text

‹#› @tpryan 05 Concurrency

Slide 74

Slide 74 text

‹#› @tpryan 06 Tooling

Slide 75

Slide 75 text

‹#› @tpryan go fmt main.go 
 Formatting Code

Slide 76

Slide 76 text

‹#› @tpryan go build main.go 
 Building Executable

Slide 77

Slide 77 text

‹#› @tpryan go test Testing

Slide 78

Slide 78 text

‹#› @tpryan func TestGreet(t *testing.T) { cases := []struct { In string Out string Err error }{ {"", "", ErrorNotFound}, {"English", "Hello world", nil}, } for _, c := range cases { actualOut, actualErr := Greet(c.In) if actualOut != c.Out { t.Errorf("Validate(%q) == %q, want %q", c.In, actualOut, c.Out) } if actualErr != nil && actualErr != c.Err { t.Errorf("Validate(%q) == %q, want %q", c.In, actualErr, c.Err) } } } Testing

Slide 79

Slide 79 text

‹#› @tpryan go doc Seeing Documentation

Slide 80

Slide 80 text

‹#› @tpryan godoc -http :8080 Seeing Documentation But Better

Slide 81

Slide 81 text

‹#› @tpryan // Package helloworld returns greetings in several common languages package helloworld import "errors" // ErrorNotFound occurs when the input language is not one we have // in our collection var ErrorNotFound = errors.New("the language you selected is not valid") // Greet returns a greeting in the input language. If the languages is not // found, returns ErrorNotFound func Greet(language string) (string, error) {…} // Languages returns a list of the supported languages func Languages() []string {…} Seeing Documentation But Better

Slide 82

Slide 82 text

‹#› @tpryan Seeing Documentation But Better

Slide 83

Slide 83 text

‹#› @tpryan go get github.com/gorilla/rpc Retrieve Dependency

Slide 84

Slide 84 text

‹#› @tpryan IDE

Slide 85

Slide 85 text

‹#› @tpryan

Slide 86

Slide 86 text

‹#› @tpryan 07 Use Cases When does it make sense to switch

Slide 87

Slide 87 text

‹#› @tpryan • Get articles from Wordpress MySQL • Flatten into HTML Files • Write to Disk Task 1

Slide 88

Slide 88 text

‹#› @tpryan make test n=10 Executing php test 0.573 Executing go test 0.557 Task 1

Slide 89

Slide 89 text

‹#› @tpryan make test n=100 Executing php test 4.384 Executing go test 5.146 Task 1

Slide 90

Slide 90 text

‹#› @tpryan func writeSeq(entries []Entry, outdir string, count int, t template.Template) error { for i := 1; i <= count; i++ { err := writeEntries(entries, outdir+strconv.Itoa(i), t) if err != nil { log.Fatal(err) } } return nil } First attempt

Slide 91

Slide 91 text

‹#› @tpryan func writePar(entries []Entry, outdir string, count int, t template.Template) error { var wg sync.WaitGroup wg.Add(count) for i := 1; i <= count; i++ { go func(i int, wg *sync.WaitGroup) { defer wg.Done() err := writeEntries(entries, outdir+strconv.Itoa(i), t) if err != nil { log.Fatal(err) } }(i, &wg) } wg.Wait() return nil } Use concurrency

Slide 92

Slide 92 text

‹#› @tpryan make test n=100 method=parallel Executing php test 4.614 Executing go test 2.889 Task 1

Slide 93

Slide 93 text

‹#› @tpryan • Get password from Randomly Generated list • Test if password conforms to rules • Include a dictionary check Task 2 Pa$$w0rdCh3ck

Slide 94

Slide 94 text

‹#› @tpryan "AALII", "AALIIS", "AALS", "AARDVARK", "AARDVARKS", "AARDWOLF", "AARDWOLVES", "AARGH", "AARRGH", "AARRGHH", "AAS", "AASVOGEL", "AASVOGELS", "AB", Method 1 - Hash Pa$$w0rdCh3ck "Pa$$", "a$$w", "$$w0", "$w0r", "w0rd", "0rdC", "rdCh", "dCh3", "Ch3c", "h3ck", "Pa$$w", "a$$w0", "$$w0r", "$w0rd",

Slide 95

Slide 95 text

‹#› @tpryan make test n=10 method=hash Executing php test 0.141 Executing go test 0.077 Task 2

Slide 96

Slide 96 text

‹#› @tpryan make test n=1000 method=hash Executing php test 0.264 Executing go test 0.091 Task 2

Slide 97

Slide 97 text

‹#› @tpryan make test n=100000 method=hash Executing php test 7.339 Executing go test 0.823 Task 2

Slide 98

Slide 98 text

‹#› @tpryan "AALII", "AALIIS", "AALS", "AARDVARK", "AARDVARKS", "AARDWOLF", "AARDWOLVES", "AARGH", "AARRGH", "AARRGHH", "AAS", "AASVOGEL", "AASVOGELS", "AB", Method 2 - Bruteforce Pa$$w0rdCh3ck

Slide 99

Slide 99 text

‹#› @tpryan make test n=10 method=bruteforce Executing php test 0.962 Executing go test 0.094 Task 2

Slide 100

Slide 100 text

‹#› @tpryan make test n=1000 method=bruteforce Executing php test 96.425 Executing go test 1.809 Task 2

Slide 101

Slide 101 text

‹#› @tpryan • Write an app with 3 Docker images • Host on Kubernetes • Have the smallest Docker images possible Task 3

Slide 102

Slide 102 text

‹#› @tpryan • Whack a pod • API - random color generator • PHP • gcr.io/google_appengine/php:latest • Admin - Kubernetes API Proxy • PHP • gcr.io/google_appengine/php:latest • Game - UI for app • HTML/JS/CSS • gcr.io/google_appengine/php:latest Task 3 Before After API 171 MB Admin 171 MB Game 181 MB Total 523 MB

Slide 103

Slide 103 text

‹#› @tpryan • Whack a pod • API - random color generator • Golang executable • Scratch • Admin - Kubernetes API Proxy • Golang executable • Scratch • Game - UI for app • HTML/JS/CSS • nginx Task 3 Before After API 171 MB 2 MB Admin 171 MB 2 MB Game 181 MB 49 MB Total 523 MB 53 MB -470 MB

Slide 104

Slide 104 text

‹#› @tpryan Does it actually matter?

Slide 105

Slide 105 text

‹#› @tpryan 08 Go Weirdness Top things that bug new Gophers

Slide 106

Slide 106 text

‹#› @tpryan • https://opencredo.com/why-i-dont-like-error-handling-in-go/ • https://blog.golang.org/errors-are-values • https://github.com/pkg/errors • But, all I can say is you get used to it. No exceptions

Slide 107

Slide 107 text

‹#› @tpryan • Maybe arrays, slices, and maps will work? • Maybe interfaces will work? • Maybe using … in signature definition will work? • Or you know, maybe Go isn’t for you No Generics

Slide 108

Slide 108 text

‹#› @tpryan • Yes, it is. Gopath is confusing

Slide 109

Slide 109 text

‹#› @tpryan • All Go projects happen in workspaces • All Go workspaces have 3 parts • src • bin • pkg • Most everything happens in src • github.com/username/project • Set folder that contains src, bin, pkg to GOPATH • export GOPATH=$HOME/go
 Go Path

Slide 110

Slide 110 text

‹#› @tpryan • go get • vendoring • dep Maturing soon Dependency Management

Slide 111

Slide 111 text

‹#› @tpryan 08 Conclusions Bring it home

Slide 112

Slide 112 text

‹#› @tpryan Use go for problems where PHP has pain dealing with all the things you need to handle. - That Google Guy

Slide 113

Slide 113 text

‹#› @tpryan Use go for all the things! - That Google Guy

Slide 114

Slide 114 text

‹#› @tpryan Use go for problems where PHP has pain dealing with all the things you need to handle. - That Google Guy

Slide 115

Slide 115 text

‹#› @tpryan Search for ‘golang’ - That Google Guy

Slide 116

Slide 116 text

‹#› @tpryan Thank You Gopher Images credits Renee French gophercloud Blue Matador Ashley McNamara

Slide 117

Slide 117 text

‹#› @tpryan Thank You terrenceryan.com @tpryan This preso: http://bit.ly/tpryan-go4php