Text file talks/2014/go4gophers.slide

     1  Go for gophers
     2  GopherCon closing keynote
     3  25 Apr 2014
     4  
     5  Andrew Gerrand
     6  Google, Inc.
     7  @enneff
     8  adg@golang.org
     9  
    10  
    11  * Video
    12  
    13  A video of this talk was recorded at GopherCon in Denver.
    14  
    15  .link https://www.youtube.com/watch?v=dKGmK_Z1Zl0 Watch the talk on YouTube
    16  
    17  
    18  * About me
    19  
    20  .image go4gophers/gopherswim.jpg
    21  
    22  I joined Google and the Go team in February 2010.
    23  
    24  Had to re-think some of my preconceptions about programming.
    25  
    26  Let me share what I have learned since.
    27  
    28  
    29  * Interfaces
    30  
    31  
    32  * Interfaces: first impressions
    33  
    34  I used to think about classes and types.
    35  
    36  Go resists this:
    37  
    38  - No inheritance.
    39  - No subtype polymorphism.
    40  - No generics.
    41  
    42  It instead emphasizes _interfaces_.
    43  
    44  
    45  * Interfaces: the Go way
    46  
    47  Go interfaces are small.
    48  
    49  	type Stringer interface {
    50  		String() string
    51  	}
    52  
    53  A `Stringer` can pretty print itself.
    54  Anything that implements `String` is a `Stringer`.
    55  
    56  
    57  * An interface example
    58  
    59  An `io.Reader` value emits a stream of binary data.
    60  
    61  	type Reader interface {
    62  		Read([]byte) (int, error)
    63  	}
    64  
    65  Like a UNIX pipe.
    66  
    67  
    68  * Implementing interfaces
    69  
    70  .code go4gophers/reader.go /ByteReader/,/^}/
    71  
    72  
    73  * Wrapping interfaces
    74  
    75  .code go4gophers/reader.go /LogReader/,/STOP/
    76  
    77  Wrapping a `ByteReader` with a `LogReader`:
    78  
    79  .play go4gophers/reader.go /START/,/STOP/
    80  
    81  By wrapping we compose interface _values_.
    82  
    83  
    84  * Chaining interfaces
    85  
    86  Wrapping wrappers to build chains:
    87  
    88  .code go4gophers/chain.go /START/,/STOP/
    89  
    90  More succinctly:
    91  
    92  .play go4gophers/chain.go /LogReader{io/
    93  
    94  Implement complex behavior by composing small pieces.
    95  
    96  
    97  * Programming with interfaces
    98  
    99  Interfaces separate data from behavior.
   100  
   101  With interfaces, functions can operate on _behavior:_
   102  
   103  	// Copy copies from src to dst until either EOF is reached
   104  	// on src or an error occurs.  It returns the number of bytes
   105  	// copied and the first error encountered while copying, if any.
   106  	func Copy(dst Writer, src Reader) (written int64, err error) {
   107  
   108  .play go4gophers/chain.go /LogReader{io/
   109  
   110  `Copy` can't know about the underlying data structures.
   111  
   112  
   113  * A larger interface
   114  
   115  `sort.Interface` describes the operations required to sort a collection:
   116  
   117  	type Interface interface {
   118  	    Len() int
   119  	    Less(i, j int) bool
   120  	    Swap(i, j int)
   121  	}
   122  
   123  `IntSlice` can sort a slice of ints:
   124  
   125  	type IntSlice []int
   126  
   127  	func (p IntSlice) Len() int           { return len(p) }
   128  	func (p IntSlice) Less(i, j int) bool { return p[i] < p[j] }
   129  	func (p IntSlice) Swap(i, j int)      { p[i], p[j] = p[j], p[i] }
   130  
   131  `sort.Sort` uses can sort a `[]int` with `IntSlice`:
   132  
   133  .play go4gophers/sort.go /START/,/STOP/
   134  
   135  
   136  * Another interface example
   137  
   138  The `Organ` type describes a body part and can print itself:
   139  
   140  .play go4gophers/organs.go /type Organ/,$
   141  
   142  
   143  * Sorting organs
   144  
   145  The `Organs` type knows how to describe and mutate a slice of organs:
   146  
   147  .code go4gophers/organs2.go /PART1/,/PART2/
   148  
   149  The `ByName` and `ByWeight` types embed `Organs` to sort by different fields:
   150  
   151  .code go4gophers/organs2.go /PART2/,/PART3/
   152  
   153  With embedding we compose _types_.
   154  
   155  
   156  * Sorting organs (continued)
   157  
   158  To sort a `[]*Organ`, wrap it with `ByName` or `ByWeight` and pass it to `sort.Sort`:
   159  
   160  .play go4gophers/organs2.go /START/,/STOP/
   161  
   162  
   163  * Another wrapper
   164  
   165  The `Reverse` function takes a `sort.Interface` and
   166  returns a `sort.Interface` with an inverted `Less` method:
   167  
   168  .code go4gophers/organs3.go /func Reverse/,$
   169  
   170  To sort the organs in descending order, compose our sort types with `Reverse`:
   171  
   172  .play go4gophers/organs3.go /START/,/STOP/
   173  
   174  
   175  * Interfaces: why they work
   176  
   177  These are not just cool tricks.
   178  
   179  This is how we structure programs in Go.
   180  
   181  
   182  * Interfaces: Sigourney
   183  
   184  Sigourney is a modular audio synthesizer I wrote in Go.
   185  
   186  .image go4gophers/sigourney.png
   187  
   188  Audio is generated by a chain of `Processors`:
   189  
   190  	type Processor interface {
   191  		Process(buffer []Sample)
   192  	}
   193  
   194  ([[https://github.com/nf/sigourney][github.com/nf/sigourney]])
   195  
   196  
   197  * Interfaces: Roshi
   198  
   199  Roshi is a time-series event store written by Peter Bourgon. It provides this API:
   200  
   201  	Insert(key, timestamp, value)
   202  	Delete(key, timestamp, value)
   203  	Select(key, offset, limit) []TimestampValue
   204  
   205  The same API is implemented by the `farm` and `cluster` parts of the system.
   206  
   207  .image go4gophers/roshi.png
   208  
   209  An elegant design that exhibits composition.
   210  ([[https://github.com/soundcloud/roshi][github.com/soundcloud/roshi]])
   211  
   212  
   213  * Interfaces: why they work (continued)
   214  
   215  Interfaces are _the_ generic programming mechanism.
   216  
   217  This gives all Go code a familiar shape.
   218  
   219  Less is more.
   220  
   221  
   222  * Interfaces: why they work (continued)
   223  
   224  It's all about composition.
   225  
   226  Interfaces—by design and convention—encourage us to write composable code.
   227  
   228  
   229  * Interfaces: why they work (continued)
   230  
   231  Interfaces types are just types
   232  and interface values are just values.
   233  
   234  They are orthogonal to the rest of the language.
   235  
   236  
   237  * Interfaces: why they work (continued)
   238  
   239  Interfaces separate data from behavior. (Classes conflate them.)
   240  
   241  	type HandlerFunc func(ResponseWriter, *Request)
   242  
   243  	func (f HandlerFunc) ServeHTTP(w ResponseWriter, r *Request) {
   244  		f(w, r)
   245  	}
   246  
   247  
   248  * Interfaces: what I learned
   249  
   250  Think about composition.
   251  
   252  Better to have many small simple things than one big complex thing.
   253  
   254  Also: what I thought of as small is pretty big.
   255  
   256  Some repetition in the small is okay when it benefits "the large".
   257  
   258  
   259  * Concurrency
   260  
   261  
   262  * Concurrency: first impressions
   263  
   264  My first exposure to concurrency was in C, Java, and Python.
   265  Later: event-driven models in Python and JavaScript.
   266  
   267  When I saw Go I saw:
   268  
   269  "The performance of an event-driven model without callback hell."
   270  
   271  But I had questions: "Why can't I wait on or kill a goroutine?"
   272  
   273  
   274  * Concurrency: the Go way
   275  
   276  Goroutines provide concurrent execution.
   277  
   278  Channels express the communication and synchronization of independent processes.
   279  
   280  Select enables computation on channel operations.
   281  
   282  .image go4gophers/gopherflag.png
   283  
   284  
   285  * A concurrency example
   286  
   287  The binary tree comparison exercise from the Go Tour.
   288  
   289  "Implement a function
   290  
   291          func Same(t1, t2 *tree.Tree) bool
   292  
   293  that compares the contents of two binary trees."
   294  
   295  .image go4gophers/tree.png
   296  
   297  
   298  * Walking a tree
   299  
   300  	type Tree struct {
   301  		Left, Right *Tree
   302  		Value int
   303  	}
   304  
   305  A simple depth-first tree traversal:
   306  
   307  .play go4gophers/tree-walk.go /func Walk/,$
   308  
   309  
   310  * Comparing trees (1/2)
   311  
   312  A concurrent walker:
   313  
   314  .code go4gophers/tree-thread.go /func Walk/,/STOP/
   315  
   316  
   317  * Comparing trees (2/2)
   318  
   319  Walking two trees concurrently:
   320  
   321  .play go4gophers/tree-thread.go /func Same/,$
   322  
   323  
   324  * Comparing trees without channels (1/3)
   325  
   326  .code go4gophers/tree-nothread.go /func Same/,/^}/
   327  
   328  The `Walk` function has nearly the same signature:
   329  
   330  .code go4gophers/tree-nothread.go /func Walk/
   331  .code go4gophers/tree-nothread.go /func.+Next/
   332  
   333  (We call `Next` instead of the channel receive.)
   334  
   335  
   336  * Comparing trees without channels (2/3)
   337  
   338  But the implementation is much more complex:
   339  
   340  .code go4gophers/tree-nothread.go /func Walk/,/CUT/
   341  
   342  
   343  * Comparing trees without channels (3/3)
   344  
   345  .code go4gophers/tree-nothread.go /CUT/,/STOP/
   346  
   347  
   348  * Another look at the channel version
   349  
   350  .code go4gophers/tree-thread.go /func Walk/,/STOP/
   351  
   352  But there's a problem: when an inequality is found,
   353  a goroutine might be left blocked sending to `ch`.
   354  
   355  
   356  * Stopping early
   357  
   358  Add a `quit` channel to the walker so we can stop it mid-stride.
   359  
   360  .code go4gophers/tree-select.go /func Walk/,/STOP/
   361  
   362  
   363  * Stopping early (continued)
   364  
   365  Create a `quit` channel and pass it to each walker.
   366  By closing `quit` when the `Same` exits, any running walkers are terminated.
   367  
   368  .code go4gophers/tree-select.go /func Same/,/^}/
   369  
   370  
   371  * Why not just kill the goroutines?
   372  
   373  Goroutines are invisible to Go code. They can't be killed or waited on.
   374  
   375  You have to build that yourself.
   376  
   377  There's a reason:
   378  
   379  As soon as Go code knows in which thread it runs you get thread-locality.
   380  
   381  Thread-locality defeats the concurrency model.
   382  
   383  
   384  * Concurrency: why it works
   385  
   386  The model makes concurrent code easy to read and write.
   387  (Makes concurrency is *accessible*.)
   388  
   389  This encourages the decomposition of independent computations.
   390  
   391  
   392  * Concurrency: why it works (continued)
   393  
   394  The simplicity of the concurrency model makes it flexible.
   395  
   396  Channels are just values; they fit right into the type system.
   397  
   398  Goroutines are invisible to Go code; this gives you concurrency anywhere.
   399  
   400  Less is more.
   401  
   402  
   403  * Concurrency: what I learned
   404  
   405  Concurrency is not just for doing more things faster.
   406  
   407  It's for writing better code.
   408  
   409  
   410  * Syntax
   411  
   412  
   413  * Syntax: first impressions
   414  
   415  At first, Go syntax felt a bit inflexible and verbose.
   416  
   417  It affords few of the conveniences to which I was accustomed.
   418  
   419  For instance:
   420  
   421  - No getters/setters on fields.
   422  - No map/filter/reduce/zip.
   423  - No optional arguments.
   424  
   425  
   426  * Syntax: the Go way
   427  
   428  Favor readability above all.
   429  
   430  Offer enough sugar to be productive, but not too much.
   431  
   432  
   433  * Getters and setters (or "properties")
   434  
   435  Getters and setters turn assignments and reads into function calls.
   436  This leads to surprising hidden behavior.
   437  
   438  In Go, just write (and call) the methods.
   439  
   440  The control flow cannot be obscured.
   441  
   442  
   443  * Map/filter/reduce/zip
   444  
   445  Map/filter/reduce/zip are useful  in Python.
   446  
   447  	a = [1, 2, 3, 4]
   448  	b = map(lambda x: x+1, a)
   449  
   450  In Go, you just write the loops.
   451  
   452  	a := []int{1, 2, 3, 4}
   453  	b := make([]int, len(a))
   454  	for i, x := range a {
   455  		b[i] = x+1
   456  	}
   457  
   458  This is a little more verbose,
   459  but makes the performance characteristics obvious.
   460  
   461  It's easy code to write, and you get more control.
   462  
   463  
   464  * Optional arguments
   465  
   466  Go functions can't have optional arguments.
   467  
   468  Instead, use variations of the function:
   469  
   470  	func NewWriter(w io.Writer) *Writer
   471  	func NewWriterLevel(w io.Writer, level int) (*Writer, error)
   472  
   473  Or an options struct:
   474  
   475  	func New(o *Options) (*Jar, error)
   476  
   477  	type Options struct {
   478  		PublicSuffixList PublicSuffixList
   479  	}
   480  
   481  Or a variadic list of options.
   482  
   483  Create many small simple things, not one big complex thing.
   484  
   485  
   486  * Syntax: why it works
   487  
   488  The language resists convoluted code.
   489  
   490  With obvious control flow, it's easy to navigate unfamiliar code.
   491  
   492  Instead we create more small things that are easy to document and understand.
   493  
   494  So Go code is easy to read.
   495  
   496  (And with gofmt, it's easy to write readable code.)
   497  
   498  
   499  * Syntax: what I learned
   500  
   501  I was often too clever for my own good.
   502  
   503  I appreciate the consistency, clarity, and _transparency_ of Go code.
   504  
   505  I sometimes miss the conveniences, but rarely.
   506  
   507  
   508  * Error handling
   509  
   510  
   511  * Error handling: first impressions
   512  
   513  I had previously used exceptions to handle errors.
   514  
   515  Go's error handling model felt verbose by comparison.
   516  
   517  I was immediately tired of typing this:
   518  
   519  	if err != nil {
   520  		return err
   521  	}
   522  
   523  
   524  * Error handling: the Go way
   525  
   526  Go codifies errors with the built-in `error` interface:
   527  
   528  	type error interface {
   529  		Error() string
   530  	}
   531  
   532  Error values are used just like any other value.
   533  
   534  	func doSomething() error
   535  
   536  	err := doSomething()
   537  	if err != nil {
   538  		log.Println("An error occurred:", err)
   539  	}
   540  
   541  Error handling code is just code.
   542  
   543  (Started as a convention (`os.Error`). We made it built in for Go 1.)
   544  
   545  
   546  * Error handling: why it works
   547  
   548  Error handling is important.
   549  
   550  Go makes error handling as important as any other code.
   551  
   552  
   553  * Error handling: why it works (continued)
   554  
   555  Errors are just values; they fit easily into the rest of the language
   556  (interfaces, channels, and so on).
   557  
   558  Result: Go code handles errors correctly and elegantly.
   559  
   560  
   561  * Error handling: why it works (continued)
   562  
   563  We use the same language for errors as everything else.
   564  
   565  Lack of hidden control flow (throw/try/catch/finally) improves readability.
   566  
   567  Less is more.
   568  
   569  
   570  
   571  * Error handling: what I learned
   572  
   573  To write good code we must think about errors.
   574  
   575  Exceptions make it easy to avoid thinking about errors.
   576  (Errors shouldn't be "exceptional!")
   577  
   578  Go encourages us to consider every error condition.
   579  
   580  My Go programs are far more robust than my programs in other languages.
   581  
   582  I don't miss exceptions at all.
   583  
   584  
   585  * Packages
   586  
   587  
   588  * Packages: first impressions
   589  
   590  I found the capital-letter-visibility rule weird;
   591  "Let me use my own naming scheme!"
   592  
   593  I didn't like "package per directory";
   594  "Let me use my own structure!"
   595  
   596  I was disappointed by lack of monkey patching.
   597  
   598  
   599  * Packages: the Go way
   600  
   601  Go packages are a name space for types, functions, variables, and constants.
   602  
   603  
   604  * Visibility
   605  
   606  Visibility is at the package level.
   607  Names are "exported" when they begin with a capital letter.
   608  
   609  	package zip
   610  
   611  	func NewReader(r io.ReaderAt, size int64) (*Reader, error) // exported
   612  
   613  	type Reader struct {    // exported
   614  		File    []*File     // exported
   615  		Comment string      // exported
   616  		r       io.ReaderAt // unexported
   617  	}
   618  
   619  	func (f *File) Open() (rc io.ReadCloser, err error)   // exported
   620  
   621  	func (f *File) findBodyOffset() (int64, error)        // unexported
   622  
   623  	func readDirectoryHeader(f *File, r io.Reader) error  // unexported
   624  
   625  Good for readability: easy to see whether a name is part of the public interface.
   626  Good for design: couples naming decisions with interface decisions.
   627  
   628  
   629  * Package structure
   630  
   631  Packages can be spread across multiple files.
   632  
   633  Permits shared private implementation and informal code organization.
   634  
   635  Packages files must live in a directory unique to the package.
   636  
   637  The path to that directory determines the package's import path.
   638  
   639  The build system locates dependencies from the source alone.
   640  
   641  
   642  * "Monkey patching"
   643  
   644  Go forbids modifying package declarations from outside the package.
   645  
   646  But we can get similar behavior using global variables:
   647  
   648  	package flag
   649  
   650  	var Usage = func() {
   651  		fmt.Fprintf(os.Stderr, "Usage of %s:\n", os.Args[0])
   652  		PrintDefaults()
   653  	}
   654  
   655  Or registration functions:
   656  
   657  	package http
   658  
   659  	func Handle(pattern string, handler Handler)
   660  
   661  This gives the flexibility of monkey patching but on the package author's terms.
   662  
   663  (This depends on Go's initialization semantics.)
   664  
   665  
   666  * Packages: why they work
   667  
   668  The loose organization of packages lets us write and refactor code quickly.
   669  
   670  But packages encourage the programmer to consider the public interface.
   671  
   672  This leads to good names and simpler interfaces.
   673  
   674  With the source as the single source of truth,
   675  there are no makefiles to get out of sync.
   676  
   677  (This design enables great tools like [[https://pkg.go.dev][pkg.go.dev]] and goimports.)
   678  
   679  Predictable semantics make packages easy to read, understand, and use.
   680  
   681  
   682  * Packages: what I learned
   683  
   684  Go's package system taught me to prioritize the consumer of my code.
   685  (Even if that consumer is me.)
   686  
   687  It also stopped me from doing gross stuff.
   688  
   689  Packages are rigid where it matters, and loose where it doesn't.
   690  It just feels right.
   691  
   692  Probably my favorite part of the language.
   693  
   694  
   695  * Documentation
   696  
   697  
   698  * Documentation: first impressions
   699  
   700  Godoc reads documentation from Go source code, like `pydoc` or `javadoc`.
   701  
   702  But unlike those two, it doesn't support complex formatting or other meta data.
   703  Why?
   704  
   705  
   706  * Documentation: the Go way
   707  
   708  Godoc comments precede the declaration of an exported identifier:
   709  
   710  	// Join concatenates the elements of a to create a single string.
   711  	// The separator string sep is placed between elements in the resulting string.
   712  	func Join(a []string, sep string) string {
   713  
   714  It extracts the comments and presents them:
   715  
   716  	$ godoc strings Join
   717  	func Join(a []string, sep string) string
   718  	    Join concatenates the elements of a to create a single string. The
   719  	    separator string sep is placed between elements in the resulting string.
   720  
   721  Also integrated with the testing framework to provide testable example functions.
   722  
   723  	func ExampleJoin() {
   724  		s := []string{"foo", "bar", "baz"}
   725  		fmt.Println(strings.Join(s, ", "))
   726  		// Output: foo, bar, baz
   727  	}
   728  
   729  
   730  * Documentation: the Go way (continued)
   731  
   732  .image go4gophers/godoc.png
   733  
   734  
   735  * Documentation: why it works
   736  
   737  Godoc wants you to write good comments, so the source looks great:
   738  
   739  	// ValidMove reports whether the specified move is valid.
   740  	func ValidMove(from, to Position) bool
   741  
   742  Javadoc just wants to produce pretty documentation, so the source is hideous:
   743  
   744  	/**
   745  	 * Validates a chess move.
   746  	 *
   747  	 * @param fromPos  position from which a piece is being moved
   748  	 * @param toPos    position to which a piece is being moved
   749  	 * @return         true if the move is valid, otherwise false
   750  	 */
   751  	boolean isValidMove(Position fromPos, Position toPos)
   752  
   753  (Also a grep for `"ValidMove"` will return the first line of documentation.)
   754  
   755  
   756  * Documentation: what I learned
   757  
   758  Godoc taught me to write documentation _as_I_code._
   759  
   760  Writing documentation _improves_the_code_ I write.
   761  
   762  
   763  * More
   764  
   765  There are many more examples.
   766  
   767  The overriding theme:
   768  
   769  - At first, something seemed weird or lacking.
   770  - I realized it was a design decision.
   771  
   772  Those decisions make the language—and Go code—better.
   773  
   774  Sometimes you have to live with the language a while to see it.
   775  
   776  
   777  * Lessons
   778  
   779  
   780  * Code is communication
   781  
   782  Be articulate:
   783  
   784  - Choose good names.
   785  - Design simple interfaces.
   786  - Write precise documentation.
   787  - Don't be too clever.
   788  
   789  
   790  * Less is exponentially more
   791  
   792  New features can weaken existing features.
   793  
   794  Features multiply complexity.
   795  
   796  Complexity defeats orthogonality.
   797  
   798  Orthogonality is vital: it enables composition.
   799  
   800  
   801  * Composition is key
   802  
   803  Don't solve problems by building _a_ thing.
   804  
   805  Instead, combine simple tools and compose them.
   806  
   807  
   808  * Design good interfaces
   809  
   810  .image go4gophers/gophertraining.png
   811  
   812  .html go4gophers/gophertraining.html
   813  
   814  
   815  * Simplicity is hard
   816  
   817  Invest the time to find the simple solution.
   818  
   819  
   820  * Go's effect on me
   821  
   822  These lessons were all things I already "knew".
   823  
   824  Go helped me internalize them.
   825  
   826  .image go4gophers/gopherhat.jpg
   827  
   828  Go made me a better programmer.
   829  
   830  
   831  * A message for gophers everywhere
   832  
   833  Let's build small, simple, and beautiful things together.
   834  
   835  .image go4gophers/gopherswrench.jpg
   836  
   837  

View as plain text