Text file
talks/2014/organizeio.slide
1 Organizing Go code
2
3 David Crawshaw
4 crawshaw@golang.org
5
6
7 * Packages
8
9 * Go programs are made up of packages
10
11 All Go source is part of a package.
12 Every file begins with a package statement.
13 Programs start in package main.
14
15 .play organizeio/hello.go
16
17 For very small programs, `main` is the only package you need to write.
18
19 The hello world program _imports_ package `fmt`.
20
21 The function `Println` is defined in the fmt package.
22
23 * An example package: fmt
24
25 // Package fmt implements formatted I/O.
26 package fmt
27
28 // Println formats using the default formats for its
29 // operands and writes to standard output.
30 func Println(a ...interface{}) (n int, err error) {
31 ...
32 }
33
34 func newPrinter() *pp {
35 ...
36 }
37
38 The `Println` function is _exported_. It starts with an upper case
39 letter, which means other packages are allowed to call it.
40
41 The `newPrinter` function is _unexported_. It starts with a lower
42 case letter, so it can only be used inside the fmt package.
43
44 * The shape of a package
45
46 Packages collect related code.
47
48 They can be big or small,
49 and may be spread across multiple files.
50
51 All the files in a package live in a single directory.
52
53 The `net/http` package exports more than 100 names. (18 files)
54 The `errors` package exports just one. (1 file)
55
56 * The name of a package
57
58 Keep package names short and meaningful.
59 Don't use underscores, they make package names long.
60
61 - `io/ioutil` not `io/util`
62 - `suffixarray` not `suffix_array`
63
64 Don't overgeneralize. A `util` package could be anything.
65
66 The name of a package is part of its type and function names.
67 On its own, type `Buffer` is ambiguous. But users see:
68
69 buf := new(bytes.Buffer)
70
71 Choose package names carefully.
72
73 Choose good names for users.
74
75 * The testing of a package
76
77 Tests are distinguished by file name. Test files end in `_test.go`.
78
79 package fmt
80
81 import "testing"
82
83 var fmtTests = []fmtTest{
84 {"%d", 12345, "12345"},
85 {"%v", 12345, "12345"},
86 {"%t", true, "true"},
87 }
88
89 func TestSprintf(t *testing.T) {
90 for _, tt := range fmtTests {
91 if s := Sprintf(tt.fmt, tt.val); s != tt.out {
92 t.Errorf("...")
93 }
94 }
95 }
96
97 Test well.
98
99 * Code organization
100
101 * Introducing workspaces
102
103 Your Go code is kept in a _workspace_.
104
105 A workspace contains _many_ source repositories (git, hg).
106
107 The Go tool understands the layout of a workspace.
108 You don't need a `Makefile`. The file layout is everything.
109
110 Change the file layout, change the build.
111
112 $GOPATH/
113 src/
114 github.com/user/repo/
115 mypkg/
116 mysrc1.go
117 mysrc2.go
118 cmd/mycmd/
119 main.go
120 bin/
121 mycmd
122
123
124 * Let's make a workspace
125
126 mkdir /tmp/gows
127 GOPATH=/tmp/gows
128
129 The `GOPATH` environment variable tells the Go tool where your workspace is located.
130
131 go get github.com/dsymonds/fixhub/cmd/fixhub
132
133 The `go` `get` command fetches source repositories from the internet and places them in your workspace.
134
135 Package paths matter to the Go tool. Using "github.com/..."
136 means the tool knows how to fetch your repository.
137
138 go install github.com/dsymonds/fixhub/cmd/fixhub
139
140 The go install command builds a binary and places it in `$GOPATH/bin/fixhub`.
141
142 * Our workspace
143
144 $GOPATH/
145 bin/fixhub # installed binary
146 pkg/darwin_amd64/ # compiled archives
147 code.google.com/p/goauth2/oauth.a
148 github.com/...
149 src/ # source repositories
150 code.google.com/p/goauth2/
151 .hg
152 oauth # used by package go-github
153 ...
154 github.com/
155 golang/lint/... # used by package fixhub
156 .git
157 google/go-github/... # used by package fixhub
158 .git
159 dsymonds/fixhub/
160 .git
161 client.go
162 cmd/fixhub/fixhub.go # package main
163
164 `go` `get` fetched many repositories.
165 `go` `install` built a binary out of them.
166
167
168 * Why prescribe file layout?
169
170 Using file layout for builds means less configuration.
171 In fact, it means no configuration.
172 No `Makefile`, no `build.xml`.
173
174 Less time configuring means more time programming.
175
176 Everyone in the community uses the same layout.
177 This makes it easier to share code.
178
179 The Go tool helps build the Go community.
180
181 * Where's your workspace?
182
183 It is possible to have multiple workspaces, but most people just use one.
184
185 So where do you point your `GOPATH`? A common preference:
186
187 .image organizeio/home.png
188
189 This puts `src`, `bin`, and `pkg` directories in your home directory.
190
191 (Convenient, because `$HOME/bin` is probably already in your `PATH`.)
192
193
194 * Working with workspaces
195
196 Unix eschews typing:
197
198 CDPATH=$GOPATH/src/github.com:$GOPATH/src/code.google.com/p
199
200 $ cd dsymonds/fixhub
201 /tmp/gows/src/github.com/dsymonds/fixhub
202 $ cd goauth2
203 /tmp/gows/src/code.google.com/p/goauth2
204 $
205
206 A shell function for your `~/.profile`:
207
208 gocd () { cd `go list -f '{{.Dir}}' $1` }
209
210 This lets you move around using the Go tool's path names:
211
212 $ gocd .../lint
213 /tmp/gows/src/github.com/golang/lint
214 $
215
216
217 * The Go tool's many talents
218
219 $ go help
220 Go is a tool for managing Go source code.
221
222 Usage:
223
224 go command [arguments]
225
226 The commands are:
227
228 Worth exploring! Some highlights:
229
230 build compile packages and dependencies
231 get download and install packages and dependencies
232 install compile and install packages and dependencies
233 test test packages
234
235 There are more useful subcommands. Check out `vet` and `fmt`.
236
237 * Dependency management
238
239 * In production, versions matter.
240
241 `go` `get` always fetches the latest code, even if your build breaks.
242
243 .image organizeio/gogetversion.png
244
245 That's fine when developing. It's not fine when releasing.
246 We need other tools.
247
248 * Versioning
249
250 My favorite technique: vendoring.
251
252 For building binaries, import the packages you care about
253 into a `_vendor` workspace.
254
255 GOPATH=/tmp/gows/_vendor:/tmp/gows
256
257 For building libraries, import the packages you care about
258 into your repository. Rename the imports to:
259
260 import "github.com/you/proj/vendor/github.com/them/lib"
261
262 Long paths, but trivial to automate. Write a Go program!
263
264 Another technique: [[http://gopkg.in][gopkg.in]], provides versioned package paths:
265
266 gopkg.in/user/pkg.v3 -> github.com/user/pkg (branch/tag v3, v3.N, or v.3.N.M)
267
268 * Naming
269
270 * Names matter
271
272 Programs are full of names. Names have costs and benefits.
273
274 *Costs*: *space* *and* *time*
275 Names need to be in short term memory when reading code.
276 You can only fit so many. Longer names take up more space.
277
278 *Benefits:* *information*
279 A good name is not only a referent, it conveys information.
280
281 Use the shortest name that carries the right amount of information in its context.
282
283 Devote time to naming.
284
285 * Name style
286
287 Use `camelCase`, `not_underscores`.
288 Local variable names should be short, typically one or two characters.
289
290 Package names are usually one lowercase word.
291
292 Global variables should have longer names.
293
294 Don't stutter.
295
296 - `bytes.Buffer` not `bytes.ByteBuffer`
297 - `zip.Reader` not `zip.ZipReader`
298 - `errors.New` not `errors.NewError`
299 - `r` not `bytesReader`
300 - `i` not `loopIterator`
301
302 * Doc comments
303
304 Doc comments precede the declaration of an exported identifier:
305
306 // Join concatenates the elements of elem to create a single string.
307 // The separator string sep is placed between elements in the resulting string.
308 func Join(elem []string, sep string) string {
309
310 The godoc tool extracts such comments and presents them on the web:
311
312 .image organizeio/godoc.png
313
314 * Writing doc comments
315
316 Doc comments should be English sentences and paragraphs.
317 They use no special formatting beyond indentation for preformatted text.
318
319 Doc comments should begin with the noun they describe.
320
321 // Join concatenates… good
322 // This function… bad
323
324 Package docs go above the package declaration:
325
326 // Package fmt…
327 package fmt
328
329 Read the world's Go docs on [[https://pkg.go.dev]]. E.g.
330
331 [[https://pkg.go.dev/golang.org/x/tools/txtar]]
332
333 * Questions?
334
View as plain text