x/talks: Program your next server in Go, ACM Applicative, NYC

Change-Id: I05600877bf0c66b6375751e605db0eb332f23224
Reviewed-on: https://go-review.googlesource.com/23601
Reviewed-by: Alan Donovan <adonovan@google.com>
diff --git a/2016/applicative.slide b/2016/applicative.slide
new file mode 100644
index 0000000..4f6a761
--- /dev/null
+++ b/2016/applicative.slide
@@ -0,0 +1,465 @@
+Program your next server in Go
+
+Sameer Ajmani
+Manager, Go team
+Google
+@Sajma
+sameer@golang.org
+
+* Video
+
+This talk was presented at the [[http://applicative.acm.org/][ACM Applicative]] conference in New York City on June 1, 2016.
+
+(We'll link the video here when it's ready.)
+
+* Outline
+
+1. What is Go, and who uses it?
+2. Comparing Go and other languages
+3. Code examples
+4. Concurrency
+5. Getting started
+
+* What is Go?
+
+"Go is an open source programming language that makes it easy to build simple, reliable, and efficient software."
+
+.link http://golang.org
+
+* History
+
+Design began in late 2007.
+
+- Robert Griesemer, Rob Pike, and Ken Thompson.
+- Ian Lance Taylor and Russ Cox.
+
+Open source since 2009 with a very active community.
+
+Language stable as of Go 1, early 2012.
+
+Go 1.7 is coming this August.
+
+* Why Go?
+
+Go is an answer to problems of scale at Google.
+
+.image ../2012/splash/datacenter.jpg 500 _
+
+* System Scale
+
+- designed to scale to 10⁶⁺ machines
+- everyday jobs run on 1000s of machines
+- jobs coordinate, interact with others in the system
+- lots going on at once
+
+Solution: great support for concurrency
+
+.image ../2012/waza/gophercomplex6.jpg
+
+* A Second Problem: Engineering Scale
+
+In 2011:
+
+- 5000+ developers across 40+ offices
+- 20+ changes per minute
+- 50% of code base changes every month
+- 50 million test cases executed per day
+- single code tree
+
+Solution: design the language for large code bases
+
+* Who uses Go at Google?
+
+Hundreds of projects. Thousands of Go programmers. Millions of lines of Go code.
+
+Public examples:
+
+- Flywheel: SPDY proxy for Chrome on mobile devices
+
+.image applicative/spdy.png 400 _
+
+* Who uses Go at Google?
+
+Hundreds of projects. Thousands of Go programmers. Millions of lines of Go code.
+
+Public examples:
+
+- Flywheel: SPDY proxy for Chrome on mobile devices
+- dl.google.com: Download server for Chrome, ChromeOS, Android SDK, Earth, etc.
+- Vitess: YouTube MySQL balancer
+- Seesaw: Linux Virtual Server (LVS) based load balancer
+- Lingo: Logs analysis in Go, migrated from Sawzall
+
+The target is networked servers, but Go is a great general-purpose language.
+
+* Who uses Go besides Google?
+
+.link http://golang.org/wiki/GoUsers
+
+Aerospike, BBC Worldwide, Bitbucket, Booking.com, Core OS, Datadog, Digital Ocean, Docker, Dropbox, Facebook, Getty Images, GitHub, GOV.UK, Heroku, IBM, Intel, InfluxDB, Iron.io, Kubernetes, Medium, MongoDB, Mozilla services, Netflix, New York Times, pool.ntp.org, Rackspace, Shutterfly, SmugMug, SoundCloud, SpaceX, Square, Stack Exchange, Thomson Reuters Eikon, Tumblr, Twitch, Twitter, Uber, VMWare ...
+
+.image ../2014/state-of-go/bus.jpg 300 _
+
+* Comparing Go and other languages
+
+* "Go: 90% Perfect, 100% of the time" -bradfitz, 2014
+
+.image ../2014/gocon-tokyo/funfast.svg
+
+# Brad Fitzpatrick, GoCon Tokyo, May 2014
+
+* Go has much in common with Java
+
+- C family (imperative, braces)
+- Statically typed
+- Garbage collected
+- Memory safe (nil references, runtime bounds checks)
+- Variables are always initialized (zero/nil/false)
+- Methods
+- Interfaces
+- Type assertions (`instanceof`)
+- Reflection
+
+* Go differs from Java in several ways
+
+Fast, efficient for computers:
+
+- Programs compile to machine code.  There's no VM.
+- Control over memory layout, fewer indirections
+
+Fun, fast for humans:
+
+- Simple, concise syntax
+- Statically linked binaries
+- Function values and lexical closures
+- Built-in strings (UTF-8)
+- Built-in generic maps and arrays/slices
+- Built-in concurrency
+
+* Go intentionally leaves out many features
+
+- No classes
+- No inheritance
+- No constructors
+- No `final`
+- No exceptions
+- No annotations
+- No user-defined generics
+
+* Why does Go leave out those features?
+
+Clarity is critical.
+
+When reading code, it should be clear what the program will do.
+
+When writing code, it should be clear how to make the program do what you want.
+
+Sometimes this means writing out a loop instead of invoking an obscure function.
+
+(Don't DRY out.)
+
+For more background on design:
+
+- [[http://commandcenter.blogspot.com/2012/06/less-is-exponentially-more.html][Less is exponentially more (Pike, 2012)]]
+- [[http://talks.golang.org/2012/splash.article][Go at Google: Language Design in the Service of Software Engineering (Pike, 2012)]]
+
+* Code examples
+
+* Go looks familiar
+
+Hello, world!
+
+.play applicative/hello/hello.go
+
+* Hello, web server
+
+.play applicative/hello/server.go
+
+Types follow names in declarations.
+Exported names are Capitalized.  Unexported names are not.
+
+* Example: Google Search frontend
+
+.play applicative/frontend.go /func main/,/func handleSearch/
+
+.link http://localhost:8080/search
+.link http://localhost:8080/search?q=golang
+.link http://localhost:8080/search?q=golang&output=json
+.link http://localhost:8080/search?q=golang&output=prettyjson
+
+* Validate the query
+
+.code applicative/frontend.go /func handleSearch/,/ENDQUERY/
+
+`FormValue` is a method on the type `*http.Request`:
+
+  package http
+  type Request struct {...}
+  func (r *Request) FormValue(key string) string {...}
+
+`query`:=`req.FormValue("q")` initializes a new variable `query` with
+the type of the expression on the right hand side, `string`.
+
+* Fetch the search results
+
+  import "golang.org/x/talks/2016/applicative/google"
+  
+.code applicative/frontend.go /Run the Google search/,/ENDSEARCH/
+
+`Search` returns two values, a slice of results and an error.
+The results are valid only if the error is nil.
+
+  type error interface {
+      Error() string // a useful human-readable error message
+  }
+
+Errors may contain additional information, accessed via type assertions.
+
+* Structure the search results
+
+.code applicative/frontend.go /Create the structured/,/ENDRESPONSE/
+
+The `response` type is defined locally within `handleSearch`.
+
+The `google.Result` type is exported from package `google`:
+
+  package google
+  
+  type Result struct { Title, URL string }
+
+The `resp` variable is initialized to a `response` value using a composite struct literal.
+
+
+* Render the search results
+
+.code applicative/frontend.go /Render the response/,/ENDRENDER/
+
+Each case writes bytes to an `io.Writer`:
+
+  type Writer interface {
+          Write(p []byte) (n int, err error)
+  }
+
+`http.ResponseWriter` implements the `io.Writer` interface.
+
+* HTML templates operate on Go values
+
+.play applicative/frontend.go /var responseTemplate/,/\)\)/
+
+.image applicative/frontend-screenshot.png _ 900
+
+* That's it for the search handler
+
+All the packages are from the standard library:
+
+  import (
+      "encoding/json"
+      "fmt"
+      "html/template"
+      "log"
+      "net/http"
+      "time"
+  )
+
+Go servers scale well: each request runs in its own _goroutine_.
+
+Let's talk about concurrency.
+
+* Communicating Sequential Processes (Hoare, 1978)
+
+Concurrent programs are structured as independent processes that
+execute sequentially and communicate by passing messages.
+
+Sequential execution is easy to understand.  Async callbacks are not.
+
+*Go*primitives:* goroutines, channels, and the `select` statement.
+
+* Goroutines
+
+Goroutines are like lightweight threads.
+
+They start with tiny stacks and resize as needed.
+
+Go programs can have hundreds of thousands of them.
+
+Start a goroutine using the `go` statement:
+
+  go f(args)
+
+The Go runtime schedules goroutines onto OS threads.
+
+Blocked goroutines don't use a thread.
+
+* Channels
+
+Channels provide communication between goroutines.
+
+  c := make(chan string)
+
+  // goroutine 1
+  c <- "hello!"
+
+  // goroutine 2
+  s := <-c
+  fmt.Println(s) // "hello!"
+
+* Select
+
+A `select` statement blocks until communication can proceed.
+
+  select {
+  case x := <-in:
+    fmt.Println("received", x)
+  case out <- v:
+    fmt.Println("sent", v)
+  }
+
+Only the selected case runs.
+
+* Example: Google Search (backend)
+
+Q: What does Google search do?
+
+A: Given a query, return a page of search results (and some ads).
+
+Q: How do we get the search results?
+
+A: Send the query to Web search, Image search, YouTube, Maps, News, etc., then mix the results.
+
+How do we implement this?
+
+* Google Search: A fake framework
+
+We can simulate a back end search with a random timeout up to 100ms.
+
+.code applicative/google/fake.go /START2/,/STOP2/
+
+* Google Search: Test the framework
+
+.play applicative/google-serial.go /func.main/,/}/ HLsearch
+
+* Google Search (serial)
+
+The `Search` function takes a query and returns a slice of `Results`.
+
+Search invokes the Web, Image, and Video searches serially, then constructs the `results` slice.
+
+.code applicative/google/serial.go /func Search/,/^}/
+.play applicative/google-serial.go /google.Search/
+
+* Google Search (parallel)
+
+Run the Web, Image, and Video searches concurrently, and wait for all results.
+
+The `func` literals are closures over `query` and `c`.
+
+.code applicative/google/parallel.go /func Search/,/^}/
+.play applicative/google-parallel.go /google.Search/
+
+* Google Search (timeout)
+
+Don't wait for slow servers.
+
+.code applicative/google/timeout.go /func Search/,/STOP/
+.play applicative/google-timeout.go /google.Search/ HLsearch
+
+* Avoid timeout
+
+Q: How do we avoid discarding results from slow servers?
+
+A: Replicate the servers.  Send requests to multiple replicas, and use the first response.
+
+.code applicative/google/first.go /func First/,/^}/
+
+* Using the First function
+
+.play applicative/first.go /func main/,/^}/
+
+* Google Search (replicated)
+
+Reduce tail latency using replicated back ends.
+
+.code applicative/google/first.go /START/,/STOP/
+.play applicative/google-replicated.go /google.Search/
+
+Go functions have simple, synchronous signatures.
+The use of concurrency is encapsulated.
+
+* What just happened?
+
+In just a few simple transformations we used Go's concurrency primitives to convert a
+
+- slow
+- sequential
+- failure-sensitive
+
+program into one that is
+
+- fast
+- concurrent
+- replicated
+- robust.
+
+No locks. No condition variables. No futures. No callbacks.
+
+* Getting started
+
+* You're interested in Go.  What next?
+
+Take the Go Tour online.
+
+.link http://tour.golang.org
+
+Then go deeper ...
+
+.link http://golang.org/wiki/Learn
+
+Still interested?
+
+Run a pilot project.
+
+* Run a pilot project
+
+Reduces the cost & risks of switching to a new technology,
+while helping your organization discover the benefits.
+
+1. Choose something small to write in Go (e.g., a microservice)
+2. Build a prototype with a friend
+
+- Find the libraries you need
+- Integrate with editors & IDEs
+- Integrate with build & test & deploy
+- Learn how to debug & profile your program
+
+3. Compare Go to what you use today 
+
+- Isolate the language change; try not to change anything else.
+
+4. *Present*results*to*the*team*
+
+* Go is designed for tooling
+
+Go tools meet you where you are.  There's no one "Go IDE".
+
+- IDE & editor integration: Eclipse, IntelliJ, VisualStudio, SublimeText, emacs, vim, ...
+- [[http://play.golang.org][play.golang.org]]: online playground
+- `gofmt`: automatic formatting
+- `goimports`: automatic updates of package imports
+- `gocode`: automatic completion
+- the `go` tool: automatic fetch & build
+- `guru`: static analysis, bug finding, code navigation
+- [[http://godoc.org][godoc.org]]: open source package index and docs
+
+* Where to Go next
+
+Take the Go Tour online.
+
+.link http://tour.golang.org
+
+Lots more material.
+
+.link http://golang.org/wiki/Learn
+
+Great community.
+
+.link http://golang.org/project
diff --git a/2016/applicative/builtin.go b/2016/applicative/builtin.go
new file mode 100644
index 0000000..800a193
--- /dev/null
+++ b/2016/applicative/builtin.go
@@ -0,0 +1,24 @@
+// +build OMIT
+
+package main
+
+import (
+	"fmt"
+	"sort"
+)
+
+func main() {
+	hellos := map[string]string{ // HLbuiltin
+		"English":  "Hello",   // HLstrings
+		"Mandarin": "您好",      // HLstrings
+		"Hindi":    "नमस्कार", // HLstrings
+	}
+	fmt.Println(hellos)               // HLfmt
+	var langs []string                // HLbuiltin
+	for lang, hello := range hellos { // HLbuiltin
+		fmt.Println(lang, ":", hello, "world!") // HLfmt
+		langs = append(langs, lang)             // HLbuiltin
+	}
+	sort.Strings(langs)                           // HLstrings
+	fmt.Printf("len(%v) = %d", langs, len(langs)) // HLfmt
+}
diff --git a/2016/applicative/channel.go b/2016/applicative/channel.go
new file mode 100644
index 0000000..d155504
--- /dev/null
+++ b/2016/applicative/channel.go
@@ -0,0 +1,32 @@
+// +build OMIT
+
+package main
+
+import (
+	"fmt"
+	"time"
+)
+
+// STARTMAIN1 OMIT
+type Ball struct{ hits int }
+
+func main() {
+	table := make(chan *Ball) // HL
+	go player("ping", table)
+
+	table <- new(Ball) // game on; toss the ball
+	time.Sleep(1 * time.Second)
+	<-table // game over; grab the ball
+}
+
+func player(name string, table chan *Ball) {
+	for i := 0; ; i++ {
+		ball := <-table // HL
+		ball.hits++
+		fmt.Println(name, i, "hit", ball.hits)
+		time.Sleep(100 * time.Millisecond)
+		table <- ball // HL
+	}
+}
+
+// STOPMAIN1 OMIT
diff --git a/2016/applicative/closure.go b/2016/applicative/closure.go
new file mode 100644
index 0000000..5958c1e
--- /dev/null
+++ b/2016/applicative/closure.go
@@ -0,0 +1,30 @@
+// +build OMIT
+
+package main
+
+import "fmt"
+
+func div(n, d int) (q, r int, err error) {
+	if d == 0 {
+		err = fmt.Errorf("%d/%d: divide by zero", n, d)
+		return
+	}
+	return n / d, n % d, nil
+}
+
+func main() {
+	var failures int
+
+	f := func(n, d int) { // HL
+		if q, r, err := div(n, d); err != nil {
+			fmt.Println(err)
+			failures++ // HL
+		} else {
+			fmt.Printf("%d/%d = %d leaving %d\n", n, d, q, r)
+		}
+	}
+
+	f(4, 3)
+	f(3, 0)
+	fmt.Println("failures:", failures)
+}
diff --git a/2016/applicative/error.go b/2016/applicative/error.go
new file mode 100644
index 0000000..92ebe21
--- /dev/null
+++ b/2016/applicative/error.go
@@ -0,0 +1,23 @@
+// +build OMIT
+
+package main
+
+import (
+	"errors"
+	"fmt"
+)
+
+// div divides n by d and returns the quotient and remainder.
+// It returns an error if d is zero.
+func div(n, d int) (q, r int, err error) { // HL
+	if d == 0 {
+		err = errors.New("divide by zero") // HL
+		return
+	}
+	return n / d, n % d, nil // HL
+}
+
+func main() {
+	fmt.Println(div(4, 3))
+	fmt.Println(div(3, 0))
+}
diff --git a/2016/applicative/first.go b/2016/applicative/first.go
new file mode 100644
index 0000000..6f1d186
--- /dev/null
+++ b/2016/applicative/first.go
@@ -0,0 +1,29 @@
+// +build OMIT
+
+package main
+
+import (
+	"fmt"
+	"math/rand"
+	"time"
+
+	"golang.org/x/talks/2016/applicative/google"
+)
+
+func init() {
+	rand.Seed(time.Now().UnixNano())
+}
+
+// START2 OMIT
+func main() {
+	start := time.Now()
+	search := google.First( // HL
+		google.FakeSearch("replica 1", "I'm #1!", ""),  // HL
+		google.FakeSearch("replica 2", "#2 wins!", "")) // HL
+	result := search("golang")
+	elapsed := time.Since(start)
+	fmt.Println(result)
+	fmt.Println(elapsed)
+}
+
+// STOP2 OMIT
diff --git a/2016/applicative/frontend-screenshot.png b/2016/applicative/frontend-screenshot.png
new file mode 100644
index 0000000..561c944
--- /dev/null
+++ b/2016/applicative/frontend-screenshot.png
Binary files differ
diff --git a/2016/applicative/frontend.go b/2016/applicative/frontend.go
new file mode 100644
index 0000000..5fc4685
--- /dev/null
+++ b/2016/applicative/frontend.go
@@ -0,0 +1,94 @@
+// +build OMIT
+
+// The server program issues Google search requests. It serves on port 8080.
+//
+// The /search endpoint accepts these query params:
+//   q=the Google search query
+//
+// For example, http://localhost:8080/search?q=golang serves the first
+// few Google search results for "golang".
+package main
+
+import (
+	"encoding/json"
+	"fmt"
+	"html/template"
+	"log"
+	"net/http"
+	"time"
+
+	"golang.org/x/talks/2016/applicative/google"
+)
+
+func main() {
+	http.HandleFunc("/search", handleSearch) // HL
+	fmt.Println("serving on http://localhost:8080/search")
+	log.Fatal(http.ListenAndServe("localhost:8080", nil))
+}
+
+// handleSearch handles URLs like "/search?q=golang" by running a
+// Google search for "golang" and writing the results as HTML to w.
+// The query parameter "output" selects alternate output formats:
+// "json" for JSON, "prettyjson" for human-readable JSON.
+func handleSearch(w http.ResponseWriter, req *http.Request) { // HL
+	log.Println("serving", req.URL)
+
+	// Check the search query.
+	query := req.FormValue("q") // HL
+	if query == "" {
+		http.Error(w, `missing "q" URL parameter`, http.StatusBadRequest)
+		return
+	}
+	// ENDQUERY OMIT
+
+	// Run the Google search.
+	start := time.Now()
+	results, err := google.Search(query) // HL
+	elapsed := time.Since(start)
+	if err != nil {
+		http.Error(w, err.Error(), http.StatusInternalServerError)
+		return
+	}
+	// ENDSEARCH OMIT
+
+	// Create the structured response.
+	type response struct {
+		Results []google.Result
+		Elapsed time.Duration
+	}
+	resp := response{results, elapsed} // HL
+	// ENDRESPONSE OMIT
+
+	// Render the response.
+	switch req.FormValue("output") {
+	case "json":
+		err = json.NewEncoder(w).Encode(resp) // HL
+	case "prettyjson":
+		var b []byte
+		b, err = json.MarshalIndent(resp, "", "  ") // HL
+		if err == nil {
+			_, err = w.Write(b)
+		}
+	default: // HTML
+		err = responseTemplate.Execute(w, resp) // HL
+	}
+	// ENDRENDER OMIT
+	if err != nil {
+		log.Print(err)
+		return
+	}
+}
+
+var responseTemplate = template.Must(template.New("results").Parse(`
+<html>
+<head/>
+<body>
+  <ol>
+  {{range .Results}}
+    <li>{{.Title}} - <a href="{{.URL}}">{{.URL}}</a></li>
+  {{end}}
+  </ol>
+  <p>{{len .Results}} results in {{.Elapsed}}</p>
+</body>
+</html>
+`))
diff --git a/2016/applicative/func.go b/2016/applicative/func.go
new file mode 100644
index 0000000..c273fa3
--- /dev/null
+++ b/2016/applicative/func.go
@@ -0,0 +1,15 @@
+// +build OMIT
+
+package main
+
+import "fmt"
+
+// div divides n by d and returns the quotient and remainder.
+func div(n, d int) (q, r int) { // HL
+	return n / d, n % d
+}
+
+func main() {
+	quot, rem := div(4, 3)
+	fmt.Println(quot, rem)
+}
diff --git a/2016/applicative/gofmt-after.go b/2016/applicative/gofmt-after.go
new file mode 100644
index 0000000..4d41a57
--- /dev/null
+++ b/2016/applicative/gofmt-after.go
@@ -0,0 +1,11 @@
+// +build OMIT
+
+package main
+
+import "fmt"
+
+func main() {
+	for i := 0; i < 3; i++ {
+		fmt.Println("Hello, world")
+	}
+}
diff --git a/2016/applicative/goimports-after.go b/2016/applicative/goimports-after.go
new file mode 100644
index 0000000..398621d
--- /dev/null
+++ b/2016/applicative/goimports-after.go
@@ -0,0 +1,13 @@
+// +build OMIT
+
+package main
+
+import (
+	"fmt"
+
+	"golang.org/x/tools/present"
+)
+
+func main() {
+	fmt.Println(present.Image{})
+}
diff --git a/2016/applicative/goimports-before.go b/2016/applicative/goimports-before.go
new file mode 100644
index 0000000..ee9303a
--- /dev/null
+++ b/2016/applicative/goimports-before.go
@@ -0,0 +1,7 @@
+// +build OMIT
+
+package main
+
+func main() {
+	fmt.Println(present.Image{})
+}
diff --git a/2016/applicative/google-parallel.go b/2016/applicative/google-parallel.go
new file mode 100644
index 0000000..77f8457
--- /dev/null
+++ b/2016/applicative/google-parallel.go
@@ -0,0 +1,21 @@
+package main
+
+import (
+	"fmt"
+	"math/rand"
+	"time"
+
+	"golang.org/x/talks/2016/applicative/google"
+)
+
+func init() {
+	rand.Seed(time.Now().UnixNano())
+}
+
+func main() {
+	start := time.Now()
+	results, err := google.SearchParallel("golang") // HLsearch
+	elapsed := time.Since(start)
+	fmt.Println(results)
+	fmt.Println(elapsed, err)
+}
diff --git a/2016/applicative/google-replicated.go b/2016/applicative/google-replicated.go
new file mode 100644
index 0000000..1888857
--- /dev/null
+++ b/2016/applicative/google-replicated.go
@@ -0,0 +1,21 @@
+package main
+
+import (
+	"fmt"
+	"math/rand"
+	"time"
+
+	"golang.org/x/talks/2016/applicative/google"
+)
+
+func init() {
+	rand.Seed(time.Now().UnixNano())
+}
+
+func main() {
+	start := time.Now()
+	results, err := google.SearchReplicated("golang", 80*time.Millisecond) // HLsearch
+	elapsed := time.Since(start)
+	fmt.Println(results)
+	fmt.Println(elapsed, err)
+}
diff --git a/2016/applicative/google-serial.go b/2016/applicative/google-serial.go
new file mode 100644
index 0000000..250e9c7
--- /dev/null
+++ b/2016/applicative/google-serial.go
@@ -0,0 +1,21 @@
+package main
+
+import (
+	"fmt"
+	"math/rand"
+	"time"
+
+	"golang.org/x/talks/2016/applicative/google"
+)
+
+func init() {
+	rand.Seed(time.Now().UnixNano())
+}
+
+func main() {
+	start := time.Now()
+	results, err := google.Search("golang") // HLsearch
+	elapsed := time.Since(start)
+	fmt.Println(results)
+	fmt.Println(elapsed, err)
+}
diff --git a/2016/applicative/google-timeout.go b/2016/applicative/google-timeout.go
new file mode 100644
index 0000000..0233f15
--- /dev/null
+++ b/2016/applicative/google-timeout.go
@@ -0,0 +1,21 @@
+package main
+
+import (
+	"fmt"
+	"math/rand"
+	"time"
+
+	"golang.org/x/talks/2016/applicative/google"
+)
+
+func init() {
+	rand.Seed(time.Now().UnixNano())
+}
+
+func main() {
+	start := time.Now()
+	results, err := google.SearchTimeout("golang", 80*time.Millisecond) // HLsearch
+	elapsed := time.Since(start)
+	fmt.Println(results)
+	fmt.Println(elapsed, err)
+}
diff --git a/2016/applicative/google/fake.go b/2016/applicative/google/fake.go
new file mode 100644
index 0000000..75f1294
--- /dev/null
+++ b/2016/applicative/google/fake.go
@@ -0,0 +1,42 @@
+package google
+
+import (
+	"fmt"
+	"math/rand"
+	"time"
+)
+
+// START2 OMIT
+var (
+	Web   = FakeSearch("web", "The Go Programming Language", "http://golang.org")
+	Image = FakeSearch("image", "The Go gopher", "https://blog.golang.org/gopher/gopher.png")
+	Video = FakeSearch("video", "Concurrency is not Parallelism", "https://www.youtube.com/watch?v=cN_DpYBzKso")
+)
+
+type SearchFunc func(query string) Result // HL
+
+func FakeSearch(kind, title, url string) SearchFunc {
+	return func(query string) Result {
+		time.Sleep(time.Duration(rand.Intn(100)) * time.Millisecond) // HL
+		return Result{
+			Title: fmt.Sprintf("%s(%q): %s", kind, query, title),
+			URL:   url,
+		}
+	}
+}
+
+// STOP2 OMIT
+
+// String returns the result's title, followed by a newline.
+func (r Result) String() string { return r.Title + "\n" }
+
+var (
+	Web1   = FakeSearch("web1", "The Go Programming Language", "http://golang.org")
+	Web2   = FakeSearch("web2", "The Go Programming Language", "http://golang.org")
+	Image1 = FakeSearch("image1", "The Go gopher", "https://blog.golang.org/gopher/gopher.png")
+	Image2 = FakeSearch("image2", "The Go gopher", "https://blog.golang.org/gopher/gopher.png")
+	Video1 = FakeSearch("video1", "Concurrency is not Parallelism",
+		"https://www.youtube.com/watch?v=cN_DpYBzKso")
+	Video2 = FakeSearch("video2", "Concurrency is not Parallelism",
+		"https://www.youtube.com/watch?v=cN_DpYBzKso")
+)
diff --git a/2016/applicative/google/first.go b/2016/applicative/google/first.go
new file mode 100644
index 0000000..796083c
--- /dev/null
+++ b/2016/applicative/google/first.go
@@ -0,0 +1,46 @@
+package google
+
+import (
+	"errors"
+	"time"
+)
+
+func First(replicas ...SearchFunc) SearchFunc { // HL
+	return func(query string) Result {
+		c := make(chan Result, len(replicas))
+		searchReplica := func(i int) {
+			c <- replicas[i](query)
+		}
+		for i := range replicas {
+			go searchReplica(i) // HL
+		}
+		return <-c
+	}
+}
+
+// START OMIT
+var (
+	replicatedWeb   = First(Web1, Web2)     // HL
+	replicatedImage = First(Image1, Image2) // HL
+	replicatedVideo = First(Video1, Video2) // HL
+)
+
+func SearchReplicated(query string, timeout time.Duration) ([]Result, error) {
+	timer := time.After(timeout)
+	c := make(chan Result, 3)
+	go func() { c <- replicatedWeb(query) }()   // HL
+	go func() { c <- replicatedImage(query) }() // HL
+	go func() { c <- replicatedVideo(query) }() // HL
+	// STOP OMIT
+
+	var results []Result
+	for i := 0; i < 3; i++ {
+		select {
+		case result := <-c:
+			results = append(results, result)
+		case <-timer:
+			return results, errors.New("timed out")
+		}
+	}
+	return results, nil
+}
diff --git a/2016/applicative/google/parallel.go b/2016/applicative/google/parallel.go
new file mode 100644
index 0000000..67434ce
--- /dev/null
+++ b/2016/applicative/google/parallel.go
@@ -0,0 +1,10 @@
+package google
+
+func SearchParallel(query string) ([]Result, error) {
+	c := make(chan Result)
+	go func() { c <- Web(query) }()
+	go func() { c <- Image(query) }()
+	go func() { c <- Video(query) }()
+
+	return []Result{<-c, <-c, <-c}, nil
+}
diff --git a/2016/applicative/google/serial.go b/2016/applicative/google/serial.go
new file mode 100644
index 0000000..1a723aa
--- /dev/null
+++ b/2016/applicative/google/serial.go
@@ -0,0 +1,17 @@
+package google
+
+// START1 OMIT
+type Result struct {
+	Title, URL string
+}
+
+func Search(query string) ([]Result, error) {
+	results := []Result{
+		Web(query),
+		Image(query),
+		Video(query),
+	}
+	return results, nil
+}
+
+// STOP1 OMIT
diff --git a/2016/applicative/google/timeout.go b/2016/applicative/google/timeout.go
new file mode 100644
index 0000000..eef1503
--- /dev/null
+++ b/2016/applicative/google/timeout.go
@@ -0,0 +1,26 @@
+package google
+
+import (
+	"errors"
+	"time"
+)
+
+func SearchTimeout(query string, timeout time.Duration) ([]Result, error) { // HL
+	timer := time.After(timeout) // HL
+	c := make(chan Result, 3)
+	go func() { c <- Web(query) }()
+	go func() { c <- Image(query) }()
+	go func() { c <- Video(query) }()
+
+	var results []Result
+	for i := 0; i < 3; i++ {
+		select { // HL
+		case result := <-c: // HL
+			results = append(results, result)
+		case <-timer: // HL
+			return results, errors.New("timed out")
+		}
+	}
+	return results, nil
+	// STOP OMIT
+}
diff --git a/2016/applicative/google1.jpg b/2016/applicative/google1.jpg
new file mode 100644
index 0000000..e52e5f0
--- /dev/null
+++ b/2016/applicative/google1.jpg
Binary files differ
diff --git a/2016/applicative/google14.jpg b/2016/applicative/google14.jpg
new file mode 100644
index 0000000..f83bb9b
--- /dev/null
+++ b/2016/applicative/google14.jpg
Binary files differ
diff --git a/2016/applicative/google17.jpg b/2016/applicative/google17.jpg
new file mode 100644
index 0000000..909b579
--- /dev/null
+++ b/2016/applicative/google17.jpg
Binary files differ
diff --git a/2016/applicative/google20.jpg b/2016/applicative/google20.jpg
new file mode 100644
index 0000000..1ba9213
--- /dev/null
+++ b/2016/applicative/google20.jpg
Binary files differ
diff --git a/2016/applicative/goroutine.go b/2016/applicative/goroutine.go
new file mode 100644
index 0000000..9e9dab7
--- /dev/null
+++ b/2016/applicative/goroutine.go
@@ -0,0 +1,26 @@
+// +build OMIT
+
+package main
+
+import (
+	"fmt"
+	"time"
+)
+
+// STARTMAIN1 OMIT
+type Ball struct{ hits int }
+
+func main() {
+	go player("ping", new(Ball)) // HL
+	time.Sleep(1 * time.Second)
+}
+
+func player(name string, ball *Ball) {
+	for i := 0; ; i++ {
+		ball.hits++
+		fmt.Println(name, i, "hit", ball.hits)
+		time.Sleep(100 * time.Millisecond)
+	}
+}
+
+// STOPMAIN1 OMIT
diff --git a/2016/applicative/hello/Main.class b/2016/applicative/hello/Main.class
new file mode 100644
index 0000000..cccf827
--- /dev/null
+++ b/2016/applicative/hello/Main.class
Binary files differ
diff --git a/2016/applicative/hello/Main.java b/2016/applicative/hello/Main.java
new file mode 100644
index 0000000..73a4d22
--- /dev/null
+++ b/2016/applicative/hello/Main.java
@@ -0,0 +1,5 @@
+public class Main {
+    public static void main(String[] args) {
+        System.out.println("Hello, world!");
+    }
+}
diff --git a/2016/applicative/hello/hello.go b/2016/applicative/hello/hello.go
new file mode 100644
index 0000000..1725b6e
--- /dev/null
+++ b/2016/applicative/hello/hello.go
@@ -0,0 +1,9 @@
+// +build OMIT
+
+package main
+
+import "fmt"
+
+func main() {
+	fmt.Println("Hello, 世界!")
+}
diff --git a/2016/applicative/hello/server.go b/2016/applicative/hello/server.go
new file mode 100644
index 0000000..a9da549
--- /dev/null
+++ b/2016/applicative/hello/server.go
@@ -0,0 +1,20 @@
+// +build OMIT
+
+package main
+
+import (
+	"fmt"
+	"log"
+	"net/http"
+)
+
+func main() {
+	http.HandleFunc("/hello", handleHello) // HL
+	fmt.Println("serving on http://localhost:7777/hello")
+	log.Fatal(http.ListenAndServe("localhost:7777", nil))
+}
+
+func handleHello(w http.ResponseWriter, req *http.Request) {
+	log.Println("serving", req.URL)
+	fmt.Fprintln(w, "Hello, 世界!") // HL
+}
diff --git a/2016/applicative/interface.go b/2016/applicative/interface.go
new file mode 100644
index 0000000..efef67e
--- /dev/null
+++ b/2016/applicative/interface.go
@@ -0,0 +1,33 @@
+// +build OMIT
+
+package main
+
+import (
+	"bytes"
+	"fmt"
+)
+
+type Point struct {
+	X, Y int
+}
+
+type Rectangle struct {
+	Min, Max Point
+}
+
+func (r Rectangle) String() string {
+	var buf bytes.Buffer
+	for h := 0; h < r.Max.Y-r.Min.Y; h++ {
+		for w := 0; w < r.Max.X-r.Min.X; w++ {
+			buf.WriteString("#")
+		}
+		buf.WriteString("\n")
+	}
+	return buf.String()
+}
+
+func main() {
+	fmt.Println(Rectangle{Max: Point{20, 5}})
+}
+
+// EOF OMIT
diff --git a/2016/applicative/method.go b/2016/applicative/method.go
new file mode 100644
index 0000000..230c47f
--- /dev/null
+++ b/2016/applicative/method.go
@@ -0,0 +1,35 @@
+// +build OMIT
+
+package main
+
+import (
+	"bytes"
+	"fmt"
+)
+
+type Point struct {
+	X, Y int
+}
+
+type Rectangle struct {
+	Min, Max Point
+}
+
+func (r Rectangle) String() string { // HL
+	var buf bytes.Buffer
+	for h := 0; h < r.Max.Y-r.Min.Y; h++ {
+		for w := 0; w < r.Max.X-r.Min.X; w++ {
+			buf.WriteString("#")
+		}
+		buf.WriteString("\n")
+	}
+	return buf.String()
+}
+
+func main() {
+	r := Rectangle{Max: Point{20, 5}}
+	s := r.String() // HL
+	fmt.Println(s)
+}
+
+// EOF OMIT
diff --git a/2016/applicative/panic.go b/2016/applicative/panic.go
new file mode 100644
index 0000000..6ae78e8
--- /dev/null
+++ b/2016/applicative/panic.go
@@ -0,0 +1,15 @@
+// +build OMIT
+
+package main
+
+import "fmt"
+
+// div divides n by d and returns the quotient and remainder.
+func div(n, d int) (q, r int) {
+	return n / d, n % d
+}
+
+func main() {
+	quot, rem := div(4, 0) // HL
+	fmt.Println(quot, rem)
+}
diff --git a/2016/applicative/pingpipe.go b/2016/applicative/pingpipe.go
new file mode 100644
index 0000000..df3c563
--- /dev/null
+++ b/2016/applicative/pingpipe.go
@@ -0,0 +1,38 @@
+// +build OMIT
+
+package main
+
+import (
+	"fmt"
+	"time"
+)
+
+// STARTMAIN1 OMIT
+type Ball struct{ hits int }
+
+func main() {
+	in, out := make(chan *Ball), make(chan *Ball) // HL
+	go player("ping", in, out)
+	go player("pong", in, out)
+
+	go func() {
+		for i := 0; i < 8; i++ {
+			in <- new(Ball) // feed the pipeline // HL
+		}
+	}()
+	for i := 0; i < 8; i++ {
+		<-out // drain the pipeline // HL
+	}
+}
+
+func player(name string, in <-chan *Ball, out chan<- *Ball) { // HL
+	for i := 0; ; i++ {
+		ball := <-in // HL
+		ball.hits++
+		fmt.Println(name, i, "hit", ball.hits)
+		time.Sleep(100 * time.Millisecond)
+		out <- ball // HL
+	}
+}
+
+// STOPMAIN1 OMIT
diff --git a/2016/applicative/pingpong.go b/2016/applicative/pingpong.go
new file mode 100644
index 0000000..4ee3f6b
--- /dev/null
+++ b/2016/applicative/pingpong.go
@@ -0,0 +1,33 @@
+// +build OMIT
+
+package main
+
+import (
+	"fmt"
+	"time"
+)
+
+// STARTMAIN1 OMIT
+type Ball struct{ hits int }
+
+func main() {
+	table := make(chan *Ball)
+	go player("ping", table)
+	go player("pong", table) // HL
+
+	table <- new(Ball) // game on; toss the ball
+	time.Sleep(1 * time.Second)
+	<-table // game over; grab the ball
+}
+
+func player(name string, table chan *Ball) {
+	for i := 0; ; i++ {
+		ball := <-table
+		ball.hits++
+		fmt.Println(name, i, "hit", ball.hits)
+		time.Sleep(100 * time.Millisecond)
+		table <- ball
+	}
+}
+
+// STOPMAIN1 OMIT
diff --git a/2016/applicative/pingselect.go b/2016/applicative/pingselect.go
new file mode 100644
index 0000000..b274e41
--- /dev/null
+++ b/2016/applicative/pingselect.go
@@ -0,0 +1,37 @@
+// +build OMIT
+
+package main
+
+import (
+	"fmt"
+	"time"
+)
+
+// STARTMAIN1 OMIT
+type Ball struct{ hits int }
+
+func main() {
+	in, out := make(chan *Ball), make(chan *Ball)
+	go player("ping", in, out)
+	go player("pong", in, out)
+
+	for i := 0; i < 8; {
+		select { // HL
+		case in <- new(Ball): // feed the pipeline // HL
+		case <-out: // drain the pipeline // HL
+			i++ // HL
+		} // HL
+	}
+}
+
+func player(name string, in <-chan *Ball, out chan<- *Ball) {
+	for i := 0; ; i++ {
+		ball := <-in
+		ball.hits++
+		fmt.Println(name, i, "hit", ball.hits)
+		time.Sleep(100 * time.Millisecond)
+		out <- ball
+	}
+}
+
+// STOPMAIN1 OMIT
diff --git a/2016/applicative/player.go b/2016/applicative/player.go
new file mode 100644
index 0000000..e66e567
--- /dev/null
+++ b/2016/applicative/player.go
@@ -0,0 +1,25 @@
+// +build OMIT
+
+package main
+
+import (
+	"fmt"
+	"time"
+)
+
+// STARTMAIN1 OMIT
+type Ball struct{ hits int }
+
+func main() {
+	player("ping", new(Ball))
+}
+
+func player(name string, ball *Ball) {
+	for i := 0; ; i++ {
+		ball.hits++
+		fmt.Println(name, i, "hit", ball.hits)
+		time.Sleep(100 * time.Millisecond)
+	}
+}
+
+// STOPMAIN1 OMIT
diff --git a/2016/applicative/pointer.go b/2016/applicative/pointer.go
new file mode 100644
index 0000000..05a69af
--- /dev/null
+++ b/2016/applicative/pointer.go
@@ -0,0 +1,36 @@
+// +build OMIT
+
+package main
+
+import "fmt"
+
+// START TYPES OMIT
+type Point struct {
+	X, Y int
+}
+
+type Rectangle struct {
+	Min, Max Point
+}
+
+// END TYPES OMIT
+
+func main() {
+	var r0 Rectangle
+
+	r1 := r0 // struct copy
+
+	r1.Min.X, r1.Min.Y = -1, -1
+	r1.Max = Point{X: 2}
+
+	fmt.Printf("r0 is %+v\n", r0)
+	fmt.Printf("r1 is %v\n", r1)
+
+	y := &r1.Max.Y // y is a *int // HL
+	*y = 5         // HL
+	fmt.Println(y, "points to", *y)
+
+	min := &r1.Min // min is a *Point // HL
+	min.X = 7      // HL
+	fmt.Printf("r1 is %v\n", r1)
+}
diff --git a/2016/applicative/safe.go b/2016/applicative/safe.go
new file mode 100644
index 0000000..68e1136
--- /dev/null
+++ b/2016/applicative/safe.go
@@ -0,0 +1,20 @@
+// +build OMIT
+
+package main
+
+import "fmt"
+
+func newInt(v int) *int {
+	var n = v
+	return &n // HL
+}
+
+func inc(p *int) {
+	*p++ // try removing * // HL
+}
+
+func main() {
+	p := newInt(3)
+	inc(p)
+	fmt.Println(p, "points to", *p)
+}
diff --git a/2016/applicative/spdy.png b/2016/applicative/spdy.png
new file mode 100644
index 0000000..bbc0650
--- /dev/null
+++ b/2016/applicative/spdy.png
Binary files differ
diff --git a/2016/applicative/struct.go b/2016/applicative/struct.go
new file mode 100644
index 0000000..da025c2
--- /dev/null
+++ b/2016/applicative/struct.go
@@ -0,0 +1,36 @@
+// +build OMIT
+
+package main
+
+import "fmt"
+
+// START SLICES OMIT
+var arr [8]Rectangle
+
+var (
+	rects  = arr[2:4]
+	rects2 = []Rectangle{rects[0], rects[1]}
+)
+
+// START TYPES OMIT
+type Point struct {
+	X, Y int
+}
+
+type Rectangle struct {
+	Min, Max Point
+}
+
+// END TYPES OMIT
+
+func main() {
+	var r0 Rectangle
+
+	r1 := r0 // struct copy
+
+	r1.Min.X, r1.Min.Y = -1, -1
+	r1.Max = Point{X: 2}
+
+	fmt.Printf("r0 is %+v\n", r0)
+	fmt.Printf("r1 is %v\n", r1)
+}