Go for PHP Developers

Go for PHP Developers

A short intro to Golang for PHP devs

6c18ceafef161be26ae441469b29c475?s=128

Terrence Ryan

October 25, 2017
Tweet

Transcript

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

  2. ‹#› @tpryan Who are you?

  3. ‹#› @tpryan Go is just another tool

  4. ‹#› @tpryan 01 Introduction What is Go?

  5. ‹#› @tpryan • Developed at Google • Open Source •

    Compiled Go is a programming language
  6. ‹#› @tpryan Wait! What the hell is that thing?


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

  8. ‹#› @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
  9. ‹#› @tpryan 02 Simple CLI Let’s see some code already.

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

    Hello World main.go
  11. ‹#› @tpryan package main import "fmt" func main() { var

    s string = "Hello World" fmt.Printf("%s\n", s) } Hello World main.go
  12. ‹#› @tpryan go run main.go Hello World

  13. ‹#› @tpryan var s string = "Hello World” s :=

    "Hello World" Type inference
  14. ‹#› @tpryan package main import "fmt" func main() { s

    := "Hello World" fmt.Printf("%s\n", s) } Hello World main.go
  15. ‹#› @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
  16. ‹#› @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
  17. ‹#› @tpryan greetings := [5]string{“你好世界", "Hello wereld", "Hello world", "Bonjour

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

    monde", "Hallo Welt”} greetings = greetings.append("γειά σου κόσμος") Slice
  19. ‹#› @tpryan If you aren’t sure, just use a slice.

  20. ‹#› @tpryan greetings := []string{"你好世界", "Hello wereld", "Hello world", "Bonjour

    monde", "Hallo Welt", "γειά σου κόσμος", "Ciao mondo", "こんにちは世界", "ৈࠁࣁਃ ࣁ҅", "Olá mundo", "Здравствулте мир", "Hola mundo"} Hello World
  21. ‹#› @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
  22. ‹#› @tpryan Input Give our code something to respond to

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

  24. ‹#› @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
  25. ‹#› @tpryan i := flag.Int("lang", 0, " a number between

    0 and 11") flag.Parse() … *i Flags
  26. ‹#› @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 • * • &
  27. ‹#› @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
  28. ‹#› @tpryan if *i < 0 || *i >= len(g)

    { log.Fatalf("%d is not valid, please choose between 0 - %d", *i, len(g)-1) } Handle errors
  29. ‹#› @tpryan go run main.go -lang 2
 Hello World

  30. ‹#› @tpryan Finishing up the Program

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

  32. ‹#› @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
  33. ‹#› @tpryan newMap := map[keyType]valueType{} newMap := make(map[keyType]valueType) Maps

  34. ‹#› @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?
  35. ‹#› @tpryan <?php $greetings = []; $greetings[“Chinese"]="你好世界"; … if (!isset($argv[1])){

    $argv[1] = "English"; } if (array_key_exists($argv[1], $greetings)){ echo $greetings[$argv[1]]."\n"; } else { die("The language you selected is not valid.\n"); } Hello World
  36. ‹#› @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
  37. ‹#› @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
  38. ‹#› @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
  39. ‹#› @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
  40. ‹#› @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
  41. ‹#› @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
  42. ‹#› @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
  43. ‹#› @tpryan Why are go variables so short?

  44. ‹#› @tpryan We hate you and we hate things that

    are good. - Creators of Go
  45. ‹#› @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
  46. ‹#› @tpryan @tpryan PHP dog Go d Java PuppyWithASadFaceFactoryBean

  47. ‹#› @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
  48. ‹#› @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
  49. ‹#› @tpryan 03 Package Writing code to be shared

  50. ‹#› @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
  51. ‹#› @tpryan • Local (unexported) - First letter is lowercase

    • Global (exported) - First letter is Uppercase Access (Public/Private)
  52. ‹#› @tpryan package helloworld import "errors" var greetings = map[string]string{"Chinese":

    "你好世界", … } func Greet(language string) (string, error) {…} func helper(language string) (int) {…} Hello World
  53. ‹#› @tpryan Error Handling

  54. ‹#› @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
  55. ‹#› @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
  56. ‹#› @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
  57. ‹#› @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
  58. ‹#› @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
  59. ‹#› @tpryan package main import ( "fmt" "log" "os" "github.com/tpryan/gosamples/helloworld"

    ) Hello World
  60. ‹#› @tpryan Object Oriented Sorta

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

    Types
  62. ‹#› @tpryan type Greeting struct { Text string } func

    (g Greeting) Address() string{ return g.Text + ", Human!" } Custom Types - public methods
  63. ‹#› @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
  64. ‹#› @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
  65. ‹#› @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)
  66. ‹#› @tpryan 04 Web application Cause we didn’t come here

    to build CLIs
  67. ‹#› @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
  68. ‹#› @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
  69. ‹#› @tpryan func main() { http.HandleFunc("/get", HandleGet) http.HandleFunc("/list", HandleList) http.ListenAndServe(":8080",

    nil) } Web app - wire up routing
  70. ‹#› @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
  71. ‹#› @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
  72. ‹#› @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
  73. ‹#› @tpryan 05 Concurrency

  74. ‹#› @tpryan 06 Tooling

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

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

  77. ‹#› @tpryan go test Testing

  78. ‹#› @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
  79. ‹#› @tpryan go doc Seeing Documentation

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

  81. ‹#› @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
  82. ‹#› @tpryan Seeing Documentation But Better

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

  84. ‹#› @tpryan IDE

  85. ‹#› @tpryan

  86. ‹#› @tpryan 07 Use Cases When does it make sense

    to switch
  87. ‹#› @tpryan • Get articles from Wordpress MySQL • Flatten

    into HTML Files • Write to Disk Task 1
  88. ‹#› @tpryan make test n=10 Executing php test 0.573 Executing

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

    go test 5.146 Task 1
  90. ‹#› @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
  91. ‹#› @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
  92. ‹#› @tpryan make test n=100 method=parallel Executing php test 4.614

    Executing go test 2.889 Task 1
  93. ‹#› @tpryan • Get password from Randomly Generated list •

    Test if password conforms to rules • Include a dictionary check Task 2 Pa$$w0rdCh3ck
  94. ‹#› @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",
  95. ‹#› @tpryan make test n=10 method=hash Executing php test 0.141

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

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

    Executing go test 0.823 Task 2
  98. ‹#› @tpryan "AALII", "AALIIS", "AALS", "AARDVARK", "AARDVARKS", "AARDWOLF", "AARDWOLVES", "AARGH",

    "AARRGH", "AARRGHH", "AAS", "AASVOGEL", "AASVOGELS", "AB", Method 2 - Bruteforce Pa$$w0rdCh3ck
  99. ‹#› @tpryan make test n=10 method=bruteforce Executing php test 0.962

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

    Executing go test 1.809 Task 2
  101. ‹#› @tpryan • Write an app with 3 Docker images

    • Host on Kubernetes • Have the smallest Docker images possible Task 3
  102. ‹#› @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
  103. ‹#› @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
  104. ‹#› @tpryan Does it actually matter?

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

    Gophers
  106. ‹#› @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
  107. ‹#› @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
  108. ‹#› @tpryan • Yes, it is. Gopath is confusing

  109. ‹#› @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
  110. ‹#› @tpryan • go get • vendoring • dep Maturing

    soon Dependency Management
  111. ‹#› @tpryan 08 Conclusions Bring it home

  112. ‹#› @tpryan Use go for problems where PHP has pain

    dealing with all the things you need to handle. - That Google Guy
  113. ‹#› @tpryan Use go for all the things! - That

    Google Guy
  114. ‹#› @tpryan Use go for problems where PHP has pain

    dealing with all the things you need to handle. - That Google Guy
  115. ‹#› @tpryan Search for ‘golang’ - That Google Guy

  116. ‹#› @tpryan Thank You Gopher Images credits Renee French gophercloud

    Blue Matador Ashley McNamara
  117. ‹#› @tpryan Thank You terrenceryan.com @tpryan This preso: http://bit.ly/tpryan-go4php