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

Go - a simple programming environment by Andrew Gerrand

Go - a simple programming environment by Andrew Gerrand

Watch the talk here: https://vimeo.com/69237265

Railsberry

April 23, 2013
Tweet

More Decks by Railsberry

Other Decks in Technology

Transcript

  1. Go: a simple programming
    environment
    23 April 2013
    Andrew Gerrand
    Google

    View Slide

  2. Why Go?

    View Slide

  3. Software should be simple

    View Slide

  4. Software can be simple

    View Slide

  5. What I mean by "simple"
    Small
    Readable
    Consistent
    Orthogonal
    Predictable
    Robust
    Useful by default

    View Slide

  6. Go at a glance
    Compiled
    Statically typed
    Clean syntax
    Simple type system
    Concurrency primitives
    Rich standard library
    Great tools
    Open source
    This talk is just a taste.

    View Slide

  7. The Gopher

    View Slide

  8. Hello, Go
    package main
    import "fmt"
    func main() {
    fmt.Println("Hello, Go")
    } Run

    View Slide

  9. go
    Goroutines are lightweight threads that are managed by the Go runtime.
    To run a function in a new goroutine, just put "go" before the function call.
    package main
    import (
    "fmt"
    "time"
    )
    func main() {
    go say("let's go!", 3*time.Second)
    go say("ho!", 2*time.Second)
    go say("hey!", 1*time.Second)
    time.Sleep(4 * time.Second)
    }
    func say(text string, delay time.Duration) {
    time.Sleep(delay)
    fmt.Println(text)
    } Run

    View Slide

  10. chan
    Channels are typed conduits for sychronization and communication between
    goroutines.
    They're a versatile and expressive means of modelling concurrent processes.
    But we're not going to look at them today. (There's no time!)

    View Slide

  11. sync
    Channels are great, but sometimes other concurrency mechanisms are a better fit.
    The sync package provides mutexes, condition variables, and more useful primitives.
    func main() {
    wg := new(sync.WaitGroup)
    wg.Add(3)
    go say(wg, "let's go!", 3*time.Second)
    go say(wg, "ho!", 2*time.Second)
    go say(wg, "hey!", 1*time.Second)
    wg.Wait()
    }
    func say(wg *sync.WaitGroup, text string, delay time.Duration) {
    time.Sleep(delay)
    fmt.Println(text)
    wg.Done()
    } Run

    View Slide

  12. time
    The
    time
    package provides
    Time
    and
    Duration
    types, for expressing instants in time
    and periods of time.
    It also provides a
    Location
    type for expressing time zones.
    And, as we've already seen, it provides functions related to sleeping.
    birthday, _ := time.Parse("Jan 2 2006", "Nov 10 2009") // time.Time
    age := time.Since(birthday) // time.Duration
    fmt.Printf("Go is %d days old\n", age/(time.Hour*24)) Run
    t := time.Now()
    fmt.Println(t.In(time.UTC))
    home, _ := time.LoadLocation("Australia/Sydney")
    fmt.Println(t.In(home)) Run

    View Slide

  13. net/http (1/2)
    The net/http package provides an HTTP client.
    The client handles HTTP Keep-Alive using a pool of connections, by default.
    (This is configurable, of course.)
    func main() {
    r, err := http.Get("http://www.golang.org/")
    if err != nil {
    log.Fatal(err)
    }
    if r.StatusCode != http.StatusOK {
    log.Fatal(r.Status)
    }
    io.Copy(os.Stdout, r.Body)
    } Run

    View Slide

  14. net/http (2/2)
    The net/http package also provides an HTTP server.
    This is a high-performance, DoS-hardened, production-ready web server.
    It serves dl.google.com.
    func main() {
    http.HandleFunc("/", handler)
    err := http.ListenAndServe("localhost:8080", nil)
    if err != nil {
    log.Fatal(err)
    }
    }
    func handler(w http.ResponseWriter, r *http.Request) {
    fmt.Fprint(w, "Hello, web")
    } Run

    View Slide

  15. html/template
    The
    html/template
    package provides an HTML templating system that automatically
    escapes content depending on its context.
    const html = `
    var foo = {{.Foo}};

    {{.Text}}

    `
    func main() {
    tmpl := template.Must(template.New("example").Parse(html))
    data := struct {
    Foo string
    URL, Text string
    }{
    Foo: `Some "quoted" string`,
    URL: `" onClick="alert('xss!');`,
    Text: "The <- operator is for channel sends and receives",
    }
    tmpl.Execute(os.Stdout, data)
    } Run

    View Slide

  16. flag
    The
    flag
    package provides a simple API for parsing command-line flags.
    Example invocation (a little different than GNU getopt):
    $ flag -message 'Hold on...' -delay 5m
    var (
    message = flag.String("message", "Hello!", "what to say")
    delay = flag.Duration("delay", 2*time.Second, "how long to wait")
    )
    func main() {
    flag.Parse()
    fmt.Println(*message)
    time.Sleep(*delay)
    } Run

    View Slide

  17. An example
    isgo1point1outyet.com (http://isgo1point1outyet.com)

    View Slide

  18. Structure
    The program has two parts that execute concurrently:
    a poller that continuously checks whether Go 1.1 has been tagged, and
    an HTTP server providing the user interface.

    View Slide

  19. Sharing state
    We must share state ("Is Go 1.1 out?") between the repo poller and the user interface.
    This global struct variable contains a sync.RWMutex and a boolean value:
    var state struct {
    sync.RWMutex
    yes bool // whether Go 1.1 has been tagged.
    }
    To read, take the read lock (multiple goroutines can do this simultaneously):
    state.RLock()
    yes := state.yes
    state.RUnlock()
    To write, take the write lock (only one goroutine can do this at a time):
    state.Lock()
    state.yes = true
    state.Unlock()

    View Slide

  20. Polling (1/2)
    When a go1.1 tag exists in the Go repository this URL will return a "200 OK" response:
    const changeURL = "https://code.google.com/p/go/source/detail?r=go1.1"
    The isTagged function returns true if the go1.1 tag exists.
    func isTagged() bool {
    r, err := http.Head(changeURL)
    if err != nil {
    log.Print(err)
    return false
    }
    return r.StatusCode == http.StatusOK
    }

    View Slide

  21. Polling (2/2)
    The poll function loops until isTagged returns true.
    Then it updates the state ("Go 1.1 is out!") and returns.
    func poll(period time.Duration) {
    for !isTagged() {
    time.Sleep(period)
    }
    state.Lock()
    state.yes = true
    state.Unlock()
    }

    View Slide

  22. Serving the user interface
    The
    handler
    function serves an HTTP request.
    It puts the
    state.yes
    and
    changeURL
    values into a struct,
    and uses the struct to render the template as the HTTP response.
    func handler(w http.ResponseWriter, r *http.Request) {
    state.RLock()
    data := struct {
    Yes bool
    URL string
    }{
    Yes: state.yes,
    URL: changeURL,
    }
    state.RUnlock()
    err := tmpl.Execute(w, data)
    if err != nil {
    log.Print(err)
    }
    }

    View Slide

  23. The HTML user interface
    The tmpl variable is a template that provides the HTML UI.
    It is a global variable, so the template is parsed just once at init time.
    var tmpl = template.Must(template.New("root").Parse(`

    Is Go 1.1 out yet?

    {{if .Yes}}
    YES!
    {{else}}
    No.
    {{end}}


    `))

    View Slide

  24. Putting it all together
    The
    main
    function starts polling in a new goroutine and sets up the web server.
    Some command-line flags enable run time configuration.
    var (
    httpAddr = flag.String("http", "localhost:8080", "Listen address")
    pollPeriod = flag.Duration("poll", 5*time.Second, "Poll period")
    )
    func main() {
    flag.Parse()
    go poll(*pollPeriod)
    http.HandleFunc("/", handler)
    log.Fatal(http.ListenAndServe(*httpAddr, nil))
    }
    The whole program is just 68 lines of code.

    View Slide

  25. Demo

    View Slide

  26. One more thing

    View Slide

  27. expvar (1/2)
    The
    expvar
    package allows you to export variables via an HTTP handler
    registered at
    /debug/vars
    (http://localhost:8080/debug/vars) .
    package main
    import (
    "expvar"
    "log"
    "net/http"
    "time"
    )
    func main() {
    count := expvar.NewInt("count")
    go func() {
    for {
    count.Add(1)
    time.Sleep(time.Second)
    }
    }()
    log.Fatal(http.ListenAndServe("localhost:8080", nil))
    } Run

    View Slide

  28. expvar (1/2)
    var (
    hitCount = expvar.NewInt("hitCount")
    pollCount = expvar.NewInt("pollCount")
    pollError = expvar.NewString("pollError")
    pollErrorCount = expvar.NewInt("pollErrorCount")
    )
    func isTagged() bool {
    pollCount.Add(1)
    r, err := http.Head(changeURL)
    if err != nil {
    log.Print(err)
    pollError.Set(err.Error())
    pollErrorCount.Add(1)
    return false
    }
    return r.StatusCode == http.StatusOK
    }
    func handler(w http.ResponseWriter, r *http.Request) {
    hitCount.Add(1)

    View Slide

  29. Demo

    View Slide

  30. Conclusion
    Simplicity revisited:
    Small
    Readable
    Consistent
    Orthogonal
    Predictable
    Robust
    Useful by default

    View Slide

  31. Stuff I didn't talk about
    Types and interfaces
    Concurrency in depth
    Packages and the build system
    Code formatting
    Testing
    Benchmarking and profiling
    Debugging
    Documentation

    View Slide

  32. Learn more about Go
    The Go web site
    golang.org (http://golang.org)
    The Go blog
    blog.golang.org (http://blog.golang.org)
    Go talks
    talks.golang.org (http://talks.golang.org)
    A Tour of Go
    tour.golang.org (http://tour.golang.org)

    View Slide

  33. Thank you
    23 April 2013
    Andrew Gerrand
    Google
    @enneff (http://twitter.com/enneff)
    [email protected] (mailto:[email protected])
    http://golang.org (http://golang.org)

    View Slide