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