Text file talks/2013/bestpractices.slide

     1  Twelve Go Best Practices
     2  
     3  Francesc Campoy Flores
     4  Gopher at Google
     5  @francesc
     6  http://campoy.cat/+
     7  
     8  https://go.dev
     9  
    10  * Best practices
    11  
    12  From Wikipedia:
    13  
    14  	"A best practice is a method or technique that has consistently shown results superior
    15  	to those achieved with other means"
    16  
    17  Techniques to write Go code that is
    18  
    19  - simple,
    20  - readable,
    21  - maintainable.
    22  
    23  .image /doc/gopher/gopherbw.png 200 200
    24  
    25  * Some code
    26  
    27  .code bestpractices/shortercode1.go /type Gopher/,/^}/
    28  
    29  .code bestpractices/shortercode1.go /WriteTo/,/^}/
    30  
    31  * Avoid nesting by handling errors first
    32  
    33  .code bestpractices/shortercode2.go /WriteTo/,/^}/
    34  
    35  Less nesting means less cognitive load on the reader
    36  
    37  * Avoid repetition when possible
    38  
    39  Deploy one-off utility types for simpler code
    40  
    41  .code bestpractices/shortercode3.go /binWriter/,/^}/
    42  
    43  .code bestpractices/shortercode3.go /Write writes/,/^}/
    44  
    45  * Avoid repetition when possible
    46  
    47  Using `binWriter`
    48  
    49  .code bestpractices/shortercode3.go /WriteTo/,/^}/
    50  
    51  * Type switch to handle special cases
    52  
    53  .code bestpractices/shortercode4.go /func .* Write/,/^}/
    54  
    55  .code bestpractices/shortercode4.go /WriteTo/,/^}/
    56  
    57  * Type switch with short variable declaration
    58  
    59  .code bestpractices/shortercode5.go /func .* Write/,/^}/
    60  
    61  * Writing everything or nothing
    62  
    63  .code bestpractices/shortercode6.go /binWriter/,/^}/
    64  
    65  .code bestpractices/shortercode6.go /Write writes/,/^}/
    66  
    67  * Writing everything or nothing
    68  
    69  .code bestpractices/shortercode6.go /Flush/,/^}/
    70  
    71  .code bestpractices/shortercode6.go /func .* WriteTo/,/^}/
    72  
    73  * Function adapters
    74  
    75  .code bestpractices/httphandler.go /HANDLER1/,/HANDLER2/
    76  
    77  * Function adapters
    78  
    79  .code bestpractices/httphandler.go /HANDLER2/,/END/
    80  
    81  * Organizing your code
    82  
    83  * Important code goes first
    84  
    85  License information, build tags, package documentation.
    86  
    87  Import statements, related groups separated by blank lines.
    88  
    89  	import (
    90  		"fmt"
    91  		"io"
    92  		"log"
    93  
    94  		"golang.org/x/net/websocket"
    95  	)
    96  
    97  The rest of the code starting with the most significant types, and ending
    98  with helper function and types.
    99  
   100  * Document your code
   101  
   102  Package name, with the associated documentation before.
   103  
   104  	// Package playground registers an HTTP handler at "/compile" that
   105  	// proxies requests to the golang.org playground service.
   106  	package playground
   107  
   108  Exported identifiers appear in `godoc`, they should be documented correctly.
   109  
   110  	// Author represents the person who wrote and/or is presenting the document.
   111  	type Author struct {
   112  		Elem []Elem
   113  	}
   114  
   115  	// TextElem returns the first text elements of the author details.
   116  	// This is used to display the author' name, job title, and company
   117  	// without the contact details.
   118  	func (p *Author) TextElem() (elems []Elem) {
   119  
   120  [[https://pkg.go.dev/code.google.com/p/go.talks/pkg/present#Author][Generated documentation]]
   121  
   122  [[/blog/godoc-documenting-go-code][Gocode: documenting Go code]]
   123  
   124  * Shorter is better
   125  
   126  or at least _longer_is_not_always_better_.
   127  
   128  Try to find the *shortest*name*that*is*self*explanatory*.
   129  
   130  - Prefer `MarshalIndent` to `MarshalWithIndentation`.
   131  
   132  Don't forget that the package name will appear before the identifier you chose.
   133  
   134  - In package `encoding/json` we find the type `Encoder`, not `JSONEncoder`.
   135  
   136  - It is referred as `json.Encoder`.
   137  
   138  * Packages with multiple files
   139  
   140  Should you split a package into multiple files?
   141  
   142  - Avoid very long files
   143  
   144  The `net/http` package from the standard library contains 15734 lines in 47 files.
   145  
   146  - Separate code and tests
   147  
   148  `net/http/cookie.go` and `net/http/cookie_test.go` are both part of the `http`
   149  package.
   150  
   151  Test code is compiled *only* at test time.
   152  
   153  - Separated package documentation
   154  
   155  When we have more than one file in a package, it's convention to create a `doc.go`
   156  containing the package documentation.
   157  
   158  * Make your packages "go get"-able
   159  
   160  Some packages are potentially reusable, some others are not.
   161  
   162  A package defining some network protocol might be reused while one defining
   163  an executable command may not.
   164  
   165  .image bestpractices/cmd.png
   166  
   167  [[https://github.com/bradfitz/camlistore]]
   168  
   169  * APIs
   170  
   171  * Ask for what you need
   172  
   173  Let's use the Gopher type from before
   174  
   175  .code bestpractices/shortercode1.go /type Gopher/,/^}/
   176  
   177  We could define this method
   178  
   179  .code bestpractices/shortercode1.go /WriteToFile/
   180  
   181  But using a concrete type makes this code difficult to test, so we use an interface.
   182  
   183  .code bestpractices/shortercode1.go /WriteToReadWriter/
   184  
   185  And, since we're using an interface, we should ask only for the methods we need.
   186  
   187  .code bestpractices/shortercode1.go /WriteToWriter/
   188  
   189  * Keep independent packages independent
   190  
   191  .code bestpractices/funcdraw/cmd/funcdraw.go /IMPORT/,/ENDIMPORT/
   192  
   193  .code bestpractices/funcdraw/cmd/funcdraw.go /START/,/END/
   194  
   195  * Parsing
   196  
   197  .code bestpractices/funcdraw/parser/parser.go /START/,/END/
   198  
   199  * Drawing
   200  
   201  .code bestpractices/funcdraw/drawer/dependent.go /START/,/END/
   202  
   203  Avoid dependency by using an interface.
   204  
   205  .code bestpractices/funcdraw/drawer/drawer.go /START/,/END/
   206  
   207  * Testing
   208  
   209  Using an interface instead of a concrete type makes testing easier.
   210  
   211  .code bestpractices/funcdraw/drawer/drawer_test.go ,/END/
   212  
   213  * Avoid concurrency in your API
   214  
   215  .play bestpractices/concurrency1.go /START/,/END/
   216  
   217  What if we want to use it sequentially?
   218  
   219  * Avoid concurrency in your API
   220  
   221  .play bestpractices/concurrency2.go /START/,/END/
   222  
   223  Expose synchronous APIs, calling them concurrently is easy.
   224  
   225  * Best practices for concurrency
   226  
   227  * Use goroutines to manage state
   228  
   229  Use a chan or a struct with a chan to communicate with a goroutine
   230  
   231  .code bestpractices/server.go /START/,/STOP/
   232  
   233  * Use goroutines to manage state (continued)
   234  
   235  .play bestpractices/server.go /STOP/,
   236  
   237  * Avoid goroutine leaks with buffered chans
   238  
   239  .code bestpractices/bufchan.go /SEND/,/BROADCAST/
   240  
   241  .code bestpractices/bufchan.go /MAIN/,
   242  
   243  * Avoid goroutine leaks with buffered chans (continued)
   244  
   245  .play bestpractices/bufchan.go /BROADCAST/,/MAIN/
   246  
   247  - the goroutine is blocked on the chan write
   248  - the goroutine holds a reference to the chan
   249  - the chan will never be garbage collected
   250  
   251  * Avoid goroutines leaks with buffered chans (continued)
   252  
   253  .play bestpractices/bufchanfix.go /BROADCAST/,/MAIN/
   254  
   255  - what if we can't predict the capacity of the channel?
   256  
   257  * Avoid goroutines leaks with quit chan
   258  
   259  .play bestpractices/quitchan.go /BROADCAST/,/MAIN/
   260  
   261  * Twelve best practices
   262  
   263  1. Avoid nesting by handling errors first
   264  2. Avoid repetition when possible
   265  3. Important code goes first
   266  4. Document your code
   267  5. Shorter is better
   268  6. Packages with multiple files
   269  7. Make your packages "go get"-able
   270  8. Ask for what you need
   271  9. Keep independent packages independent
   272  10. Avoid concurrency in your API
   273  11. Use goroutines to manage state
   274  12. Avoid goroutine leaks
   275  
   276  * Some links
   277  
   278  Resources
   279  
   280  - Go homepage [[/][go.dev]]
   281  - Go interactive tour [[/tour/][go.dev/tour]]
   282  
   283  Other talks
   284  
   285  - Lexical scanning with Go [[http://www.youtube.com/watch?v=HxaD_trXwRE][video]]
   286  - Concurrency is not parallelism [[http://vimeo.com/49718712][video]]
   287  - Go concurrency patterns [[http://www.youtube.com/watch?v=f6kdp27TYZs][video]]
   288  - Advanced Go concurrency patterns [[http://www.youtube.com/watch?v=QDDwwePbDtw][video]]
   289  

View as plain text