go.talks: Best Practices in Go

R=adg, campoy
CC=golang-dev
https://golang.org/cl/11407043
diff --git a/2013/bestpractices.slide b/2013/bestpractices.slide
new file mode 100644
index 0000000..3ee24bc
--- /dev/null
+++ b/2013/bestpractices.slide
@@ -0,0 +1,270 @@
+Twelve Go Best Practices
+
+Francesc Campoy Flores
+Gopher at Google
+@campoy83
+http://campoy.cat/+
+
+http://golang.org
+
+* Best practices
+
+From Wikipedia:
+
+	"A best practice is a method or technique that has consistently shown results superior
+	to those achieved with other means"
+
+Techniques to write Go code that is
+
+- simple,
+- readable,
+- maintainable.
+
+.image http://golang.org/doc/gopher/gopherbw.png 200 200
+
+* Some code
+
+.code bestpractices/shortercode1.go /GOPHER/,/DUMP/
+
+.code bestpractices/shortercode1.go /DUMP/,/MAIN/
+
+* Avoid nesting by handling errors first
+
+.code bestpractices/shortercode2.go /DUMP/,/MAIN/
+
+Less nesting means less cognitive load on the reader
+
+* Avoid repetition when possible
+
+Deploy one-off utility types for simpler code
+
+.code bestpractices/shortercode3.go /BINWRITER/,/DUMP/
+
+.code bestpractices/shortercode3.go /DUMP/,/MAIN/
+
+* Type switch to handle special cases
+
+.code bestpractices/shortercode4.go /WRITE/,/DUMP/
+
+.code bestpractices/shortercode4.go /DUMP/,/MAIN/
+
+* Type switch with short variable declaration
+
+.code bestpractices/shortercode5.go /WRITE/,/DUMP/
+
+* Function adapters
+
+.code bestpractices/httphandler.go /HANDLER1/,/HANDLER2/
+
+* Function adapters
+
+.code bestpractices/httphandler.go /HANDLER2/,/END/
+
+* Organizing your code
+
+* Important code goes first
+
+License information, build tags, package documentation.
+
+Import statements, related groups separated by blank lines.
+
+	import (
+		"fmt"
+		"io"
+		"log"
+
+		"code.google.com/p/go.net/websocket"
+	)
+
+The rest of the code starting with the most significant types, and ending
+with helper function and types.
+
+* Document your code
+
+Package name, with the associated documentation before.
+
+	// Package playground registers an HTTP handler at "/compile" that
+	// proxies requests to the golang.org playground service.
+	package playground
+
+Exported identifiers appear in `godoc`, they should be documented correctly.
+
+	// Author represents the person who wrote and/or is presenting the document.
+	type Author struct {
+		Elem []Elem
+	}
+
+	// TextElem returns the first text elements of the author details.
+	// This is used to display the author' name, job title, and company
+	// without the contact details.
+	func (p *Author) TextElem() (elems []Elem) {
+
+[[http://godoc.org/code.google.com/p/go.talks/pkg/present#Author][Generated documentation]]
+
+[[http://blog.golang.org/godoc-documenting-go-code][Gocode: documenting Go code]]
+
+* Shorter is better
+
+or at least _longer_is_not_always_better_.
+
+Try to find the *shortest*name*that*is*self*explanatory*.
+
+- Prefer `MarshalIndent` to `MarshalWithIndentation`.
+
+Don't forget that the package name will appear before the identifier you chose.
+
+- In package `encoding/json` we find the type `Encoder`, not `JSONEncoder`.
+
+- It is referred as `json.Encoder`.
+
+* Packages with multiple files
+
+Should you split a package into multiple files?
+
+- Avoid very long files
+
+The `net/http` package from the standard library contains 15734 lines in 47 files.
+
+- Separate code and tests
+
+`net/http/cookie.go` and `net/http/cookie_test.go` are both part of the `http`
+package.
+
+Test code is compiled *only* at test time.
+
+- Separated package documentation
+
+When we have more than one file in a package, it's convention to create a `doc.go`
+containing the package documentation.
+
+* Make your packages "go get"-able
+
+Some packages are potentially reusable, some others are not.
+
+A package defining some network protocol might be reused while one defining
+an executable command may not.
+
+.image bestpractices/cmd.png
+
+[[https://github.com/bradfitz/camlistore]]
+
+* APIs
+
+* Ask for what you need
+
+Let's use the Gopher type from before
+
+.code bestpractices/shortercode1.go /GOPHER/,/DUMP/
+
+We could define this method
+
+.code bestpractices/shortercode1.go /DumpToFile/,/DumpToFile/
+
+But using a concrete type makes this code difficult to test, so we use an interface.
+
+.code bestpractices/shortercode1.go /DumpToReadWriter/,/DumpToReadWriter/
+
+And, since we're using an interface, we should ask only for the methods we need.
+
+.code bestpractices/shortercode1.go /DumpToWriter/,/DumpToWriter/
+
+* Keep independent packages independent
+
+.code bestpractices/funcdraw/cmd/funcdraw.go /IMPORT/,/ENDIMPORT/
+
+.code bestpractices/funcdraw/cmd/funcdraw.go /START/,/END/
+
+* Parsing
+
+.code bestpractices/funcdraw/parser/parser.go /START/,/END/
+
+* Drawing
+
+.code bestpractices/funcdraw/drawer/dependent.go /START/,/END/
+
+Avoid dependency by using an interface.
+
+.code bestpractices/funcdraw/drawer/drawer.go /START/,/END/
+
+* Testing
+
+Using an interface instead of a concrete type makes testing easier.
+
+.code bestpractices/funcdraw/drawer/drawer_test.go ,/END/
+
+* Avoid concurrency in your API
+
+.play bestpractices/concurrency1.go /START/,/END/
+
+What if we want to use it sequentially?
+
+* Avoid concurrency in your API
+
+.play bestpractices/concurrency2.go /START/,/END/
+
+Expose synchronous APIs, calling them concurrently is easy.
+
+* Best practices for concurrency
+
+* Use goroutines to manage state
+
+Use a chan or a struct with a chan to communicate with a goroutine
+
+.code bestpractices/server.go /START/,/STOP/
+
+* Use goroutines to manage state (continued)
+
+.play bestpractices/server.go /STOP/,
+
+* Avoid goroutine leaks with buffered chans
+
+.code bestpractices/bufchan.go /SEND/,/BROADCAST/
+
+.code bestpractices/bufchan.go /MAIN/,
+
+* Avoid goroutine leaks with buffered chans (continued)
+
+.play bestpractices/bufchan.go /BROADCAST/,/MAIN/
+
+- the goroutine is blocked on the chan write
+- the goroutine holds a reference to the chan
+- the chan will never be garbage collected
+
+* Avoid goroutines leaks with buffered chans (continued)
+
+.play bestpractices/bufchanfix.go /BROADCAST/,/MAIN/
+
+- what if we can't predict the capacity of the channel?
+
+* Avoid goroutines leaks with quit chan
+
+.play bestpractices/quitchan.go /BROADCAST/,/MAIN/
+
+* Twelve best practices
+
+1. Avoid nesting by handling errors first
+2. Avoid repetition when possible
+3. Important code goes first
+4. Document your code
+5. Shorter is better
+6. Packages with multiple files 
+7. Make your packages "go get"-able
+8. Ask for what you need
+9. Keep independent packages independent
+10. Avoid concurrency in your API
+11. Use goroutines to manage state
+12. Avoid goroutine leaks
+
+* Some links
+
+Resources
+
+- Go homepage [[http://golang.org]]
+- Go interactive tour [[http://tour.golang.org]]
+
+Other talks
+
+- Lexical scanning with Go [[http://www.youtube.com/watch?v=HxaD_trXwRE][video]]
+- Concurrency is not parallelism [[http://vimeo.com/49718712][video]]
+- Go concurrency patterns [[http://www.youtube.com/watch?v=f6kdp27TYZs][video]]
+- Advanced Go concurrency patterns [[http://www.youtube.com/watch?v=QDDwwePbDtw][video]]
diff --git a/2013/bestpractices/bufchan.go b/2013/bestpractices/bufchan.go
new file mode 100644
index 0000000..7f51777
--- /dev/null
+++ b/2013/bestpractices/bufchan.go
@@ -0,0 +1,50 @@
+package main
+
+import (
+	"fmt"
+	"net"
+	"time"
+)
+
+// SEND OMIT
+func sendMsg(msg, addr string) error {
+	conn, err := net.Dial("tcp", addr)
+	if err != nil {
+		return err
+	}
+	defer conn.Close()
+	_, err = fmt.Fprint(conn, msg)
+	return err
+}
+
+// BROADCAST OMIT
+func broadcastMsg(msg string, addrs []string) error {
+	errc := make(chan error)
+	for _, addr := range addrs {
+		go func(addr string) {
+			errc <- sendMsg(msg, addr)
+			fmt.Println("done")
+		}(addr)
+	}
+
+	for _ = range addrs {
+		if err := <-errc; err != nil {
+			return err
+		}
+	}
+	return nil
+}
+
+// MAIN OMIT
+func main() {
+	addr := []string{"localhost:8080", "http://google.com"}
+	err := broadcastMsg("hi", addr) // HL
+
+	time.Sleep(time.Second)
+
+	if err != nil {
+		fmt.Println(err)
+		return
+	}
+	fmt.Println("everything went fine")
+}
diff --git a/2013/bestpractices/bufchanfix.go b/2013/bestpractices/bufchanfix.go
new file mode 100644
index 0000000..560abbd
--- /dev/null
+++ b/2013/bestpractices/bufchanfix.go
@@ -0,0 +1,50 @@
+package main
+
+import (
+	"fmt"
+	"net"
+	"time"
+)
+
+// SEND OMIT
+func sendMsg(msg, addr string) error {
+	conn, err := net.Dial("tcp", addr)
+	if err != nil {
+		return err
+	}
+	defer conn.Close()
+	_, err = fmt.Fprint(conn, msg)
+	return err
+}
+
+// BROADCAST OMIT
+func broadcastMsg(msg string, addrs []string) error {
+	errc := make(chan error, len(addrs)) // HL
+	for _, addr := range addrs {
+		go func(addr string) {
+			errc <- sendMsg(msg, addr)
+			fmt.Println("done")
+		}(addr)
+	}
+
+	for _ = range addrs {
+		if err := <-errc; err != nil {
+			return err
+		}
+	}
+	return nil
+}
+
+// MAIN OMIT
+func main() {
+	addr := []string{"localhost:8080", "http://google.com"}
+	err := broadcastMsg("hi", addr)
+
+	time.Sleep(time.Second)
+
+	if err != nil {
+		fmt.Println(err)
+		return
+	}
+	fmt.Println("everything went fine")
+}
diff --git a/2013/bestpractices/cmd.png b/2013/bestpractices/cmd.png
new file mode 100644
index 0000000..17e70a1
--- /dev/null
+++ b/2013/bestpractices/cmd.png
Binary files differ
diff --git a/2013/bestpractices/concurrency1.go b/2013/bestpractices/concurrency1.go
new file mode 100644
index 0000000..2b8c333
--- /dev/null
+++ b/2013/bestpractices/concurrency1.go
@@ -0,0 +1,32 @@
+package main
+
+import (
+	"errors"
+	"fmt"
+	"time"
+)
+
+// START OMIT
+func doConcurrently(job string, err chan error) {
+	go func() {
+		fmt.Println("doing job", job)
+		time.Sleep(1 * time.Second)
+		err <- errors.New("something went wrong!")
+	}()
+}
+
+func main() {
+	jobs := []string{"one", "two", "three"}
+
+	errc := make(chan error)
+	for _, job := range jobs {
+		doConcurrently(job, errc)
+	}
+	for _ = range jobs {
+		if err := <-errc; err != nil {
+			fmt.Println(err)
+		}
+	}
+}
+
+// END OMIT
diff --git a/2013/bestpractices/concurrency2.go b/2013/bestpractices/concurrency2.go
new file mode 100644
index 0000000..0c4f2f8
--- /dev/null
+++ b/2013/bestpractices/concurrency2.go
@@ -0,0 +1,32 @@
+package main
+
+import (
+	"errors"
+	"fmt"
+	"time"
+)
+
+// START OMIT
+func do(job string) error {
+	fmt.Println("doing job", job)
+	time.Sleep(1 * time.Second)
+	return errors.New("something went wrong!")
+}
+
+func main() {
+	jobs := []string{"one", "two", "three"}
+
+	errc := make(chan error)
+	for _, job := range jobs {
+		go func(job string) {
+			errc <- do(job)
+		}(job)
+	}
+	for _ = range jobs {
+		if err := <-errc; err != nil {
+			fmt.Println(err)
+		}
+	}
+}
+
+// END OMIT
diff --git a/2013/bestpractices/funcdraw/cmd/funcdraw.go b/2013/bestpractices/funcdraw/cmd/funcdraw.go
new file mode 100644
index 0000000..92086af
--- /dev/null
+++ b/2013/bestpractices/funcdraw/cmd/funcdraw.go
@@ -0,0 +1,48 @@
+package main
+
+import (
+	"flag"
+	"image/png"
+	"log"
+	"os"
+)
+
+// IMPORT OMIT
+import (
+	"code.google.com/p/go.talks/2013/bestpractices/funcdraw/drawer"
+	"code.google.com/p/go.talks/2013/bestpractices/funcdraw/parser"
+)
+
+// ENDIMPORT OMIT
+
+var (
+	width  = flag.Int("width", 300, "image width")
+	height = flag.Int("height", 300, "image height")
+	xmin   = flag.Float64("xmin", -10, "min value for x")
+	xmax   = flag.Float64("xmax", 10, "max value for x")
+)
+
+func main() {
+	flag.Parse()
+	if flag.NArg() != 1 {
+		log.Fatal("missing expression to parse")
+	}
+
+	text := flag.Arg(0)
+	// START OMIT
+	// Parse the text into an executable function.
+	f, err := parser.Parse(text)
+	if err != nil {
+		log.Fatalf("parse %q: %v", text, err)
+	}
+
+	// Create an image plotting the function.
+	m := drawer.Draw(f, *width, *height, *xmin, *xmax)
+
+	// Encode the image into the standard output.
+	err = png.Encode(os.Stdout, m)
+	if err != nil {
+		log.Fatalf("encode image: %v", err)
+	}
+	// END OMIT
+}
diff --git a/2013/bestpractices/funcdraw/drawer/dependent.go b/2013/bestpractices/funcdraw/drawer/dependent.go
new file mode 100644
index 0000000..239c3b7
--- /dev/null
+++ b/2013/bestpractices/funcdraw/drawer/dependent.go
@@ -0,0 +1,14 @@
+package drawer
+
+// START OMIT
+import (
+	"image"
+
+	"code.google.com/p/go.talks/2013/bestpractices/funcdraw/parser"
+)
+
+// Draw draws an image showing a rendering of the passed ParsedFunc.
+func DrawParsedFunc(f parser.ParsedFunc) image.Image {
+	// END OMIT
+	return nil
+}
diff --git a/2013/bestpractices/funcdraw/drawer/drawer.go b/2013/bestpractices/funcdraw/drawer/drawer.go
new file mode 100644
index 0000000..9808615
--- /dev/null
+++ b/2013/bestpractices/funcdraw/drawer/drawer.go
@@ -0,0 +1,15 @@
+package drawer
+
+// START OMIT
+import "image"
+
+// Function represent a drawable mathematical function.
+type Function interface {
+	Eval(float64) float64
+}
+
+// Draw draws an image showing a rendering of the passed Function.
+func Draw(f Function) image.Image {
+	// END OMIT
+	return nil
+}
diff --git a/2013/bestpractices/funcdraw/drawer/drawer_test.go b/2013/bestpractices/funcdraw/drawer/drawer_test.go
new file mode 100644
index 0000000..ca16512
--- /dev/null
+++ b/2013/bestpractices/funcdraw/drawer/drawer_test.go
@@ -0,0 +1,22 @@
+package drawer
+
+import (
+	"math"
+	"testing"
+)
+
+type TestFunc func(float64) float64
+
+func (f TestFunc) Eval(x float64) float64 { return f(x) }
+
+var (
+	ident = TestFunc(func(x float64) float64 { return x })
+	sin   = TestFunc(math.Sin)
+)
+
+func TestDraw_Ident(t *testing.T) {
+	m := Draw(ident)
+	// Verify obtained image.
+	// END OMIT
+	t.Error(m.ColorModel())
+}
diff --git a/2013/bestpractices/funcdraw/parser/parser.go b/2013/bestpractices/funcdraw/parser/parser.go
new file mode 100644
index 0000000..71c235e
--- /dev/null
+++ b/2013/bestpractices/funcdraw/parser/parser.go
@@ -0,0 +1,23 @@
+package parser
+
+// START OMIT
+type ParsedFunc struct {
+	text string
+	eval func(float64) float64
+}
+
+func Parse(text string) (*ParsedFunc, error) {
+	f, err := parse(text)
+	if err != nil {
+		return nil, err
+	}
+	return &ParsedFunc{text: text, eval: f}, nil
+}
+
+func (f *ParsedFunc) Eval(x float64) float64 { return f.eval(x) }
+func (f *ParsedFunc) String() string         { return f.text }
+
+// END OMIT
+func parse(text string) (func(float64) float64, error) {
+	return func(x float64) float64 { return x }, nil
+}
diff --git a/2013/bestpractices/httphandler.go b/2013/bestpractices/httphandler.go
new file mode 100644
index 0000000..b9e6c39
--- /dev/null
+++ b/2013/bestpractices/httphandler.go
@@ -0,0 +1,59 @@
+package bestpractices
+
+import (
+	"fmt"
+	"log"
+	"net/http"
+)
+
+func doThis() error { return nil }
+func doThat() error { return nil }
+
+// HANDLER1 OMIT
+func init() {
+	http.HandleFunc("/", handler)
+}
+
+func handler(w http.ResponseWriter, r *http.Request) {
+	err := doThis()
+	if err != nil {
+		http.Error(w, err.Error(), http.StatusInternalServerError)
+		log.Printf("handling %q: %v", r.RequestURI, err)
+		return
+	}
+
+	err = doThat()
+	if err != nil {
+		http.Error(w, err.Error(), http.StatusInternalServerError)
+		log.Printf("handling %q: %v", r.RequestURI, err)
+		return
+	}
+}
+
+// HANDLER2 OMIT
+func init() {
+	http.HandleFunc("/", errorHandler(betterHandler))
+}
+
+func errorHandler(f func(http.ResponseWriter, *http.Request) error) http.HandlerFunc {
+	return func(w http.ResponseWriter, r *http.Request) {
+		err := f(w, r)
+		if err != nil {
+			http.Error(w, err.Error(), http.StatusInternalServerError)
+			log.Printf("handling %q: %v", r.RequestURI, err)
+		}
+	}
+}
+
+func betterHandler(w http.ResponseWriter, r *http.Request) error {
+	if err := doThis(); err != nil {
+		return fmt.Errorf("doing this: %v", err)
+	}
+
+	if err := doThat(); err != nil {
+		return fmt.Errorf("doing that: %v", err)
+	}
+	return nil
+}
+
+// END OMIT
diff --git a/2013/bestpractices/quitchan.go b/2013/bestpractices/quitchan.go
new file mode 100644
index 0000000..3635b28
--- /dev/null
+++ b/2013/bestpractices/quitchan.go
@@ -0,0 +1,58 @@
+package main
+
+import (
+	"fmt"
+	"net"
+	"time"
+)
+
+// SEND OMIT
+func sendMsg(msg, addr string) error {
+	conn, err := net.Dial("tcp", addr)
+	if err != nil {
+		return err
+	}
+	defer conn.Close()
+	_, err = fmt.Fprint(conn, msg)
+	return err
+}
+
+// BROADCAST OMIT
+func broadcastMsg(msg string, addrs []string) error {
+	errc := make(chan error)
+	quit := make(chan struct{})
+
+	defer close(quit)
+
+	for _, addr := range addrs {
+		go func(addr string) {
+			select {
+			case errc <- sendMsg(msg, addr):
+				fmt.Println("done")
+			case <-quit:
+				fmt.Println("quit")
+			}
+		}(addr)
+	}
+
+	for _ = range addrs {
+		if err := <-errc; err != nil {
+			return err
+		}
+	}
+	return nil
+}
+
+// MAIN OMIT
+func main() {
+	addr := []string{"localhost:8080", "http://google.com"}
+	err := broadcastMsg("hi", addr) // HL
+
+	time.Sleep(time.Second)
+
+	if err != nil {
+		fmt.Println(err)
+		return
+	}
+	fmt.Println("everything went fine")
+}
diff --git a/2013/bestpractices/server.go b/2013/bestpractices/server.go
new file mode 100644
index 0000000..b0f2612
--- /dev/null
+++ b/2013/bestpractices/server.go
@@ -0,0 +1,44 @@
+package main
+
+import (
+	"fmt"
+	"time"
+)
+
+// START OMIT
+type Server struct{ quit chan bool }
+
+func NewServer() *Server {
+	s := &Server{make(chan bool)}
+	go s.run()
+	return s
+}
+
+func (s *Server) run() {
+	for {
+		select {
+		case <-s.quit:
+			fmt.Println("finishing task")
+			time.Sleep(time.Second)
+			fmt.Println("task done")
+			s.quit <- true
+			return
+		case <-time.After(time.Second):
+			fmt.Println("running task")
+		}
+	}
+}
+
+// STOP OMIT
+func (s *Server) Stop() {
+	fmt.Println("server stopping")
+	s.quit <- true
+	<-s.quit
+	fmt.Println("server stopped")
+}
+
+func main() {
+	s := NewServer()
+	time.Sleep(2 * time.Second)
+	s.Stop()
+}
diff --git a/2013/bestpractices/shortercode1.go b/2013/bestpractices/shortercode1.go
new file mode 100644
index 0000000..ed0e34e
--- /dev/null
+++ b/2013/bestpractices/shortercode1.go
@@ -0,0 +1,59 @@
+package main
+
+import (
+	"encoding/binary"
+	"image/color"
+	"io"
+	"log"
+	"os"
+)
+
+// GOPHER OMIT
+type Gopher struct {
+	Name     string
+	Age      int32
+	FurColor color.Color
+}
+
+// DUMP OMIT
+func (g *Gopher) DumpBinary(w io.Writer) error {
+	err := binary.Write(w, binary.LittleEndian, int32(len(g.Name)))
+	if err == nil {
+		_, err := w.Write([]byte(g.Name))
+		if err == nil {
+			err := binary.Write(w, binary.LittleEndian, g.Age)
+			if err == nil {
+				return binary.Write(w, binary.LittleEndian, g.FurColor)
+			}
+			return err
+		}
+		return err
+	}
+	return err
+}
+
+// MAIN OMIT
+func main() {
+	w := os.Stdout
+	g := &Gopher{
+		Name:     "Gophertiti",
+		Age:      3383,
+		FurColor: color.RGBA{B: 255},
+	}
+
+	if err := g.DumpBinary(w); err != nil {
+		log.Fatal("DumpBinary: %v", err)
+	}
+}
+
+func (g *Gopher) DumpToFile(f *os.File) error {
+	return nil
+}
+
+func (g *Gopher) DumpToReadWriter(rw io.ReadWriter) error {
+	return nil
+}
+
+func (g *Gopher) DumpToWriter(f io.Writer) error {
+	return nil
+}
diff --git a/2013/bestpractices/shortercode2.go b/2013/bestpractices/shortercode2.go
new file mode 100644
index 0000000..3a28e18
--- /dev/null
+++ b/2013/bestpractices/shortercode2.go
@@ -0,0 +1,47 @@
+package main
+
+import (
+	"encoding/binary"
+	"image/color"
+	"io"
+	"log"
+	"os"
+)
+
+// GOPHER OMIT
+type Gopher struct {
+	Name     string
+	Age      int32
+	FurColor color.Color
+}
+
+// DUMP OMIT
+func (g *Gopher) DumpBinary(w io.Writer) error {
+	err := binary.Write(w, binary.LittleEndian, int32(len(g.Name)))
+	if err != nil {
+		return err
+	}
+	_, err = w.Write([]byte(g.Name))
+	if err != nil {
+		return err
+	}
+	err = binary.Write(w, binary.LittleEndian, g.Age)
+	if err != nil {
+		return err
+	}
+	return binary.Write(w, binary.LittleEndian, g.FurColor)
+}
+
+// MAIN OMIT
+func main() {
+	w := os.Stdout
+	g := &Gopher{
+		Name:     "Gophertiti",
+		Age:      3383,
+		FurColor: color.RGBA{B: 255},
+	}
+
+	if err := g.DumpBinary(w); err != nil {
+		log.Fatal("DumpBinary: %v", err)
+	}
+}
diff --git a/2013/bestpractices/shortercode3.go b/2013/bestpractices/shortercode3.go
new file mode 100644
index 0000000..0bd896f
--- /dev/null
+++ b/2013/bestpractices/shortercode3.go
@@ -0,0 +1,55 @@
+package main
+
+import (
+	"encoding/binary"
+	"image/color"
+	"io"
+	"log"
+	"os"
+)
+
+// GOPHER OMIT
+type Gopher struct {
+	Name     string
+	Age      int32
+	FurColor color.Color
+}
+
+// BINWRITER OMIT
+type binWriter struct {
+	w   io.Writer
+	err error
+}
+
+// WRITE OMIT
+// Write writes a value into its writer using little endian.
+func (w *binWriter) Write(v interface{}) {
+	if w.err != nil {
+		return
+	}
+	w.err = binary.Write(w.w, binary.LittleEndian, v)
+}
+
+// DUMP OMIT
+func (g *Gopher) DumpBinary(w io.Writer) error {
+	bw := &binWriter{w: w}
+	bw.Write(int32(len(g.Name)))
+	bw.Write([]byte(g.Name))
+	bw.Write(g.Age)
+	bw.Write(g.FurColor)
+	return bw.err
+}
+
+// MAIN OMIT
+func main() {
+	w := os.Stdout
+	g := &Gopher{
+		Name:     "Gophertiti",
+		Age:      3383,
+		FurColor: color.RGBA{B: 255},
+	}
+
+	if err := g.DumpBinary(w); err != nil {
+		log.Fatal("DumpBinary: %v", err)
+	}
+}
diff --git a/2013/bestpractices/shortercode4.go b/2013/bestpractices/shortercode4.go
new file mode 100644
index 0000000..43aa6bc
--- /dev/null
+++ b/2013/bestpractices/shortercode4.go
@@ -0,0 +1,60 @@
+package main
+
+import (
+	"encoding/binary"
+	"image/color"
+	"io"
+	"log"
+	"os"
+)
+
+// GOPHER OMIT
+type Gopher struct {
+	Name     string
+	Age      int32
+	FurColor color.Color
+}
+
+type binWriter struct {
+	w   io.Writer
+	err error
+}
+
+// WRITE OMIT
+// Write writes a value into its writer using little endian.
+func (w *binWriter) Write(v interface{}) {
+	if w.err != nil {
+		return
+	}
+	switch v.(type) {
+	case string:
+		s := v.(string)
+		w.Write(int32(len(s)))
+		w.Write([]byte(s))
+	default:
+		w.err = binary.Write(w.w, binary.LittleEndian, v)
+	}
+}
+
+// DUMP OMIT
+func (g *Gopher) DumpBinary(w io.Writer) error {
+	bw := &binWriter{w: w}
+	bw.Write(g.Name)
+	bw.Write(g.Age)
+	bw.Write(g.FurColor)
+	return bw.err
+}
+
+// MAIN OMIT
+func main() {
+	w := os.Stdout
+	g := &Gopher{
+		Name:     "Gophertiti",
+		Age:      3383,
+		FurColor: color.RGBA{B: 255},
+	}
+
+	if err := g.DumpBinary(w); err != nil {
+		log.Fatal("DumpBinary: %v", err)
+	}
+}
diff --git a/2013/bestpractices/shortercode5.go b/2013/bestpractices/shortercode5.go
new file mode 100644
index 0000000..e8e67c8
--- /dev/null
+++ b/2013/bestpractices/shortercode5.go
@@ -0,0 +1,59 @@
+package main
+
+import (
+	"encoding/binary"
+	"image/color"
+	"io"
+	"log"
+	"os"
+)
+
+// GOPHER OMIT
+type Gopher struct {
+	Name     string
+	Age      int32
+	FurColor color.Color
+}
+
+type binWriter struct {
+	w   io.Writer
+	err error
+}
+
+// WRITE OMIT
+// Write write the given value into the writer using little endian.
+func (w *binWriter) Write(v interface{}) {
+	if w.err != nil {
+		return
+	}
+	switch v := v.(type) {
+	case string:
+		w.Write(int32(len(v)))
+		w.Write([]byte(v))
+	default:
+		w.err = binary.Write(w.w, binary.LittleEndian, v)
+	}
+}
+
+// DUMP OMIT
+func (g *Gopher) DumpBinary(w io.Writer) error {
+	bw := &binWriter{w: w}
+	bw.Write(g.Name)
+	bw.Write(g.Age)
+	bw.Write(g.FurColor)
+	return bw.err
+}
+
+// MAIN OMIT
+func main() {
+	w := os.Stdout
+	g := &Gopher{
+		Name:     "Gophertiti",
+		Age:      3383,
+		FurColor: color.RGBA{B: 255},
+	}
+
+	if err := g.DumpBinary(w); err != nil {
+		log.Fatal("DumpBinary: %v", err)
+	}
+}