Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Go for PHP Developers

Go for PHP Developers

A short intro to Golang for PHP devs

Terrence Ryan

October 25, 2017
Tweet

More Decks by Terrence Ryan

Other Decks in Technology

Transcript

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

    Compiled Go is a programming language
  2. ‹#› @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
  3. ‹#› @tpryan package main import "fmt" func main() { var

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

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

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

    monde", "Hallo Welt", "γειά σου κόσμος", "Ciao mondo", "こんにちは世界", "ৈࠁࣁਃ ࣁ҅", "Olá mundo", "Здравствулте мир", "Hola mundo"} Hello World
  9. ‹#› @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
  10. ‹#› @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
  11. ‹#› @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 • * • &
  12. ‹#› @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
  13. ‹#› @tpryan if *i < 0 || *i >= len(g)

    { log.Fatalf("%d is not valid, please choose between 0 - %d", *i, len(g)-1) } Handle errors
  14. ‹#› @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
  15. ‹#› @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?
  16. ‹#› @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
  17. ‹#› @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
  18. ‹#› @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
  19. ‹#› @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
  20. ‹#› @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
  21. ‹#› @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
  22. ‹#› @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
  23. ‹#› @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
  24. ‹#› @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
  25. ‹#› @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
  26. ‹#› @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
  27. ‹#› @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
  28. ‹#› @tpryan • Local (unexported) - First letter is lowercase

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

    "你好世界", … } func Greet(language string) (string, error) {…} func helper(language string) (int) {…} Hello World
  30. ‹#› @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
  31. ‹#› @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
  32. ‹#› @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
  33. ‹#› @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
  34. ‹#› @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
  35. ‹#› @tpryan type Greeting struct { Text string } func

    (g Greeting) Address() string{ return g.Text + ", Human!" } Custom Types - public methods
  36. ‹#› @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
  37. ‹#› @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
  38. ‹#› @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)
  39. ‹#› @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
  40. ‹#› @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
  41. ‹#› @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
  42. ‹#› @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
  43. ‹#› @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
  44. ‹#› @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
  45. ‹#› @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
  46. ‹#› @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
  47. ‹#› @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
  48. ‹#› @tpryan • Get password from Randomly Generated list •

    Test if password conforms to rules • Include a dictionary check Task 2 Pa$$w0rdCh3ck
  49. ‹#› @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",
  50. ‹#› @tpryan "AALII", "AALIIS", "AALS", "AARDVARK", "AARDVARKS", "AARDWOLF", "AARDWOLVES", "AARGH",

    "AARRGH", "AARRGHH", "AAS", "AASVOGEL", "AASVOGELS", "AB", Method 2 - Bruteforce Pa$$w0rdCh3ck
  51. ‹#› @tpryan • Write an app with 3 Docker images

    • Host on Kubernetes • Have the smallest Docker images possible Task 3
  52. ‹#› @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
  53. ‹#› @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
  54. ‹#› @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
  55. ‹#› @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
  56. ‹#› @tpryan Use go for problems where PHP has pain

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

    dealing with all the things you need to handle. - That Google Guy