Go: A Pragmatic Language

Go: A Pragmatic Language

When I first looked at Go, the open source programming language developed at Google, I was unimpressed. Then I used it. Now I find Go to be a solid and useful tool in my toolchest of languages. In this talk I'll introduce Go, its syntax, how you might use it. I'll talk about its strengths and weaknesses and give you code examples demonstrating some of its finer points. I will also show you some examples of how we use Go within DNSimple, in production. So join me for an intro to the world of Go, and learn about how to use this pragmatic language to solve your programming challenges.

31254903db793bf6f84bbd607fe092fd?s=128

Anthony Eden

June 05, 2014
Tweet

Transcript

  1. Go: A Pragmatic Language Anthony Eden - @aeden - DNSimple

  2. prag·mat·ic - “dealing with things sensibly and realistically in a

    way that is based on practical rather than theoretical considerations.”
  3. “Go's purpose is not to do research into programming language

    design; it is to improve the working environment for its designers and their coworkers.”
  4. What is Go?

  5. Systems Language

  6. Strongly Typed

  7. Garbage Collected

  8. Explicit support for Concurrent Programming

  9. “Go is more about software engineering than programming language research.

    Or to rephrase, it is about language design in the service of software engineering.”
  10. Learning by Example

  11. HTTP Server

  12. package main import ) func fmt.Fprintf(w, } func http.HandleFunc( "

    log.Fatal(http.ListenAndServe( }
  13. package main import (" "fmt"" "log"" "net/http"" ) func rootHandler(w

    http.ResponseWriter, r *http.Request) {" fmt.Fprintf(w, "All systems go\n")" }" " func main() {" http.HandleFunc("/", rootHandler)" " log.Fatal(http.ListenAndServe(":8080", nil))" }
  14. HTTP Client

  15. package main import ) func resp, err log.Printf( } log.Printf(

    }" }
  16. package main import (" "log"" "net/http"" ) func main() {"

    resp, err := http.Get("http://localhost:8080/")" if err != nil {" log.Printf("Error: %s", err)" } else {" log.Printf("%v", resp)" }" }
  17. Initialization: Constants, Variables and init()

  18. const DEFAULT_HTTP_BIND_PORT = "8080"" " var (! httpBindAddress = os.Getenv("HTTP_BIND_ADDRESS")"

    httpBindPort = os.Getenv("HTTP_BIND_PORT")" )" ! func init() {" if httpBindPort == "" {" httpBindPort = DEFAULT_HTTP_BIND_PORT" }" }
  19. package " import )" ! ! ! ! ! !

    ! ! ! ! ! ! ! ! func rootHandler(w http.ResponseWriter, r fmt.Fprintf(w, }" " func main() {" http.HandleFunc( ! hostAndPort log.Fatal(http.ListenAndServe(hostAndPort, } const DEFAULT_HTTP_BIND_PORT = "8080"" " var (! httpBindAddress = os.Getenv("HTTP_BIND_ADDRESS")" httpBindPort = os.Getenv("HTTP_BIND_PORT")" )" ! func init() {" if httpBindPort == "" {" httpBindPort = DEFAULT_HTTP_BIND_PORT" }" }
  20. Types

  21. Slices

  22. a := []int{1, 2, 3, 4, 5} // [1 2

    3 4 5] s := a[2:4] // [3 4] s = a[:3] // [1 2 3] s = a[1:] // [2 3 4 5] s = a[:] // [1 2 3 4 5]
  23. Looping

  24. i := 0" for {" fmt.Printf("%v: %v\n", i, a[i])" i

    += 1" if i >= len(a) {" break" }" }
  25. for index, value := range a {" fmt.Printf("%v: %v\n", index,

    value)" }
  26. Functions

  27. func rootHandler(w http.ResponseWriter, r *http.Request) {" fmt.Fprintf(w, "All systems go\n")"

    }
  28. f := func(x int, y int) int {" return x

    + y" }" fmt.Printf("Function result: %v\n", f(10, 22))
  29. func main() {" a := []int{1, 2, 3, 4, 5}"

    ! ! ! ! ! ! ! ! ! } multiplier := func(m int) []int {" r := []int{}" for _, v := range a {" r = append(r, v*m)" }" return r" }" " func closure(f func(int) []int) []int {" return f(10)" } fmt.Printf("Closure result: %v\n", closure(multiplier))
  30. “Go is an attempt to combine the ease of programming

    of an interpreted, dynamically typed language with the efficiency and safety of a statically typed, compiled language.”
  31. go build server.go

  32. go run server.go

  33. Dependency Management

  34. package gapl" " type Person struct {" Name string" Age

    int" }
  35. import (" "encoding/json"" "fmt"" " "log"" "net"" "net/http"" "os"" )

    gapl "github.com/aeden/go-a-pragmatic-language-lib"
  36. import ) gapl "github.com/aeden/go-a-pragmatic-language-lib"

  37. func personHandler(w http.ResponseWriter, r *http.Request) {" " ! ! !

    } w.Header().Set("Content-type", "application/json") person := gapl.Person{Name: "John Smith", Age: 42} encoder := json.NewEncoder(w) encoder.Encode(person)
  38. func personHandler(w http.ResponseWriter, r *http.Request) {" " ! ! !

    } w.Header().Set( person encoder encoder.Encode(person)
  39. package " import ! )" " const DEFAULT_HTTP_BIND_PORT = "

    var (" httpBindAddress = os.Getenv( httpBindPort = os.Getenv( )" " func init() {" }" " func rootHandler(w http.ResponseWriter, r fmt.Fprintf(w, }" " ! ! ! ! ! ! " func main() {" http.HandleFunc( ! " hostAndPort log.Fatal(http.ListenAndServe(hostAndPort, } gapl "github.com/aeden/go-a-pragmatic-language-lib" func personHandler(w http.ResponseWriter, r *http.Request) {" w.Header().Set("Content-type", "application/json")" person := gapl.Person{Name: "John Smith", Age: 42}" encoder := json.NewEncoder(w)" encoder.Encode(person)" } http.HandleFunc("/person", personHandler)
  40. Concurrency

  41. Communicating Sequential Processes

  42. Message Passing Via Channels

  43. package main" " import (" "fmt"" "math/rand"" "time"" )

  44. func addRand(c chan int) {" for {" time.Sleep(1 * time.Second)"

    c <- rand.Intn(100)" }" }" " func subRand(c chan int) {" for {" time.Sleep(2 * time.Second)" c <- -rand.Intn(100)" }" }"
  45. func printSum(c chan int) {" sum := 0" val :=

    0" " for {" val = <-c" fmt.Printf("%v + %v = %v\n", sum, val, sum+val)" sum = sum + val" }" }
  46. func main() {" " " " " " ! !

    ! ! " " } quitChan := make(chan int)" ! ! ! ! ! ! ! <-quitChan c := make(chan int)" " go printSum(c)" go addRand(c)" go subRand(c) rand.Seed(time.Now().Unix())
  47. package main" " import (" " "fmt"" " "math/rand"" "

    "time"" )" " func addRand(c chan int) {" " for {" " " time.Sleep(1 * time.Second)" " " c <- rand.Intn(100)" " }" }" " func subRand(c chan int) {" " for {" " " time.Sleep(2 * time.Second)" " " c <- -rand.Intn(100)" " }" }" " func printSum(c chan int) {" " sum := 0" " val := 0" " " for {" " " val = <-c" " " fmt.Printf("%v + %v = %v\n", sum, val, sum+val)" " " sum = sum + val" " }" }" " func main() {" " rand.Seed(time.Now().Unix())" " " quitChan := make(chan int)" " " c := make(chan int)" " " go printSum(c)" " go addRand(c)" " go subRand(c)" " " <-quitChan" }
  48. Interfaces

  49. Test

  50. package gapl import (" "testing"" ) func TestInMemoryPersonStore(t *testing.T) {"

    ! ! ! ! ! ! ! ! ! } name := "John Smith"" person := Person{Name: name, Age: 30} store := NewInMemoryPersonStore()" store.Put(name, person) person = store.Get(name)" if person.Name != name {" t.Errorf("Expected %s, got %s", name, person.Name)" }
  51. Implementation

  52. type PersonStore interface {" " Get(name string) Person" " Put(name

    string, person Person)" } type inMemoryPersonStore struct {" " people map[string]Person" }" func (store *inMemoryPersonStore) Get(name string) Person {" " return store.people[name]" }" " func (store *inMemoryPersonStore) Put(name string, person Person) {" " store.people[name] = person" } func NewInMemoryPersonStore() PersonStore {" " return &inMemoryPersonStore{people: make(map[string]Person)}" } package gapl
  53. Where Is Go Useful?

  54. Network Services

  55. System Monitoring Agents

  56. Command-line Utilities

  57. Data Processing

  58. Let’s See it Work

  59. “Go is an attempt to combine the ease of programming

    of an interpreted, dynamically typed language with the efficiency and safety of a statically typed, compiled language.”
  60. • What systems do I already control that might benefit

    from Go’s design? • What can I learn from Go to take to my preferred programming environment? • What is missing from Go that I absolutely cannot live without, and why?
  61. Go: A Pragmatic Language Anthony Eden - @aeden - DNSimple